aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/assembler/ARM64Assembler.h2
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h150
-rw-r--r--src/3rdparty/masm/stubs/WTFStubs.cpp6
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorPosix.cpp21
-rw-r--r--src/3rdparty/masm/yarr/Yarr.h1
-rw-r--r--src/CMakeLists.txt17
-rw-r--r--src/core/qqmlstandardpaths.cpp2
-rw-r--r--src/imports/builtins/CMakeLists.txt7
-rw-r--r--src/imports/builtins/builtins.qmltypes21
-rw-r--r--src/imports/builtins/jsroot.qmltypes2
-rw-r--r--src/imports/tooling/CMakeLists.txt2
-rw-r--r--src/imports/tooling/Method.qml2
-rw-r--r--src/imports/tooling/Parameter.qml1
-rw-r--r--src/imports/tooling/Signal.qml1
-rw-r--r--src/labs/CMakeLists.txt5
-rw-r--r--src/labs/animation/CMakeLists.txt2
-rw-r--r--src/labs/animation/doc/src/qmlanimation.qdoc2
-rw-r--r--src/labs/animation/qquickboundaryrule.cpp6
-rw-r--r--src/labs/folderlistmodel/fileinfothread.cpp5
-rw-r--r--src/labs/folderlistmodel/fileinfothread_p.h4
-rw-r--r--src/labs/folderlistmodel/fileproperty_p.h5
-rw-r--r--src/labs/models/CMakeLists.txt2
-rw-r--r--src/labs/models/doc/src/qmllabsmodels.qdoc2
-rw-r--r--src/labs/models/qqmldelegatecomponent.cpp14
-rw-r--r--src/labs/models/qqmltablemodel.cpp2
-rw-r--r--src/labs/models/qqmltablemodelcolumn.cpp2
-rw-r--r--src/labs/models/qqmltablemodelcolumn_p.h2
-rw-r--r--src/labs/platform/CMakeLists.txt91
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-colordialog-gtk.pngbin0 -> 9786 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-filedialog-gtk.pngbin0 -> 39560 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-folderdialog-gtk.pngbin0 -> 40008 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-fontdialog-gtk.pngbin0 -> 32399 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-menu.pngbin0 -> 3687 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-menubar.pngbin0 -> 60433 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-messagedialog-android.pngbin0 -> 3741 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-messagedialog-informative-android.pngbin0 -> 6737 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-menu.pngbin0 -> 20550 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-message.pngbin0 -> 33060 bytes
-rw-r--r--src/labs/platform/doc/images/qtlabsplatform-systemtrayicon.pngbin0 -> 16929 bytes
-rw-r--r--src/labs/platform/doc/qtlabsplatform.qdocconf40
-rw-r--r--src/labs/platform/doc/src/includes/widgets.qdocinc28
-rw-r--r--src/labs/platform/doc/src/qt6-changes.qdoc57
-rw-r--r--src/labs/platform/doc/src/qtlabsplatform-index.qdoc54
-rw-r--r--src/labs/platform/doc/src/qtlabsplatform-qmltypes.qdoc58
-rw-r--r--src/labs/platform/platform.pri39
-rw-r--r--src/labs/platform/qquicklabsplatformcolordialog.cpp208
-rw-r--r--src/labs/platform/qquicklabsplatformcolordialog_p.h98
-rw-r--r--src/labs/platform/qquicklabsplatformdialog.cpp411
-rw-r--r--src/labs/platform/qquicklabsplatformdialog_p.h153
-rw-r--r--src/labs/platform/qquicklabsplatformfiledialog.cpp669
-rw-r--r--src/labs/platform/qquicklabsplatformfiledialog_p.h197
-rw-r--r--src/labs/platform/qquicklabsplatformfolderdialog.cpp285
-rw-r--r--src/labs/platform/qquicklabsplatformfolderdialog_p.h110
-rw-r--r--src/labs/platform/qquicklabsplatformfontdialog.cpp210
-rw-r--r--src/labs/platform/qquicklabsplatformfontdialog_p.h98
-rw-r--r--src/labs/platform/qquicklabsplatformicon.cpp83
-rw-r--r--src/labs/platform/qquicklabsplatformicon_p.h86
-rw-r--r--src/labs/platform/qquicklabsplatformiconloader.cpp101
-rw-r--r--src/labs/platform/qquicklabsplatformiconloader_p.h86
-rw-r--r--src/labs/platform/qquicklabsplatformmenu.cpp895
-rw-r--r--src/labs/platform/qquicklabsplatformmenu_p.h213
-rw-r--r--src/labs/platform/qquicklabsplatformmenubar.cpp334
-rw-r--r--src/labs/platform/qquicklabsplatformmenubar_p.h120
-rw-r--r--src/labs/platform/qquicklabsplatformmenuitem.cpp650
-rw-r--r--src/labs/platform/qquicklabsplatformmenuitem_p.h194
-rw-r--r--src/labs/platform/qquicklabsplatformmenuitemgroup.cpp392
-rw-r--r--src/labs/platform/qquicklabsplatformmenuitemgroup_p.h123
-rw-r--r--src/labs/platform/qquicklabsplatformmenuseparator.cpp67
-rw-r--r--src/labs/platform/qquicklabsplatformmenuseparator_p.h67
-rw-r--r--src/labs/platform/qquicklabsplatformmessagedialog.cpp384
-rw-r--r--src/labs/platform/qquicklabsplatformmessagedialog_p.h121
-rw-r--r--src/labs/platform/qquicklabsplatformstandardpaths.cpp175
-rw-r--r--src/labs/platform/qquicklabsplatformstandardpaths_p.h (renamed from src/quick/designer/qquickdesignerwindowmanager_p.h)72
-rw-r--r--src/labs/platform/qquicklabsplatformsystemtrayicon.cpp443
-rw-r--r--src/labs/platform/qquicklabsplatformsystemtrayicon_p.h145
-rw-r--r--src/labs/platform/qtlabsplatformplugin.cpp117
-rw-r--r--src/labs/platform/widgets/qwidgetplatform_p.h170
-rw-r--r--src/labs/platform/widgets/qwidgetplatformcolordialog.cpp89
-rw-r--r--src/labs/platform/widgets/qwidgetplatformcolordialog_p.h78
-rw-r--r--src/labs/platform/widgets/qwidgetplatformdialog.cpp58
-rw-r--r--src/labs/platform/widgets/qwidgetplatformdialog_p.h66
-rw-r--r--src/labs/platform/widgets/qwidgetplatformfiledialog.cpp142
-rw-r--r--src/labs/platform/widgets/qwidgetplatformfiledialog_p.h84
-rw-r--r--src/labs/platform/widgets/qwidgetplatformfontdialog.cpp89
-rw-r--r--src/labs/platform/widgets/qwidgetplatformfontdialog_p.h78
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmenu.cpp185
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmenu_p.h98
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmenuitem.cpp127
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmenuitem_p.h88
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmessagedialog.cpp89
-rw-r--r--src/labs/platform/widgets/qwidgetplatformmessagedialog_p.h75
-rw-r--r--src/labs/platform/widgets/qwidgetplatformsystemtrayicon.cpp120
-rw-r--r--src/labs/platform/widgets/qwidgetplatformsystemtrayicon_p.h87
-rw-r--r--src/labs/platform/widgets/widgets.pri56
-rw-r--r--src/labs/sharedimage/doc/src/qsharedimage.qdoc2
-rw-r--r--src/labs/sharedimage/qsharedimageloader.cpp2
-rw-r--r--src/labs/sharedimage/qsharedimageprovider.cpp5
-rw-r--r--src/labs/sharedimage/qsharedimageprovider_p.h5
-rw-r--r--src/labs/wavefrontmesh/CMakeLists.txt2
-rw-r--r--src/labs/wavefrontmesh/qwavefrontmesh.cpp2
-rw-r--r--src/particles/qquickimageparticle.cpp7
-rw-r--r--src/particles/qquickimageparticle_p.h2
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp6
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp4
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_local/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_messages/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_native/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt4
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp11
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp161
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp24
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h5
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp9
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h3
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp7
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h2
-rw-r--r--src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/CMakeLists.txt2
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_server/CMakeLists.txt4
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp (renamed from src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp)3
-rw-r--r--src/plugins/qmltooling/qmldbg_tcp/CMakeLists.txt2
-rw-r--r--src/plugins/scenegraph/openvg/CMakeLists.txt2
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp1
-rw-r--r--src/qml/CMakeLists.txt53
-rw-r--r--src/qml/Qt6AndroidQmlMacros.cmake21
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake174
-rw-r--r--src/qml/Qt6QmlConfigExtras.cmake.in7
-rw-r--r--src/qml/Qt6QmlMacros.cmake1189
-rw-r--r--src/qml/animations/qabstractanimationjob.cpp14
-rw-r--r--src/qml/animations/qabstractanimationjob_p.h1
-rw-r--r--src/qml/animations/qcontinuinganimationgroupjob.cpp4
-rw-r--r--src/qml/animations/qparallelanimationgroupjob.cpp4
-rw-r--r--src/qml/common/qqmljsfixedpoolarray_p.h2
-rw-r--r--src/qml/common/qv4alloca_p.h6
-rw-r--r--src/qml/common/qv4compileddata_p.h401
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp262
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h8
-rw-r--r--src/qml/compiler/qv4codegen.cpp26
-rw-r--r--src/qml/compiler/qv4compiler.cpp61
-rw-r--r--src/qml/compiler/qv4compiler_p.h2
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp30
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions_p.h24
-rw-r--r--src/qml/configure.cmake13
-rw-r--r--src/qml/debugger/qqmldebug.cpp13
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp2
-rw-r--r--src/qml/debugger/qqmldebugconnector_p.h1
-rw-r--r--src/qml/debugger/qqmldebugserver.cpp49
-rw-r--r--src/qml/debugger/qqmldebugserver_p.h1
-rw-r--r--src/qml/debugger/qqmldebugserviceinterfaces_p.h2
-rw-r--r--src/qml/debugger/qqmldebugtranslationprotocol_p.h22
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/qtqml.qdocconf2
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt43
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml56
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml3
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt1
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml3
-rw-r--r--src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml3
-rw-r--r--src/qml/doc/snippets/code/doc_src_qtqml.cmake2
-rw-r--r--src/qml/doc/snippets/qml/CMakeLists.txt11
-rw-r--r--src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt23
-rw-r--r--src/qml/doc/snippets/qml/createQmlObject.qml15
-rw-r--r--src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs3
-rw-r--r--src/qml/doc/snippets/qml/myProject-CMakeLists.txt13
-rw-r--r--src/qml/doc/snippets/qml/myimageprovider.txt15
-rw-r--r--src/qml/doc/snippets/qml/plugin.cpp.txt14
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp71
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp68
-rw-r--r--src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp63
-rw-r--r--src/qml/doc/src/cmake/cmake-properties.qdoc187
-rw-r--r--src/qml/doc/src/cmake/cmake-variables.qdoc40
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_module.qdoc224
-rw-r--r--src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc95
-rw-r--r--src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc36
-rw-r--r--src/qml/doc/src/cmake/qt_target_qml_sources.qdoc185
-rw-r--r--src/qml/doc/src/cppintegration/definetypes.qdoc78
-rw-r--r--src/qml/doc/src/cppintegration/extending-tutorial.qdoc20
-rw-r--r--src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc185
-rw-r--r--src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc88
-rw-r--r--src/qml/doc/src/javascript/finetuning.qdoc9
-rw-r--r--src/qml/doc/src/javascript/hostenvironment.qdoc12
-rw-r--r--src/qml/doc/src/javascript/imports.qdoc13
-rw-r--r--src/qml/doc/src/qmlfunctions.qdoc55
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc8
-rw-r--r--src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc5
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc10
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc547
-rw-r--r--src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc8
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc5
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/imports.qdoc6
-rw-r--r--src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc7
-rw-r--r--src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc32
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc2
-rw-r--r--src/qml/doc/src/qt6-changes.qdoc4
-rw-r--r--src/qml/doc/src/qtqml-writing-a-module.qdoc289
-rw-r--r--src/qml/doc/src/qtqml.qdoc10
-rw-r--r--src/qml/inlinecomponentutils_p.h56
-rw-r--r--src/qml/jit/qv4baselinejit.cpp4
-rw-r--r--src/qml/jsapi/qjsengine.cpp8
-rw-r--r--src/qml/jsapi/qjsengine_p.h4
-rw-r--r--src/qml/jsapi/qjsmanagedvalue.cpp2
-rw-r--r--src/qml/jsapi/qjsvalue.cpp10
-rw-r--r--src/qml/jsapi/qjsvalue_p.h2
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h2
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp4
-rw-r--r--src/qml/jsruntime/qv4arrayiterator.cpp6
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper.cpp11
-rw-r--r--src/qml/jsruntime/qv4compilationunitmapper_p.h1
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp40
-rw-r--r--src/qml/jsruntime/qv4engine.cpp78
-rw-r--r--src/qml/jsruntime/qv4engine_p.h11
-rw-r--r--src/qml/jsruntime/qv4executablecompilationunit.cpp85
-rw-r--r--src/qml/jsruntime/qv4function.cpp3
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp11
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h1
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp170
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h38
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h6
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4lookup.cpp120
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h52
-rw-r--r--src/qml/jsruntime/qv4object.cpp61
-rw-r--r--src/qml/jsruntime/qv4profiling.cpp4
-rw-r--r--src/qml/jsruntime/qv4promiseobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4propertykey_p.h2
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp23
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h1
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp38
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h3
-rw-r--r--src/qml/jsruntime/qv4reflect.cpp5
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp1
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp12
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4stackframe.cpp6
-rw-r--r--src/qml/jsruntime/qv4string_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp28
-rw-r--r--src/qml/memory/qv4mm.cpp2
-rw-r--r--src/qml/parser/qqmljs.g12
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h4
-rw-r--r--src/qml/qml/ftw/qintrusivelist_p.h5
-rw-r--r--src/qml/qml/qqml.cpp375
-rw-r--r--src/qml/qml/qqmlanybinding_p.h24
-rw-r--r--src/qml/qml/qqmlapplicationengine.cpp7
-rw-r--r--src/qml/qml/qqmlbinding.cpp85
-rw-r--r--src/qml/qml/qqmlbinding_p.h3
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp31
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h2
-rw-r--r--src/qml/qml/qqmlcomponent.cpp163
-rw-r--r--src/qml/qml/qqmlcomponentattached_p.h1
-rw-r--r--src/qml/qml/qqmlcontext.cpp24
-rw-r--r--src/qml/qml/qqmlcontext.h2
-rw-r--r--src/qml/qml/qqmlcontextdata.cpp2
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp4
-rw-r--r--src/qml/qml/qqmldata_p.h13
-rw-r--r--src/qml/qml/qqmlengine.cpp175
-rw-r--r--src/qml/qml/qqmlengine_p.h8
-rw-r--r--src/qml/qml/qqmlexpression.cpp4
-rw-r--r--src/qml/qml/qqmlexpression_p.h1
-rw-r--r--src/qml/qml/qqmlextensionplugin.cpp30
-rw-r--r--src/qml/qml/qqmlextensionplugin.h6
-rw-r--r--src/qml/qml/qqmlfile.cpp148
-rw-r--r--src/qml/qml/qqmlfileselector.cpp9
-rw-r--r--src/qml/qml/qqmlguard_p.h10
-rw-r--r--src/qml/qml/qqmlimport.cpp84
-rw-r--r--src/qml/qml/qqmlimport_p.h28
-rw-r--r--src/qml/qml/qqmlincubator.cpp15
-rw-r--r--src/qml/qml/qqmlirloader.cpp11
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp34
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h16
-rw-r--r--src/qml/qml/qqmllocale.cpp2
-rw-r--r--src/qml/qml/qqmlloggingcategory.cpp17
-rw-r--r--src/qml/qml/qqmlmetatype.cpp114
-rw-r--r--src/qml/qml/qqmlmetatype_p.h11
-rw-r--r--src/qml/qml/qqmlmetatypedata.cpp5
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp268
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h13
-rw-r--r--src/qml/qml/qqmlopenmetaobject.cpp6
-rw-r--r--src/qml/qml/qqmlpluginimporter.cpp64
-rw-r--r--src/qml/qml/qqmlproperty.cpp90
-rw-r--r--src/qml/qml/qqmlproperty_p.h7
-rw-r--r--src/qml/qml/qqmlpropertybinding.cpp214
-rw-r--r--src/qml/qml/qqmlpropertybinding_p.h202
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp48
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h9
-rw-r--r--src/qml/qml/qqmlpropertycachecreator.cpp13
-rw-r--r--src/qml/qml/qqmlpropertycachecreator_p.h140
-rw-r--r--src/qml/qml/qqmlpropertydata_p.h1
-rw-r--r--src/qml/qml/qqmlpropertyvalidator.cpp87
-rw-r--r--src/qml/qml/qqmlpropertyvalueinterceptor_p.h1
-rw-r--r--src/qml/qml/qqmlproxymetaobject.cpp10
-rw-r--r--src/qml/qml/qqmlscriptblob.cpp8
-rw-r--r--src/qml/qml/qqmlscriptstring.cpp2
-rw-r--r--src/qml/qml/qqmlscriptstring.h1
-rw-r--r--src/qml/qml/qqmltype.cpp9
-rw-r--r--src/qml/qml/qqmltypecompiler.cpp198
-rw-r--r--src/qml/qml/qqmltypedata.cpp48
-rw-r--r--src/qml/qml/qqmltypeloader.cpp11
-rw-r--r--src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp2
-rw-r--r--src/qml/qml/qqmltypeloaderqmldircontent_p.h1
-rw-r--r--src/qml/qml/qqmltypemodule.cpp17
-rw-r--r--src/qml/qml/qqmltypemodule_p.h40
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp114
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h127
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp22
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp25
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp33
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp97
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h2
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp19
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h2
-rw-r--r--src/qml/qmldirparser/qqmlimportresolver_p.h4
-rw-r--r--src/qml/types/qqmlbind.cpp8
-rw-r--r--src/qml/types/qqmlconnections.cpp33
-rw-r--r--src/qml/util/qqmlpropertymap.cpp2
-rw-r--r--src/qmlcompiler/CMakeLists.txt24
-rw-r--r--src/qmlcompiler/qdeferredpointer_p.h56
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp30
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp278
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h40
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp412
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h73
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp11
-rw-r--r--src/qmlcompiler/qqmljslogger_p.h2
-rw-r--r--src/qmlcompiler/qqmljsscope.cpp317
-rw-r--r--src/qmlcompiler/qqmljsscope_p.h100
-rw-r--r--src/qmlcompiler/qqmljsscopesbyid_p.h100
-rw-r--r--src/qmlcompiler/qqmljstypedescriptionreader.cpp33
-rw-r--r--src/qmlcompiler/qqmljstypereader.cpp26
-rw-r--r--src/qmlcompiler/qqmljstypereader_p.h2
-rw-r--r--src/qmldebug/CMakeLists.txt2
-rw-r--r--src/qmldebug/qqmldebugclient.cpp2
-rw-r--r--src/qmldebug/qqmldebugmessageclient.cpp2
-rw-r--r--src/qmldebug/qqmldebugtranslationclient.cpp4
-rw-r--r--src/qmldebug/qqmlenginedebugclient.cpp2
-rw-r--r--src/qmldebug/qqmlinspectorclient.cpp2
-rw-r--r--src/qmldebug/qqmlpreviewclient.cpp2
-rw-r--r--src/qmldebug/qqmlprofilereventreceiver.cpp49
-rw-r--r--src/qmldebug/qqmlprofilereventreceiver_p.h3
-rw-r--r--src/qmldebug/qv4debugclient.cpp2
-rw-r--r--src/qmldevtools/CMakeLists.txt18
-rw-r--r--src/qmldom/qqmldomattachedinfo.cpp2
-rw-r--r--src/qmldom/qqmldomcomments.cpp2
-rw-r--r--src/qmldom/qqmldomelements.cpp46
-rw-r--r--src/qmldom/qqmldomelements_p.h2
-rw-r--r--src/qmldom/qqmldomerrormessage.cpp2
-rw-r--r--src/qmldom/qqmldomerrormessage_p.h63
-rw-r--r--src/qmldom/qqmldomfieldfilter.cpp2
-rw-r--r--src/qmldom/qqmldomfilewriter.cpp2
-rw-r--r--src/qmldom/qqmldomitem.cpp95
-rw-r--r--src/qmldom/qqmldomitem_p.h13
-rw-r--r--src/qmldom/qqmldomlinewriter.cpp2
-rw-r--r--src/qmldom/qqmldommoduleindex.cpp2
-rw-r--r--src/qmldom/qqmldompath.cpp17
-rw-r--r--src/qmldom/qqmldompath_p.h32
-rw-r--r--src/qmldom/qqmldomreformatter.cpp62
-rw-r--r--src/qmldom/qqmldomtop.cpp169
-rw-r--r--src/qmldom/qqmldomtop_p.h13
-rw-r--r--src/qmllocalstorage/qqmllocalstorage.cpp16
-rw-r--r--src/qmlmodels/CMakeLists.txt5
-rw-r--r--src/qmlmodels/doc/src/qtqmlmodel.qdoc2
-rw-r--r--src/qmlmodels/qqmlabstractdelegatecomponent.cpp2
-rw-r--r--src/qmlmodels/qqmladaptormodel.cpp27
-rw-r--r--src/qmlmodels/qqmladaptormodel_p.h8
-rw-r--r--src/qmlmodels/qqmlchangeset.cpp10
-rw-r--r--src/qmlmodels/qqmldelegatemodel.cpp52
-rw-r--r--src/qmlmodels/qqmldelegatemodel_p.h3
-rw-r--r--src/qmlmodels/qqmlinstantiator.cpp2
-rw-r--r--src/qmlmodels/qqmllistaccessor.cpp4
-rw-r--r--src/qmlmodels/qqmllistcompositor_p.h5
-rw-r--r--src/qmlmodels/qqmllistmodel.cpp214
-rw-r--r--src/qmlmodels/qqmllistmodel_p.h3
-rw-r--r--src/qmlmodels/qqmllistmodel_p_p.h47
-rw-r--r--src/qmlmodels/qqmlmodelindexvaluetype.cpp (renamed from src/qml/types/qqmlmodelindexvaluetype.cpp)0
-rw-r--r--src/qmlmodels/qqmlmodelindexvaluetype_p.h (renamed from src/qml/types/qqmlmodelindexvaluetype_p.h)0
-rw-r--r--src/qmltest/CMakeLists.txt5
-rw-r--r--src/qmltest/SignalSpy.qml9
-rw-r--r--src/qmltest/TestCase.qml2
-rw-r--r--src/qmltest/doc/snippets/overview.cmake2
-rw-r--r--src/qmltest/doc/src/qtquicktest-qmltypes.qdoc2
-rw-r--r--src/qmltest/quicktest.cpp14
-rw-r--r--src/qmltest/quicktestevent.cpp4
-rw-r--r--src/qmltest/quicktestresult.cpp3
-rw-r--r--src/qmltest/quicktestutil.cpp2
-rw-r--r--src/qmltyperegistrar/metatypesjsonprocessor.cpp3
-rw-r--r--src/qmltyperegistrar/qmltyperegistrar.cpp13
-rw-r--r--src/qmltyperegistrar/qmltypes.prf55
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.cpp28
-rw-r--r--src/qmltyperegistrar/qmltypescreator.cpp10
-rw-r--r--src/qmltyperegistrar/qmltypescreator.h2
-rw-r--r--src/qmlworkerscript/doc/src/qmlworkerscript.qdoc2
-rw-r--r--src/qmlxmllistmodel/qqmlxmllistmodel.cpp2
-rw-r--r--src/quick/CMakeLists.txt3
-rw-r--r--src/quick/accessible/qaccessiblequickitem.cpp7
-rw-r--r--src/quick/designer/qquickdesignersupport.cpp14
-rw-r--r--src/quick/designer/qquickdesignersupport_p.h3
-rw-r--r--src/quick/designer/qquickdesignersupportitems.cpp1
-rw-r--r--src/quick/designer/qquickdesignerwindowmanager.cpp125
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webpbin0 -> 53154 bytes
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webpbin0 -> 27426 bytes
-rw-r--r--src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webpbin0 -> 51008 bytes
-rw-r--r--src/quick/doc/qtquick.qdocconf49
-rw-r--r--src/quick/doc/snippets/cmake-macros/examples.cmake6
-rw-r--r--src/quick/doc/snippets/code/doc_src_qtquick.cmake2
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml69
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml76
-rw-r--r--src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml73
-rw-r--r--src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.pngbin0 -> 1454 bytes
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandler.qml5
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml68
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml83
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml101
-rw-r--r--src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml83
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerButton.qml80
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml98
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml98
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml8
-rw-r--r--src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml98
-rw-r--r--src/quick/doc/src/advtutorial.qdoc31
-rw-r--r--src/quick/doc/src/concepts/effects/particles.qdoc2
-rw-r--r--src/quick/doc/src/concepts/input/focus.qdoc9
-rw-r--r--src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc67
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc9
-rw-r--r--src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc2
-rw-r--r--src/quick/doc/src/concepts/positioning/righttoleft.qdoc14
-rw-r--r--src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc1
-rw-r--r--src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc220
-rw-r--r--src/quick/doc/src/guidelines/qtquick-tool-qmllint.qdoc43
-rw-r--r--src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc74
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc2
-rw-r--r--src/quick/doc/src/qt6-changes.qdoc4
-rw-r--r--src/quick/doc/src/qtquick.qdoc1
-rw-r--r--src/quick/doc/src/tutorial.qdoc10
-rw-r--r--src/quick/handlers/qquickdragaxis.cpp2
-rw-r--r--src/quick/handlers/qquickdraghandler.cpp14
-rw-r--r--src/quick/handlers/qquickhandlerpoint.cpp27
-rw-r--r--src/quick/handlers/qquickhoverhandler.cpp108
-rw-r--r--src/quick/handlers/qquickmultipointhandler.cpp6
-rw-r--r--src/quick/handlers/qquickpinchhandler.cpp20
-rw-r--r--src/quick/handlers/qquickpointerdevicehandler.cpp4
-rw-r--r--src/quick/handlers/qquickpointerhandler.cpp53
-rw-r--r--src/quick/handlers/qquickpointhandler.cpp128
-rw-r--r--src/quick/handlers/qquicksinglepointhandler.cpp4
-rw-r--r--src/quick/handlers/qquicktaphandler.cpp133
-rw-r--r--src/quick/handlers/qquicktaphandler_p.h7
-rw-r--r--src/quick/handlers/qquickwheelhandler.cpp8
-rw-r--r--src/quick/items/context2d/qquickcanvasitem.cpp6
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp31
-rw-r--r--src/quick/items/context2d/qquickcontext2d_p.h2
-rw-r--r--src/quick/items/context2d/qquickcontext2dtexture.cpp11
-rw-r--r--src/quick/items/qquickaccessibleattached.cpp7
-rw-r--r--src/quick/items/qquickaccessibleattached_p.h2
-rw-r--r--src/quick/items/qquickanchors.cpp2
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp14
-rw-r--r--src/quick/items/qquickcolorgroup.cpp4
-rw-r--r--src/quick/items/qquickdrag.cpp12
-rw-r--r--src/quick/items/qquickdrag_p.h3
-rw-r--r--src/quick/items/qquickdroparea.cpp38
-rw-r--r--src/quick/items/qquickdroparea_p.h14
-rw-r--r--src/quick/items/qquickevents.cpp53
-rw-r--r--src/quick/items/qquickflickable.cpp197
-rw-r--r--src/quick/items/qquickflickable_p_p.h41
-rw-r--r--src/quick/items/qquickflipable.cpp54
-rw-r--r--src/quick/items/qquickgridview.cpp32
-rw-r--r--src/quick/items/qquickimage.cpp6
-rw-r--r--src/quick/items/qquickimagebase.cpp30
-rw-r--r--src/quick/items/qquickimplicitsizeitem_p.h2
-rw-r--r--src/quick/items/qquickitem.cpp338
-rw-r--r--src/quick/items/qquickitem.h1
-rw-r--r--src/quick/items/qquickitem_p.h28
-rw-r--r--src/quick/items/qquickitemchangelistener_p.h1
-rw-r--r--src/quick/items/qquickitemgrabresult.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp136
-rw-r--r--src/quick/items/qquickitemview.cpp26
-rw-r--r--src/quick/items/qquickitemview_p_p.h5
-rw-r--r--src/quick/items/qquickitemviewtransition.cpp35
-rw-r--r--src/quick/items/qquickitemviewtransition_p.h3
-rw-r--r--src/quick/items/qquicklistview.cpp21
-rw-r--r--src/quick/items/qquickloader.cpp19
-rw-r--r--src/quick/items/qquickmousearea.cpp36
-rw-r--r--src/quick/items/qquickmultipointtoucharea.cpp12
-rw-r--r--src/quick/items/qquickmultipointtoucharea_p.h3
-rw-r--r--src/quick/items/qquickpainteditem.cpp2
-rw-r--r--src/quick/items/qquickpalette.cpp2
-rw-r--r--src/quick/items/qquickpathview.cpp13
-rw-r--r--src/quick/items/qquickpathview_p_p.h6
-rw-r--r--src/quick/items/qquickpincharea.cpp28
-rw-r--r--src/quick/items/qquickpositioners.cpp6
-rw-r--r--src/quick/items/qquickrectangle.cpp9
-rw-r--r--src/quick/items/qquickrendercontrol.cpp23
-rw-r--r--src/quick/items/qquickrendercontrol.h3
-rw-r--r--src/quick/items/qquickrendercontrol_p.h3
-rw-r--r--src/quick/items/qquickscalegrid.cpp2
-rw-r--r--src/quick/items/qquickshadereffect.cpp23
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp8
-rw-r--r--src/quick/items/qquickshadereffectsource_p.h1
-rw-r--r--src/quick/items/qquickspriteengine.cpp1
-rw-r--r--src/quick/items/qquickstateoperations.cpp92
-rw-r--r--src/quick/items/qquicktableview.cpp152
-rw-r--r--src/quick/items/qquicktableview_p_p.h16
-rw-r--r--src/quick/items/qquicktext.cpp92
-rw-r--r--src/quick/items/qquicktext_p.h2
-rw-r--r--src/quick/items/qquicktextedit.cpp13
-rw-r--r--src/quick/items/qquicktextedit_p.h2
-rw-r--r--src/quick/items/qquicktextinput.cpp60
-rw-r--r--src/quick/items/qquicktextinput_p_p.h2
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp5
-rw-r--r--src/quick/items/qquickwindow.cpp132
-rw-r--r--src/quick/items/qquickwindow_p.h18
-rw-r--r--src/quick/items/qquickwindowmodule_p.h5
-rw-r--r--src/quick/qtquickglobal_p.h30
-rw-r--r--src/quick/qtquickplugin.cpp3
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp2
-rw-r--r--src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp21
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp2
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp308
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h32
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.cpp6
-rw-r--r--src/quick/scenegraph/coreapi/qsggeometry.h1
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp4
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp3
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h13
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendernode.cpp15
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture.cpp5
-rw-r--r--src/quick/scenegraph/coreapi/qsgtexture_mac.mm1
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h5
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp63
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext.cpp29
-rw-r--r--src/quick/scenegraph/qsgdefaultrendercontext_p.h6
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp82
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h4
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp45
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp66
-rw-r--r--src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h6
-rw-r--r--src/quick/scenegraph/qsgrhilayer.cpp8
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode.cpp41
-rw-r--r--src/quick/scenegraph/qsgrhishadereffectnode_p.h3
-rw-r--r--src/quick/scenegraph/qsgrhitextureglyphcache.cpp52
-rw-r--r--src/quick/scenegraph/qsgrhitextureglyphcache_p.h7
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp60
-rw-r--r--src/quick/scenegraph/shaders_ng/24bittextmask.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/32bitcolortext.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/8bittextmask_a.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext.vert9
-rw-r--r--src/quick/scenegraph/shaders_ng/outlinedtext_a.frag5
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext.vert7
-rw-r--r--src/quick/scenegraph/shaders_ng/styledtext_a.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.frag3
-rw-r--r--src/quick/scenegraph/shaders_ng/textmask.vert7
-rw-r--r--src/quick/scenegraph/util/qsgdefaultpainternode.cpp12
-rw-r--r--src/quick/scenegraph/util/qsgplaintexture.cpp9
-rw-r--r--src/quick/scenegraph/util/qsgrhiatlastexture.cpp4
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp4
-rw-r--r--src/quick/util/qquickanimation.cpp5
-rw-r--r--src/quick/util/qquickanimation_p_p.h2
-rw-r--r--src/quick/util/qquickanimatorjob.cpp16
-rw-r--r--src/quick/util/qquickanimatorjob_p.h11
-rw-r--r--src/quick/util/qquickapplication.cpp172
-rw-r--r--src/quick/util/qquickbehavior.cpp7
-rw-r--r--src/quick/util/qquickdeliveryagent.cpp261
-rw-r--r--src/quick/util/qquickdeliveryagent_p_p.h11
-rw-r--r--src/quick/util/qquickfontmetrics.cpp16
-rw-r--r--src/quick/util/qquickimageprovider.cpp15
-rw-r--r--src/quick/util/qquickpixmapcache.cpp16
-rw-r--r--src/quick/util/qquickpixmapcache_p.h6
-rw-r--r--src/quick/util/qquickpropertychanges.cpp35
-rw-r--r--src/quick/util/qquicksmoothedanimation.cpp2
-rw-r--r--src/quick/util/qquickstatechangescript.cpp4
-rw-r--r--src/quick/util/qquickstategroup.cpp14
-rw-r--r--src/quick/util/qquickstyledtext.cpp4
-rw-r--r--src/quick/util/qquicktimeline.cpp2
-rw-r--r--src/quick/util/qquicktransition.cpp11
-rw-r--r--src/quick/util/qquicktransition_p.h1
-rw-r--r--src/quick/util/qquickvalidator.cpp6
-rw-r--r--src/quickcontrols2/CMakeLists.txt85
-rw-r--r--src/quickcontrols2/basic/AbstractButton.qml47
-rw-r--r--src/quickcontrols2/basic/Action.qml40
-rw-r--r--src/quickcontrols2/basic/ActionGroup.qml40
-rw-r--r--src/quickcontrols2/basic/ApplicationWindow.qml45
-rw-r--r--src/quickcontrols2/basic/BusyIndicator.qml62
-rw-r--r--src/quickcontrols2/basic/Button.qml79
-rw-r--r--src/quickcontrols2/basic/ButtonGroup.qml40
-rw-r--r--src/quickcontrols2/basic/CMakeLists.txt171
-rw-r--r--src/quickcontrols2/basic/CheckBox.qml92
-rw-r--r--src/quickcontrols2/basic/CheckDelegate.qml109
-rw-r--r--src/quickcontrols2/basic/ComboBox.qml140
-rw-r--r--src/quickcontrols2/basic/Container.qml47
-rw-r--r--src/quickcontrols2/basic/Control.qml47
-rw-r--r--src/quickcontrols2/basic/DelayButton.qml104
-rw-r--r--src/quickcontrols2/basic/Dial.qml79
-rw-r--r--src/quickcontrols2/basic/Dialog.qml85
-rw-r--r--src/quickcontrols2/basic/DialogButtonBox.qml73
-rw-r--r--src/quickcontrols2/basic/Drawer.qml78
-rw-r--r--src/quickcontrols2/basic/Frame.qml55
-rw-r--r--src/quickcontrols2/basic/GroupBox.qml73
-rw-r--r--src/quickcontrols2/basic/HorizontalHeaderView.qml67
-rw-r--r--src/quickcontrols2/basic/ItemDelegate.qml76
-rw-r--r--src/quickcontrols2/basic/Label.qml46
-rw-r--r--src/quickcontrols2/basic/Menu.qml80
-rw-r--r--src/quickcontrols2/basic/MenuBar.qml62
-rw-r--r--src/quickcontrols2/basic/MenuBarItem.qml76
-rw-r--r--src/quickcontrols2/basic/MenuItem.qml104
-rw-r--r--src/quickcontrols2/basic/MenuSeparator.qml57
-rw-r--r--src/quickcontrols2/basic/Page.qml56
-rw-r--r--src/quickcontrols2/basic/PageIndicator.qml74
-rw-r--r--src/quickcontrols2/basic/Pane.qml54
-rw-r--r--src/quickcontrols2/basic/Popup.qml63
-rw-r--r--src/quickcontrols2/basic/ProgressBar.qml66
-rw-r--r--src/quickcontrols2/basic/RadioButton.qml85
-rw-r--r--src/quickcontrols2/basic/RadioDelegate.qml102
-rw-r--r--src/quickcontrols2/basic/RangeSlider.qml95
-rw-r--r--src/quickcontrols2/basic/RoundButton.qml80
-rw-r--r--src/quickcontrols2/basic/ScrollBar.qml75
-rw-r--r--src/quickcontrols2/basic/ScrollIndicator.qml75
-rw-r--r--src/quickcontrols2/basic/ScrollView.qml64
-rw-r--r--src/quickcontrols2/basic/SelectionRectangle.qml61
-rw-r--r--src/quickcontrols2/basic/Slider.qml82
-rw-r--r--src/quickcontrols2/basic/SpinBox.qml134
-rw-r--r--src/quickcontrols2/basic/SplitView.qml54
-rw-r--r--src/quickcontrols2/basic/StackView.qml66
-rw-r--r--src/quickcontrols2/basic/SwipeDelegate.qml77
-rw-r--r--src/quickcontrols2/basic/SwipeView.qml65
-rw-r--r--src/quickcontrols2/basic/Switch.qml91
-rw-r--r--src/quickcontrols2/basic/SwitchDelegate.qml108
-rw-r--r--src/quickcontrols2/basic/TabBar.qml69
-rw-r--r--src/quickcontrols2/basic/TabButton.qml72
-rw-r--r--src/quickcontrols2/basic/TextArea.qml74
-rw-r--r--src/quickcontrols2/basic/TextField.qml82
-rw-r--r--src/quickcontrols2/basic/ToolBar.qml53
-rw-r--r--src/quickcontrols2/basic/ToolButton.qml74
-rw-r--r--src/quickcontrols2/basic/ToolSeparator.qml57
-rw-r--r--src/quickcontrols2/basic/ToolTip.qml68
-rw-r--r--src/quickcontrols2/basic/Tumbler.qml80
-rw-r--r--src/quickcontrols2/basic/VerticalHeaderView.qml67
-rw-r--r--src/quickcontrols2/basic/basic.pri67
-rw-r--r--src/quickcontrols2/basic/images/arrow-indicator.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/basic/images/arrow-indicator@2x.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/basic/images/arrow-indicator@3x.pngbin0 -> 285 bytes
-rw-r--r--src/quickcontrols2/basic/images/arrow-indicator@4x.pngbin0 -> 352 bytes
-rw-r--r--src/quickcontrols2/basic/images/check.pngbin0 -> 424 bytes
-rw-r--r--src/quickcontrols2/basic/images/check@2x.pngbin0 -> 713 bytes
-rw-r--r--src/quickcontrols2/basic/images/check@3x.pngbin0 -> 999 bytes
-rw-r--r--src/quickcontrols2/basic/images/check@4x.pngbin0 -> 1188 bytes
-rw-r--r--src/quickcontrols2/basic/images/dial-indicator.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/basic/images/dial-indicator@2x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/basic/images/dial-indicator@3x.pngbin0 -> 284 bytes
-rw-r--r--src/quickcontrols2/basic/images/dial-indicator@4x.pngbin0 -> 307 bytes
-rw-r--r--src/quickcontrols2/basic/images/double-arrow.pngbin0 -> 303 bytes
-rw-r--r--src/quickcontrols2/basic/images/double-arrow@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/basic/images/double-arrow@3x.pngbin0 -> 673 bytes
-rw-r--r--src/quickcontrols2/basic/images/double-arrow@4x.pngbin0 -> 827 bytes
-rw-r--r--src/quickcontrols2/basic/images/drop-indicator.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/basic/images/drop-indicator@2x.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/basic/images/drop-indicator@3x.pngbin0 -> 297 bytes
-rw-r--r--src/quickcontrols2/basic/images/drop-indicator@4x.pngbin0 -> 376 bytes
-rw-r--r--src/quickcontrols2/basic/impl/CMakeLists.txt25
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicbusyindicator.cpp225
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicbusyindicator_p.h93
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicdial.cpp124
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicdial_p.h82
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicprogressbar.cpp282
-rw-r--r--src/quickcontrols2/basic/impl/qquickbasicprogressbar_p.h91
-rw-r--r--src/quickcontrols2/basic/qquickbasicstyle.cpp248
-rw-r--r--src/quickcontrols2/basic/qquickbasicstyle_p.h151
-rw-r--r--src/quickcontrols2/basic/qquickbasictheme.cpp91
-rw-r--r--src/quickcontrols2/basic/qquickbasictheme_p.h65
-rw-r--r--src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.cpp80
-rw-r--r--src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.qrc24
-rw-r--r--src/quickcontrols2/configure.cmake62
-rw-r--r--src/quickcontrols2/designer/AbstractButtonSection.qml122
-rw-r--r--src/quickcontrols2/designer/BusyIndicatorSpecifics.qml74
-rw-r--r--src/quickcontrols2/designer/ButtonSection.qml74
-rw-r--r--src/quickcontrols2/designer/ButtonSpecifics.qml63
-rw-r--r--src/quickcontrols2/designer/CMakeLists.txt61
-rw-r--r--src/quickcontrols2/designer/CheckBoxSpecifics.qml64
-rw-r--r--src/quickcontrols2/designer/CheckDelegateSpecifics.qml68
-rw-r--r--src/quickcontrols2/designer/CheckSection.qml68
-rw-r--r--src/quickcontrols2/designer/ComboBoxSpecifics.qml119
-rw-r--r--src/quickcontrols2/designer/ContainerSection.qml59
-rw-r--r--src/quickcontrols2/designer/ControlSection.qml114
-rw-r--r--src/quickcontrols2/designer/ControlSpecifics.qml55
-rw-r--r--src/quickcontrols2/designer/DelayButtonSpecifics.qml81
-rw-r--r--src/quickcontrols2/designer/DialSpecifics.qml172
-rw-r--r--src/quickcontrols2/designer/FrameSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/GroupBoxSpecifics.qml77
-rw-r--r--src/quickcontrols2/designer/InsetSection.qml119
-rw-r--r--src/quickcontrols2/designer/ItemDelegateSection.qml58
-rw-r--r--src/quickcontrols2/designer/ItemDelegateSpecifics.qml63
-rw-r--r--src/quickcontrols2/designer/LabelSpecifics.qml86
-rw-r--r--src/quickcontrols2/designer/PaddingSection.qml101
-rw-r--r--src/quickcontrols2/designer/PageIndicatorSpecifics.qml98
-rw-r--r--src/quickcontrols2/designer/PageSpecifics.qml101
-rw-r--r--src/quickcontrols2/designer/PaneSection.qml73
-rw-r--r--src/quickcontrols2/designer/PaneSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/ProgressBarSpecifics.qml121
-rw-r--r--src/quickcontrols2/designer/RadioButtonSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/RadioDelegateSpecifics.qml63
-rw-r--r--src/quickcontrols2/designer/RangeSliderSpecifics.qml189
-rw-r--r--src/quickcontrols2/designer/RoundButtonSpecifics.qml84
-rw-r--r--src/quickcontrols2/designer/ScrollViewSpecifics.qml90
-rw-r--r--src/quickcontrols2/designer/SliderSpecifics.qml180
-rw-r--r--src/quickcontrols2/designer/SpinBoxSpecifics.qml142
-rw-r--r--src/quickcontrols2/designer/StackViewSpecifics.qml55
-rw-r--r--src/quickcontrols2/designer/SwipeDelegateSpecifics.qml63
-rw-r--r--src/quickcontrols2/designer/SwipeViewSpecifics.qml91
-rw-r--r--src/quickcontrols2/designer/SwitchDelegateSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/SwitchSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/TabBarSpecifics.qml107
-rw-r--r--src/quickcontrols2/designer/TabButtonSpecifics.qml59
-rw-r--r--src/quickcontrols2/designer/TextAreaSpecifics.qml104
-rw-r--r--src/quickcontrols2/designer/TextFieldSpecifics.qml101
-rw-r--r--src/quickcontrols2/designer/ToolBarSpecifics.qml79
-rw-r--r--src/quickcontrols2/designer/ToolButtonSpecifics.qml63
-rw-r--r--src/quickcontrols2/designer/ToolSeparatorSpecifics.qml71
-rw-r--r--src/quickcontrols2/designer/TumblerSpecifics.qml102
-rw-r--r--src/quickcontrols2/designer/designer.pri52
-rw-r--r--src/quickcontrols2/designer/images/busyindicator-icon.pngbin0 -> 320 bytes
-rw-r--r--src/quickcontrols2/designer/images/busyindicator-icon16.pngbin0 -> 229 bytes
-rw-r--r--src/quickcontrols2/designer/images/busyindicator-icon@2x.pngbin0 -> 643 bytes
-rw-r--r--src/quickcontrols2/designer/images/button-icon.pngbin0 -> 162 bytes
-rw-r--r--src/quickcontrols2/designer/images/button-icon16.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols2/designer/images/button-icon@2x.pngbin0 -> 259 bytes
-rw-r--r--src/quickcontrols2/designer/images/checkbox-icon.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/designer/images/checkbox-icon16.pngbin0 -> 230 bytes
-rw-r--r--src/quickcontrols2/designer/images/checkbox-icon@2x.pngbin0 -> 336 bytes
-rw-r--r--src/quickcontrols2/designer/images/combobox-icon.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/designer/images/combobox-icon16.pngbin0 -> 155 bytes
-rw-r--r--src/quickcontrols2/designer/images/combobox-icon@2x.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/designer/images/delaybutton-icon.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/designer/images/delaybutton-icon16.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/designer/images/delaybutton-icon@2x.pngbin0 -> 286 bytes
-rw-r--r--src/quickcontrols2/designer/images/dial-icon.pngbin0 -> 267 bytes
-rw-r--r--src/quickcontrols2/designer/images/dial-icon16.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/designer/images/dial-icon@2x.pngbin0 -> 505 bytes
-rw-r--r--src/quickcontrols2/designer/images/frame-icon.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/designer/images/frame-icon16.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/designer/images/frame-icon@2x.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols2/designer/images/groupbox-icon.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols2/designer/images/groupbox-icon16.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols2/designer/images/groupbox-icon@2x.pngbin0 -> 136 bytes
-rw-r--r--src/quickcontrols2/designer/images/itemdelegate-icon.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/designer/images/itemdelegate-icon16.pngbin0 -> 124 bytes
-rw-r--r--src/quickcontrols2/designer/images/itemdelegate-icon@2x.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols2/designer/images/label-icon.pngbin0 -> 206 bytes
-rw-r--r--src/quickcontrols2/designer/images/label-icon16.pngbin0 -> 182 bytes
-rw-r--r--src/quickcontrols2/designer/images/label-icon@2x.pngbin0 -> 284 bytes
-rw-r--r--src/quickcontrols2/designer/images/page-icon.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols2/designer/images/page-icon16.pngbin0 -> 148 bytes
-rw-r--r--src/quickcontrols2/designer/images/page-icon@2x.pngbin0 -> 195 bytes
-rw-r--r--src/quickcontrols2/designer/images/pageindicator-icon.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/designer/images/pageindicator-icon16.pngbin0 -> 158 bytes
-rw-r--r--src/quickcontrols2/designer/images/pageindicator-icon@2x.pngbin0 -> 207 bytes
-rw-r--r--src/quickcontrols2/designer/images/pane-icon.pngbin0 -> 93 bytes
-rw-r--r--src/quickcontrols2/designer/images/pane-icon16.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols2/designer/images/pane-icon@2x.pngbin0 -> 96 bytes
-rw-r--r--src/quickcontrols2/designer/images/progressbar-icon.pngbin0 -> 101 bytes
-rw-r--r--src/quickcontrols2/designer/images/progressbar-icon16.pngbin0 -> 92 bytes
-rw-r--r--src/quickcontrols2/designer/images/progressbar-icon@2x.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/designer/images/radiobutton-icon.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/designer/images/radiobutton-icon16.pngbin0 -> 218 bytes
-rw-r--r--src/quickcontrols2/designer/images/radiobutton-icon@2x.pngbin0 -> 482 bytes
-rw-r--r--src/quickcontrols2/designer/images/rangeslider-icon.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/designer/images/rangeslider-icon16.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/designer/images/rangeslider-icon@2x.pngbin0 -> 282 bytes
-rw-r--r--src/quickcontrols2/designer/images/roundbutton-icon.pngbin0 -> 229 bytes
-rw-r--r--src/quickcontrols2/designer/images/roundbutton-icon16.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/designer/images/roundbutton-icon@2x.pngbin0 -> 381 bytes
-rw-r--r--src/quickcontrols2/designer/images/scrollview-icon.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols2/designer/images/scrollview-icon16.pngbin0 -> 116 bytes
-rw-r--r--src/quickcontrols2/designer/images/scrollview-icon@2x.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols2/designer/images/slider-icon.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols2/designer/images/slider-icon16.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/designer/images/slider-icon@2x.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/designer/images/spinbox-icon.pngbin0 -> 144 bytes
-rw-r--r--src/quickcontrols2/designer/images/spinbox-icon16.pngbin0 -> 151 bytes
-rw-r--r--src/quickcontrols2/designer/images/spinbox-icon@2x.pngbin0 -> 178 bytes
-rw-r--r--src/quickcontrols2/designer/images/stackview-icon.pngbin0 -> 162 bytes
-rw-r--r--src/quickcontrols2/designer/images/stackview-icon16.pngbin0 -> 151 bytes
-rw-r--r--src/quickcontrols2/designer/images/stackview-icon@2x.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols2/designer/images/swipeview-icon.pngbin0 -> 163 bytes
-rw-r--r--src/quickcontrols2/designer/images/swipeview-icon16.pngbin0 -> 152 bytes
-rw-r--r--src/quickcontrols2/designer/images/swipeview-icon@2x.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/designer/images/switch-icon.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols2/designer/images/switch-icon16.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/designer/images/switch-icon@2x.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols2/designer/images/textarea-icon.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/designer/images/textarea-icon16.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols2/designer/images/textarea-icon@2x.pngbin0 -> 163 bytes
-rw-r--r--src/quickcontrols2/designer/images/textfield-icon.pngbin0 -> 154 bytes
-rw-r--r--src/quickcontrols2/designer/images/textfield-icon16.pngbin0 -> 147 bytes
-rw-r--r--src/quickcontrols2/designer/images/textfield-icon@2x.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbar-icon.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbar-icon16.pngbin0 -> 114 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbar-icon@2x.pngbin0 -> 140 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbutton-icon.pngbin0 -> 141 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbutton-icon16.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolbutton-icon@2x.pngbin0 -> 158 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolseparator-icon.pngbin0 -> 111 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolseparator-icon16.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/designer/images/toolseparator-icon@2x.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/designer/images/tumbler-icon.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/designer/images/tumbler-icon16.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/designer/images/tumbler-icon@2x.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/designer/qtquickcontrols2.metainfo522
-rw-r--r--src/quickcontrols2/doc/doc.pri6
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-applicationwindow-wireframe.pngbin0 -> 6143 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-basic-thumbnail.pngbin0 -> 4352 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-basic.pngbin0 -> 10801 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator-custom.pngbin0 -> 944 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.gifbin0 -> 17357 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.pngbin0 -> 900 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-custom.pngbin0 -> 1299 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-flat.gifbin0 -> 2388 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-highlighted.gifbin0 -> 1856 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-icononly.pngbin0 -> 434 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-textbesideicon.pngbin0 -> 1315 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-textonly.pngbin0 -> 1073 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button-textundericon.pngbin0 -> 1147 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-button.gifbin0 -> 4140 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-custom.pngbin0 -> 1792 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-group.pngbin0 -> 2950 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-tristate.gifbin0 -> 8784 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkbox.gifbin0 -> 6403 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-custom.pngbin0 -> 2179 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-tristate.gifbin0 -> 10487 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate.gifbin0 -> 15290 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-combobox-custom.pngbin0 -> 924 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-combobox-delegate.pngbin0 -> 989 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-combobox-popup.pngbin0 -> 989 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-combobox.gifbin0 -> 7873 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-control.pngbin0 -> 47718 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-control.svg936
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-customize-buttons.pngbin0 -> 2542 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton-custom.pngbin0 -> 5112 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton.gifbin0 -> 12595 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-custom.pngbin0 -> 2847 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-handle.pngbin0 -> 4203 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputMode.svgzbin0 -> 2753 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputmode.pngbin0 -> 9151 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-no-wrap.gifbin0 -> 52372 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial-wrap.gifbin0 -> 70792 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dial.pngbin0 -> 2603 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox-attached.pngbin0 -> 1489 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox.pngbin0 -> 1459 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-drawer-expanded-wireframe.pngbin0 -> 2260 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-drawer-wireframe.pngbin0 -> 1534 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-drawer.gifbin0 -> 55780 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-frame-custom.pngbin0 -> 1930 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-frame.pngbin0 -> 2912 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-fusion-palettes.pngbin0 -> 11034 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-fusion-thumbnail.pngbin0 -> 6275 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-fusion-violet.pngbin0 -> 3059 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-fusion.pngbin0 -> 9302 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-checkable.pngbin0 -> 5006 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-custom.pngbin0 -> 3046 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-label.pngbin0 -> 1662 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-groupbox.pngbin0 -> 4442 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-4x.pngbin0 -> 4917 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset-boundaries.pngbin0 -> 6237 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset.pngbin0 -> 1906 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-padding.pngbin0 -> 20260 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-stretchable.pngbin0 -> 16437 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-size.pngbin0 -> 6386 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch.svgzbin0 -> 7598 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization-dark.pngbin0 -> 3001 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization.svgzbin0 -> 2215 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine-thumbnail.pngbin0 -> 4043 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-imagine.pngbin0 -> 7918 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate-custom.pngbin0 -> 1358 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.gifbin0 -> 16287 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.pngbin0 -> 5645 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-label-custom.pngbin0 -> 942 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-label.pngbin0 -> 925 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-macos-dark.pngbin0 -> 23979 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-macos-light.pngbin0 -> 22318 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-macos-thumbnail.pngbin0 -> 22504 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-accent.pngbin0 -> 1291 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-attributes.pngbin0 -> 7618 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-background.pngbin0 -> 1444 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-dark.pngbin0 -> 10934 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-elevation.pngbin0 -> 2566 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-foreground.pngbin0 -> 1377 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-light.pngbin0 -> 11182 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-purple.pngbin0 -> 3256 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-theme.pngbin0 -> 1451 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-thumbnail.pngbin0 -> 10480 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-dense.pngbin0 -> 21059 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-normal.pngbin0 -> 22897 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menu-custom.pngbin0 -> 7293 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menu.gifbin0 -> 4683 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menu.pngbin0 -> 3629 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menubar-custom.pngbin0 -> 2659 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menubar.pngbin0 -> 8870 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator-custom.pngbin0 -> 4644 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator.pngbin0 -> 4672 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-page-wireframe.pngbin0 -> 1795 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-custom.pngbin0 -> 248 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-delegate.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator.pngbin0 -> 248 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-pane-custom.pngbin0 -> 1674 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-pane.pngbin0 -> 2473 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-popup-custom.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-popup-settings.pngbin0 -> 10545 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-popup-transformorigin.pngbin0 -> 7256 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-popup.pngbin0 -> 62355 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-popup.svg712
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-custom.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-indeterminate.gifbin0 -> 5882 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-progressbar.gifbin0 -> 2072 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton-custom.pngbin0 -> 2207 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton.gifbin0 -> 7993 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate-custom.pngbin0 -> 2501 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate.gifbin0 -> 16859 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider-custom.pngbin0 -> 585 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider.gifbin0 -> 24125 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-roundbutton.pngbin0 -> 662 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-custom.pngbin0 -> 148 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-non-attached.pngbin0 -> 4645 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-nosnap.gifbin0 -> 5271 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snapalways.gifbin0 -> 4707 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snaponrelease.gifbin0 -> 5646 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar.gifbin0 -> 32067 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-custom.pngbin0 -> 102 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-non-attached.pngbin0 -> 4468 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator.gifbin0 -> 42352 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-custom.pngbin0 -> 4423 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-wireframe.pngbin0 -> 705 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-scrollview.pngbin0 -> 4424 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-selectionrectangle.pngbin0 -> 52957 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider-custom.pngbin0 -> 454 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider-handle.pngbin0 -> 439 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider-nosnap.gifbin0 -> 18138 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider-snapalways.gifbin0 -> 7201 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider-snaponrelease.gifbin0 -> 18377 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-slider.gifbin0 -> 13697 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-custom.pngbin0 -> 1006 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-double.pngbin0 -> 737 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-down.pngbin0 -> 784 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-textual.pngbin0 -> 1096 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-up.pngbin0 -> 786 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-spinbox.pngbin0 -> 775 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-splitview-custom.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-custom.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-pop.gifbin0 -> 23801 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-push.gifbin0 -> 42790 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-replace.gifbin0 -> 28882 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-unwind.gifbin0 -> 23744 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-visible.pngbin0 -> 512 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-stackview-wireframe.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-styles.pngbin0 -> 101053 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-behind.gifbin0 -> 248344 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-custom.pngbin0 -> 1818 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-leading-trailing.gifbin0 -> 132134 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate.gifbin0 -> 123494 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-indicator.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-wireframe.pngbin0 -> 1482 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-swipeview.gifbin0 -> 35983 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switch-checked.pngbin0 -> 1723 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switch-custom.pngbin0 -> 1734 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switch.gifbin0 -> 3466 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switch.pngbin0 -> 2042 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate-custom.pngbin0 -> 2773 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate.gifbin0 -> 38688 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-custom.pngbin0 -> 2644 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-explicit.pngbin0 -> 2093 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-flickable.pngbin0 -> 2527 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-wireframe.pngbin0 -> 348 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.gifbin0 -> 8590 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.pngbin0 -> 2897 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tabbutton.pngbin0 -> 2646 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textarea-custom.pngbin0 -> 1320 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textarea-scrollable.pngbin0 -> 1580 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textarea.pngbin0 -> 1968 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textfield-custom.pngbin0 -> 2083 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textfield-disabled.pngbin0 -> 1261 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textfield-focused.pngbin0 -> 1316 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textfield-normal.pngbin0 -> 1304 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-textfield.pngbin0 -> 1680 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolbar-custom.pngbin0 -> 1174 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolbar.pngbin0 -> 1008 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton-custom.pngbin0 -> 1398 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton.pngbin0 -> 1226 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator-custom.pngbin0 -> 3586 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator.pngbin0 -> 5381 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-delay.pngbin0 -> 1144 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-hover.pngbin0 -> 1110 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-pressandhold.pngbin0 -> 1110 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-slider.pngbin0 -> 1261 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tooltip.pngbin0 -> 5523 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-custom.pngbin0 -> 1879 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-delegate.pngbin0 -> 929 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-wrap.gifbin0 -> 54328 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-tumbler.pngbin0 -> 1050 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-accent.pngbin0 -> 1058 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-attributes.pngbin0 -> 5298 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-background.pngbin0 -> 1161 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-button.pngbin0 -> 674 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-dark.pngbin0 -> 10373 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-foreground.pngbin0 -> 985 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-light.pngbin0 -> 10846 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-theme.pngbin0 -> 1205 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-thumbnail.pngbin0 -> 8606 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-universal-violet.pngbin0 -> 2894 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-windows-thumbnail.pngbin0 -> 12394 bytes
-rw-r--r--src/quickcontrols2/doc/images/qtquickcontrols2-windows.pngbin0 -> 17132 bytes
-rw-r--r--src/quickcontrols2/doc/manifest-meta.qdocconf32
-rw-r--r--src/quickcontrols2/doc/qtquickcontrols.qdocconf104
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-action.qml56
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-busyindicator-custom.qml92
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-button-custom.qml55
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-button-icononly.qml34
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textbesideicon.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textonly.qml34
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-custom.qml65
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-group.qml58
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-checkdelegate-custom.qml74
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-accepted.qml (renamed from src/quick/doc/src/cmake-macros.qdoc)47
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-custom.qml114
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-find.qml40
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-popup.qml37
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-textat.qml40
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-valuerole.qml58
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-delaybutton-custom.qml82
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dial-custom.qml67
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modal.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modeless.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog.qml44
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox-attached.qml42
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox.qml38
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-frame-custom.qml43
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-frame.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-checkable.qml48
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-custom.qml57
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox.qml42
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-headerview-simple.qml119
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate-custom.qml59
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate.qml48
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-label-custom.qml36
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-label.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-accent.qml43
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-background.qml42
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-elevation.qml51
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-foreground.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-theme.qml44
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-material-variant.qml213
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-menu-custom.qml133
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar-custom.qml84
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar.qml67
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator-custom.qml69
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator.qml60
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modal.qml55
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modeless.qml55
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-overview.cmake4
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-custom.qml55
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-interactive.qml58
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-pane-custom.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-pane.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-popup-custom.qml53
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-popup.qml46
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-progressbar-custom.qml56
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-radiobutton-custom.qml65
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-radiodelegate-custom.qml74
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-rangeslider-custom.qml76
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-roundbutton.qml36
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-active.qml46
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-custom.qml53
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-non-attached.qml80
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-policy.qml38
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-active.qml46
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-custom.qml45
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-non-attached.qml84
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-custom.qml81
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-interactive.qml38
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-listview.qml63
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-policy.qml38
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview.qml60
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-selectionrectangle.qml95
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-slider-custom.qml64
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-custom.qml96
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-double.qml56
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-textual.qml56
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-custom.qml57
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-handle-containmentmask.qml64
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-custom.qml53
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-visible.qml76
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml72
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-transition.qml37
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml86
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-custom.qml39
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-indicator.qml63
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-switch-custom.qml64
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-switchdelegate-custom.qml73
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-custom.qml49
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-explicit.qml52
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-flickable.qml50
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar.qml64
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbutton.qml43
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-custom.qml42
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-scrollable.qml47
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-custom.qml43
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-disabled.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-focused.qml35
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-normal.qml34
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar-custom.qml59
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar.qml63
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbutton-custom.qml55
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator-custom.qml69
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator.qml68
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-custom.qml48
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-hover.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-pressandhold.qml39
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-slider.qml53
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip.qml51
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-custom.qml81
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-listView.qml46
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-pathView.qml57
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-timePicker.qml86
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-accent.qml43
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-background.qml44
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-foreground.qml41
-rw-r--r--src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-theme.qml44
-rw-r--r--src/quickcontrols2/doc/src/external-pages.qdoc36
-rw-r--r--src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc9
-rw-r--r--src/quickcontrols2/doc/src/includes/customize-button-background.qdocinc25
-rw-r--r--src/quickcontrols2/doc/src/includes/customizing-native-styles.qdocinc14
-rw-r--r--src/quickcontrols2/doc/src/includes/inputmethodhints.qdocinc38
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickcombobox.qdocinc6
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickcontrol-background.qdocinc13
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickcontrol-focusreason.qdocinc15
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickdial.qdocinc13
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickicon.qdocinc52
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc59
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickmaterialstyle.qdocinc79
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickoverlay-popup-parent.qdocinc20
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickpopup-padding.qdocinc10
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickstackview.qdocinc5
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickswipedelegate-interaction.qdocinc5
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickswitch.qdocinc28
-rw-r--r--src/quickcontrols2/doc/src/includes/qquicktooltip.qdocinc6
-rw-r--r--src/quickcontrols2/doc/src/includes/qquickuniversalstyle.qdocinc53
-rw-r--r--src/quickcontrols2/doc/src/qt6-changes.qdoc305
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-basic.qdoc55
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-buttons.qdoc191
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-configuration.qdoc204
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-containers.qdoc113
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-cppclasses.qdoc58
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-customize.qdoc1057
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-delegates.qdoc89
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-deployment.qdoc97
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-environment.qdoc78
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-examples.qdoc37
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-fileselectors.qdoc140
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-focus.qdoc48
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-fusion.qdoc93
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-gettingstarted.qdoc86
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-guidelines.qdoc46
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-icons.qdoc169
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-imagine.qdoc2535
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-index.qdoc209
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-indicators.qdoc83
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-input.qdoc123
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-macos.qdoc73
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-material.qdoc404
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-menus.qdoc68
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-navigation.qdoc70
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-popups.qdoc99
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-qmltypes.qdoc130
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-separators.qdoc63
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-styles.qdoc221
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-universal.qdoc288
-rw-r--r--src/quickcontrols2/doc/src/qtquickcontrols2-windows.qdoc71
-rw-r--r--src/quickcontrols2/fusion/ApplicationWindow.qml47
-rw-r--r--src/quickcontrols2/fusion/BusyIndicator.qml70
-rw-r--r--src/quickcontrols2/fusion/Button.qml76
-rw-r--r--src/quickcontrols2/fusion/CMakeLists.txt145
-rw-r--r--src/quickcontrols2/fusion/CheckBox.qml71
-rw-r--r--src/quickcontrols2/fusion/CheckDelegate.qml86
-rw-r--r--src/quickcontrols2/fusion/ComboBox.qml174
-rw-r--r--src/quickcontrols2/fusion/DelayButton.qml115
-rw-r--r--src/quickcontrols2/fusion/Dial.qml73
-rw-r--r--src/quickcontrols2/fusion/Dialog.qml99
-rw-r--r--src/quickcontrols2/fusion/DialogButtonBox.qml74
-rw-r--r--src/quickcontrols2/fusion/Drawer.qml88
-rw-r--r--src/quickcontrols2/fusion/Frame.qml57
-rw-r--r--src/quickcontrols2/fusion/GroupBox.qml76
-rw-r--r--src/quickcontrols2/fusion/HorizontalHeaderView.qml77
-rw-r--r--src/quickcontrols2/fusion/ItemDelegate.qml76
-rw-r--r--src/quickcontrols2/fusion/Label.qml48
-rw-r--r--src/quickcontrols2/fusion/Menu.qml94
-rw-r--r--src/quickcontrols2/fusion/MenuBar.qml73
-rw-r--r--src/quickcontrols2/fusion/MenuBarItem.qml77
-rw-r--r--src/quickcontrols2/fusion/MenuItem.qml102
-rw-r--r--src/quickcontrols2/fusion/MenuSeparator.qml59
-rw-r--r--src/quickcontrols2/fusion/Page.qml58
-rw-r--r--src/quickcontrols2/fusion/PageIndicator.qml76
-rw-r--r--src/quickcontrols2/fusion/Pane.qml56
-rw-r--r--src/quickcontrols2/fusion/Popup.qml66
-rw-r--r--src/quickcontrols2/fusion/ProgressBar.qml116
-rw-r--r--src/quickcontrols2/fusion/RadioButton.qml71
-rw-r--r--src/quickcontrols2/fusion/RadioDelegate.qml86
-rw-r--r--src/quickcontrols2/fusion/RangeSlider.qml81
-rw-r--r--src/quickcontrols2/fusion/RoundButton.qml100
-rw-r--r--src/quickcontrols2/fusion/ScrollBar.qml77
-rw-r--r--src/quickcontrols2/fusion/ScrollIndicator.qml77
-rw-r--r--src/quickcontrols2/fusion/ScrollView.qml64
-rw-r--r--src/quickcontrols2/fusion/SelectionRectangle.qml63
-rw-r--r--src/quickcontrols2/fusion/Slider.qml67
-rw-r--r--src/quickcontrols2/fusion/SpinBox.qml181
-rw-r--r--src/quickcontrols2/fusion/SplitView.qml55
-rw-r--r--src/quickcontrols2/fusion/SwipeDelegate.qml78
-rw-r--r--src/quickcontrols2/fusion/Switch.qml71
-rw-r--r--src/quickcontrols2/fusion/SwitchDelegate.qml85
-rw-r--r--src/quickcontrols2/fusion/TabBar.qml79
-rw-r--r--src/quickcontrols2/fusion/TabButton.qml96
-rw-r--r--src/quickcontrols2/fusion/TextArea.qml76
-rw-r--r--src/quickcontrols2/fusion/TextField.qml102
-rw-r--r--src/quickcontrols2/fusion/ToolBar.qml82
-rw-r--r--src/quickcontrols2/fusion/ToolButton.qml76
-rw-r--r--src/quickcontrols2/fusion/ToolSeparator.qml66
-rw-r--r--src/quickcontrols2/fusion/ToolTip.qml79
-rw-r--r--src/quickcontrols2/fusion/Tumbler.qml79
-rw-r--r--src/quickcontrols2/fusion/VerticalHeaderView.qml77
-rw-r--r--src/quickcontrols2/fusion/fusion.pri59
-rw-r--r--src/quickcontrols2/fusion/images/arrow.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/fusion/images/arrow.svg75
-rw-r--r--src/quickcontrols2/fusion/images/arrow@2x.pngbin0 -> 145 bytes
-rw-r--r--src/quickcontrols2/fusion/images/arrow@3x.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols2/fusion/images/arrow@4x.pngbin0 -> 182 bytes
-rw-r--r--src/quickcontrols2/fusion/images/checkmark.pngbin0 -> 181 bytes
-rw-r--r--src/quickcontrols2/fusion/images/checkmark.svg72
-rw-r--r--src/quickcontrols2/fusion/images/checkmark@2x.pngbin0 -> 316 bytes
-rw-r--r--src/quickcontrols2/fusion/images/checkmark@3x.pngbin0 -> 420 bytes
-rw-r--r--src/quickcontrols2/fusion/images/checkmark@4x.pngbin0 -> 482 bytes
-rw-r--r--src/quickcontrols2/fusion/images/progressmask.pngbin0 -> 309 bytes
-rw-r--r--src/quickcontrols2/fusion/images/progressmask.svg74
-rw-r--r--src/quickcontrols2/fusion/images/progressmask@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/fusion/images/progressmask@3x.pngbin0 -> 558 bytes
-rw-r--r--src/quickcontrols2/fusion/images/progressmask@4x.pngbin0 -> 652 bytes
-rw-r--r--src/quickcontrols2/fusion/impl/ButtonPanel.qml79
-rw-r--r--src/quickcontrols2/fusion/impl/CMakeLists.txt39
-rw-r--r--src/quickcontrols2/fusion/impl/CheckIndicator.qml91
-rw-r--r--src/quickcontrols2/fusion/impl/RadioIndicator.qml77
-rw-r--r--src/quickcontrols2/fusion/impl/SliderGroove.qml93
-rw-r--r--src/quickcontrols2/fusion/impl/SliderHandle.qml87
-rw-r--r--src/quickcontrols2/fusion/impl/SwitchIndicator.qml139
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusionbusyindicator.cpp113
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusionbusyindicator_p.h84
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusiondial.cpp141
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusiondial_p.h76
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusionknob.cpp90
-rw-r--r--src/quickcontrols2/fusion/impl/qquickfusionknob_p.h69
-rw-r--r--src/quickcontrols2/fusion/qquickfusionstyle.cpp153
-rw-r--r--src/quickcontrols2/fusion/qquickfusionstyle_p.h92
-rw-r--r--src/quickcontrols2/fusion/qquickfusiontheme.cpp57
-rw-r--r--src/quickcontrols2/fusion/qquickfusiontheme_p.h65
-rw-r--r--src/quickcontrols2/fusion/qtquickcontrols2fusionstyle.qrc16
-rw-r--r--src/quickcontrols2/fusion/qtquickcontrols2fusionstyleplugin.cpp81
-rw-r--r--src/quickcontrols2/imagine/ApplicationWindow.qml57
-rw-r--r--src/quickcontrols2/imagine/BusyIndicator.qml88
-rw-r--r--src/quickcontrols2/imagine/Button.qml98
-rw-r--r--src/quickcontrols2/imagine/CMakeLists.txt145
-rw-r--r--src/quickcontrols2/imagine/CheckBox.qml106
-rw-r--r--src/quickcontrols2/imagine/CheckDelegate.qml117
-rw-r--r--src/quickcontrols2/imagine/ComboBox.qml173
-rw-r--r--src/quickcontrols2/imagine/DelayButton.qml137
-rw-r--r--src/quickcontrols2/imagine/Dial.qml105
-rw-r--r--src/quickcontrols2/imagine/Dialog.qml116
-rw-r--r--src/quickcontrols2/imagine/DialogButtonBox.qml85
-rw-r--r--src/quickcontrols2/imagine/Drawer.qml96
-rw-r--r--src/quickcontrols2/imagine/Frame.qml69
-rw-r--r--src/quickcontrols2/imagine/GroupBox.qml99
-rw-r--r--src/quickcontrols2/imagine/HorizontalHeaderView.qml67
-rw-r--r--src/quickcontrols2/imagine/ItemDelegate.qml93
-rw-r--r--src/quickcontrols2/imagine/Label.qml63
-rw-r--r--src/quickcontrols2/imagine/Menu.qml107
-rw-r--r--src/quickcontrols2/imagine/MenuItem.qml137
-rw-r--r--src/quickcontrols2/imagine/MenuSeparator.qml79
-rw-r--r--src/quickcontrols2/imagine/Page.qml73
-rw-r--r--src/quickcontrols2/imagine/PageIndicator.qml92
-rw-r--r--src/quickcontrols2/imagine/Pane.qml69
-rw-r--r--src/quickcontrols2/imagine/Popup.qml87
-rw-r--r--src/quickcontrols2/imagine/ProgressBar.qml141
-rw-r--r--src/quickcontrols2/imagine/RadioButton.qml104
-rw-r--r--src/quickcontrols2/imagine/RadioDelegate.qml115
-rw-r--r--src/quickcontrols2/imagine/RangeSlider.qml134
-rw-r--r--src/quickcontrols2/imagine/RoundButton.qml97
-rw-r--r--src/quickcontrols2/imagine/ScrollBar.qml119
-rw-r--r--src/quickcontrols2/imagine/ScrollIndicator.qml111
-rw-r--r--src/quickcontrols2/imagine/ScrollView.qml85
-rw-r--r--src/quickcontrols2/imagine/SelectionRectangle.qml76
-rw-r--r--src/quickcontrols2/imagine/Slider.qml120
-rw-r--r--src/quickcontrols2/imagine/SpinBox.qml152
-rw-r--r--src/quickcontrols2/imagine/SplitView.qml63
-rw-r--r--src/quickcontrols2/imagine/StackView.qml91
-rw-r--r--src/quickcontrols2/imagine/SwipeDelegate.qml95
-rw-r--r--src/quickcontrols2/imagine/SwipeView.qml90
-rw-r--r--src/quickcontrols2/imagine/Switch.qml134
-rw-r--r--src/quickcontrols2/imagine/SwitchDelegate.qml146
-rw-r--r--src/quickcontrols2/imagine/TabBar.qml87
-rw-r--r--src/quickcontrols2/imagine/TabButton.qml91
-rw-r--r--src/quickcontrols2/imagine/TextArea.qml96
-rw-r--r--src/quickcontrols2/imagine/TextField.qml95
-rw-r--r--src/quickcontrols2/imagine/ToolBar.qml71
-rw-r--r--src/quickcontrols2/imagine/ToolButton.qml94
-rw-r--r--src/quickcontrols2/imagine/ToolSeparator.qml83
-rw-r--r--src/quickcontrols2/imagine/ToolTip.qml85
-rw-r--r--src/quickcontrols2/imagine/Tumbler.qml96
-rw-r--r--src/quickcontrols2/imagine/VerticalHeaderView.qml67
-rw-r--r--src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/9-patch-export.js24
-rw-r--r--src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/manifest.json19
-rw-r--r--src/quickcontrols2/imagine/design/imagine.sketchbin0 -> 164993 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-background.pngbin0 -> 67 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-background@2x.pngbin0 -> 75 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-background@3x.pngbin0 -> 77 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-background@4x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay-modal.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/applicationwindow-overlay@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/busyindicator-animation.webpbin0 -> 30116 bytes
-rw-r--r--src/quickcontrols2/imagine/images/busyindicator-animation@2x.webpbin0 -> 56588 bytes
-rw-r--r--src/quickcontrols2/imagine/images/busyindicator-animation@3x.webpbin0 -> 77816 bytes
-rw-r--r--src/quickcontrols2/imagine/images/busyindicator-animation@4x.webpbin0 -> 103290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-disabled.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-disabled@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-disabled@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-disabled@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-focused.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-focused@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-focused@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-focused@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-disabled.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-disabled@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-disabled@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-disabled@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-disabled.9.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-disabled@2x.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-disabled@3x.9.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-disabled@4x.9.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted.9.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted@2x.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted@3x.9.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-highlighted@4x.9.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat.9.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat@2x.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat@3x.9.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-flat@4x.9.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-focused.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-focused@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-focused@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-focused@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-disabled.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-disabled@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-disabled@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-disabled@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-focused.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-focused@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-focused@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-focused@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-highlighted@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/button-background@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@2x.pngbin0 -> 501 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@3x.pngbin0 -> 626 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@4x.pngbin0 -> 848 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked@2x.pngbin0 -> 499 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked@3x.pngbin0 -> 625 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-checked@4x.pngbin0 -> 830 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-disabled.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-disabled@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-disabled@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-disabled@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-focused.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-focused@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-focused@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-focused@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-hovered.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-hovered@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-hovered@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-hovered@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-pressed.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-pressed@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-pressed@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator-pressed@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkbox-indicator@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-disabled.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-focused.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-highlighted.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-hovered.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-hovered@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-hovered@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-hovered@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-pressed.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@2x.pngbin0 -> 501 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@3x.pngbin0 -> 626 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@4x.pngbin0 -> 848 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@2x.pngbin0 -> 499 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@3x.pngbin0 -> 625 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@4x.pngbin0 -> 830 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-focused.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked.pngbin0 -> 131 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@2x.pngbin0 -> 164 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@3x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@4x.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/checkdelegate-indicator@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-disabled.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-disabled@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-disabled@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-disabled@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-disabled.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-disabled@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-disabled@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-disabled@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-focused.9.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-focused@2x.9.pngbin0 -> 338 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-focused@3x.9.pngbin0 -> 549 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable-focused@4x.9.pngbin0 -> 798 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable.9.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable@2x.9.pngbin0 -> 338 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable@3x.9.pngbin0 -> 549 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-editable@4x.9.pngbin0 -> 798 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-focused.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-focused@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-focused@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-focused@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-hovered.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-hovered@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-hovered@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-hovered@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-open.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-open@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-open@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-open@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-pressed.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-pressed@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-pressed@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background-pressed@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background.9.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background@2x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background@3x.9.pngbin0 -> 387 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-background@4x.9.pngbin0 -> 596 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-disabled.pngbin0 -> 152 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-disabled@2x.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-disabled@3x.pngbin0 -> 211 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-disabled@4x.pngbin0 -> 201 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled.pngbin0 -> 197 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@2x.pngbin0 -> 259 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@3x.pngbin0 -> 386 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@4x.pngbin0 -> 445 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled.pngbin0 -> 193 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@2x.pngbin0 -> 263 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@3x.pngbin0 -> 394 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@4x.pngbin0 -> 450 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored.pngbin0 -> 199 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@2x.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@3x.pngbin0 -> 402 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@4x.pngbin0 -> 456 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable.pngbin0 -> 203 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable@2x.pngbin0 -> 266 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator-editable@4x.pngbin0 -> 452 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator@2x.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator@3x.pngbin0 -> 230 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-indicator@4x.pngbin0 -> 215 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-popup.9.pngbin0 -> 424 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-popup@2x.9.pngbin0 -> 796 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-popup@3x.9.pngbin0 -> 1212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/combobox-popup@4x.9.pngbin0 -> 1644 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-focused.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-disabled@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-focused.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-focused@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-focused@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-focused@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-hovered.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-hovered@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-hovered@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-hovered@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-pressed.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-pressed@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-pressed@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background-pressed@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-background@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-mask.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-mask@2x.9.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-mask@3x.9.pngbin0 -> 339 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-mask@4x.9.pngbin0 -> 441 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress-disabled.9.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress-disabled@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress-disabled@3x.9.pngbin0 -> 154 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress-disabled@4x.9.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress.9.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress@3x.9.pngbin0 -> 154 bytes
-rw-r--r--src/quickcontrols2/imagine/images/delaybutton-progress@4x.9.pngbin0 -> 165 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-disabled.pngbin0 -> 3098 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-disabled@2x.pngbin0 -> 5609 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-disabled@3x.pngbin0 -> 13029 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-disabled@4x.pngbin0 -> 18158 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-focused.pngbin0 -> 3098 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-focused@2x.pngbin0 -> 5609 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-focused@3x.pngbin0 -> 13382 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background-focused@4x.pngbin0 -> 18762 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background.pngbin0 -> 3098 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background@2x.pngbin0 -> 5609 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background@3x.pngbin0 -> 13268 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-background@4x.pngbin0 -> 18609 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-disabled.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-disabled@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-disabled@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-disabled@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-hovered.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-hovered@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-hovered@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-hovered@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-pressed.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-pressed@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-pressed@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused-pressed@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-focused@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-hovered.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-hovered@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-hovered@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-hovered@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-pressed.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-pressed@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-pressed@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle-pressed@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle@2x.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle@3x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dial-handle@4x.pngbin0 -> 231 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-background.9.pngbin0 -> 426 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-background@2x.9.pngbin0 -> 792 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-background@3x.9.pngbin0 -> 1206 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-background@4x.9.pngbin0 -> 1625 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay-modal.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay-modal@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay-modal@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay-modal@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialog-overlay@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialogbuttonbox-background.9.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialogbuttonbox-background@2x.9.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialogbuttonbox-background@3x.9.pngbin0 -> 119 bytes
-rw-r--r--src/quickcontrols2/imagine/images/dialogbuttonbox-background@4x.9.pngbin0 -> 119 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-bottom.9.pngbin0 -> 224 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-bottom@2x.9.pngbin0 -> 334 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-bottom@3x.9.pngbin0 -> 443 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-bottom@4x.9.pngbin0 -> 531 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-left.9.pngbin0 -> 218 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-left@2x.9.pngbin0 -> 321 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-left@3x.9.pngbin0 -> 417 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-left@4x.9.pngbin0 -> 532 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-right.9.pngbin0 -> 229 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-right@2x.9.pngbin0 -> 333 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-right@3x.9.pngbin0 -> 433 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-right@4x.9.pngbin0 -> 549 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-top.9.pngbin0 -> 216 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-top@2x.9.pngbin0 -> 325 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-top@3x.9.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-background-top@4x.9.pngbin0 -> 533 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay-modal.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay-modal@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay-modal@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay-modal@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/drawer-overlay@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/frame-background.9.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols2/imagine/images/frame-background@2x.9.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols2/imagine/images/frame-background@3x.9.pngbin0 -> 379 bytes
-rw-r--r--src/quickcontrols2/imagine/images/frame-background@4x.9.pngbin0 -> 477 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-background.9.pngbin0 -> 190 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-background@2x.9.pngbin0 -> 281 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-background@3x.9.pngbin0 -> 379 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-background@4x.9.pngbin0 -> 477 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-title.9.pngbin0 -> 112 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-title@2x.9.pngbin0 -> 117 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-title@3x.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/groupbox-title@4x.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-disabled.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-focused.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-highlighted.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-hovered.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-hovered@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-hovered@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-hovered@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-pressed.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/itemdelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menu-background.9.pngbin0 -> 664 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menu-background@2x.9.pngbin0 -> 1324 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menu-background@3x.9.pngbin0 -> 2099 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menu-background@4x.9.pngbin0 -> 2958 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-disabled.pngbin0 -> 173 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-disabled@2x.pngbin0 -> 204 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-disabled@3x.pngbin0 -> 251 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-disabled@4x.pngbin0 -> 294 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled.pngbin0 -> 181 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@2x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@3x.pngbin0 -> 253 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@4x.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored.pngbin0 -> 181 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@2x.pngbin0 -> 212 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@3x.pngbin0 -> 253 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@4x.pngbin0 -> 301 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow.pngbin0 -> 176 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow@2x.pngbin0 -> 204 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow@3x.pngbin0 -> 251 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-arrow@4x.pngbin0 -> 294 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background-highlighted.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background-highlighted@2x.9.pngbin0 -> 124 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background-highlighted@3x.9.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background-highlighted@4x.9.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background.9.pngbin0 -> 115 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background@2x.9.pngbin0 -> 118 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background@3x.9.pngbin0 -> 119 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-background@4x.9.pngbin0 -> 124 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered.pngbin0 -> 271 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@2x.pngbin0 -> 468 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@3x.pngbin0 -> 599 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@4x.pngbin0 -> 815 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@2x.pngbin0 -> 501 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@3x.pngbin0 -> 626 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@4x.pngbin0 -> 848 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked.pngbin0 -> 275 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked@2x.pngbin0 -> 499 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked@3x.pngbin0 -> 625 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-checked@4x.pngbin0 -> 830 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-disabled.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-disabled@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-disabled@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-disabled@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-focused.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-focused@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-focused@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-focused@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-hovered.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-hovered@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-hovered@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-hovered@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-pressed.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-pressed@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-pressed@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator-pressed@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator.pngbin0 -> 121 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator@2x.pngbin0 -> 156 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator@3x.pngbin0 -> 192 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuitem-indicator@4x.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuseparator-separator.9.pngbin0 -> 98 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuseparator-separator@2x.9.pngbin0 -> 110 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuseparator-separator@3x.9.pngbin0 -> 113 bytes
-rw-r--r--src/quickcontrols2/imagine/images/menuseparator-separator@4x.9.pngbin0 -> 115 bytes
-rw-r--r--src/quickcontrols2/imagine/images/page-background.pngbin0 -> 67 bytes
-rw-r--r--src/quickcontrols2/imagine/images/page-background@2x.pngbin0 -> 75 bytes
-rw-r--r--src/quickcontrols2/imagine/images/page-background@3x.pngbin0 -> 77 bytes
-rw-r--r--src/quickcontrols2/imagine/images/page-background@4x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-current.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-current@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-current@3x.pngbin0 -> 220 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-current@4x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@3x.pngbin0 -> 220 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@4x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@3x.pngbin0 -> 220 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@4x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-pressed.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@3x.pngbin0 -> 220 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@4x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate@2x.pngbin0 -> 179 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate@3x.pngbin0 -> 220 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pageindicator-delegate@4x.pngbin0 -> 280 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pane-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pane-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pane-background@3x.9.pngbin0 -> 130 bytes
-rw-r--r--src/quickcontrols2/imagine/images/pane-background@4x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-background.9.pngbin0 -> 426 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-background@2x.9.pngbin0 -> 792 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-background@3x.9.pngbin0 -> 1206 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-background@4x.9.pngbin0 -> 1625 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay-modal.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay-modal@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay-modal@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay-modal@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay.pngbin0 -> 70 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay@2x.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay@3x.pngbin0 -> 78 bytes
-rw-r--r--src/quickcontrols2/imagine/images/popup-overlay@4x.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-animation.webpbin0 -> 4760 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-animation@2x.webpbin0 -> 7932 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-animation@3x.webpbin0 -> 8154 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-animation@4x.webpbin0 -> 9646 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-background.9.pngbin0 -> 194 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-background@2x.9.pngbin0 -> 284 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-background@3x.9.pngbin0 -> 405 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-background@4x.9.pngbin0 -> 580 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-mask.9.pngbin0 -> 166 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-mask@2x.9.pngbin0 -> 223 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-mask@3x.9.pngbin0 -> 293 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-mask@4x.9.pngbin0 -> 344 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-progress.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-progress@2x.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-progress@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/progressbar-progress@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@3x.pngbin0 -> 643 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@3x.pngbin0 -> 643 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked.pngbin0 -> 264 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-checked@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-disabled.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-focused.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-focused@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-focused@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-focused@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-hovered.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-pressed.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiobutton-indicator@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-disabled.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-focused.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-highlighted.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-hovered.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-hovered@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-hovered@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-hovered@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-pressed.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@3x.pngbin0 -> 643 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@3x.pngbin0 -> 643 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked.pngbin0 -> 264 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@2x.pngbin0 -> 442 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@4x.pngbin0 -> 881 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-focused.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator.pngbin0 -> 213 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator@2x.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator@3x.pngbin0 -> 490 bytes
-rw-r--r--src/quickcontrols2/imagine/images/radiodelegate-indicator@4x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-horizontal.9.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-horizontal@2x.9.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-horizontal@3x.9.pngbin0 -> 332 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-horizontal@4x.9.pngbin0 -> 444 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-vertical.9.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-vertical@2x.9.pngbin0 -> 252 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-vertical@3x.9.pngbin0 -> 328 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-background-vertical@4x.9.pngbin0 -> 464 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-disabled.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-disabled@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-disabled@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-disabled@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@4x.pngbin0 -> 990 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@4x.pngbin0 -> 990 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-focused@4x.pngbin0 -> 998 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-hovered.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-hovered@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-hovered@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-hovered@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-pressed.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-pressed@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-pressed@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle-pressed@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle@2x.pngbin0 -> 487 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle@3x.pngbin0 -> 728 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-handle@4x.pngbin0 -> 976 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled.9.pngbin0 -> 144 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@2x.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@3x.9.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@4x.9.pngbin0 -> 273 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal.9.pngbin0 -> 144 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@2x.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@3x.9.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@4x.9.pngbin0 -> 273 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled.9.pngbin0 -> 143 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@2x.9.pngbin0 -> 188 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@3x.9.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@4x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical.9.pngbin0 -> 143 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical@2x.9.pngbin0 -> 188 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical@3x.9.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/imagine/images/rangeslider-progress-vertical@4x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-focused.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-checked@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-disabled@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-focused.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-focused@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-focused@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-focused@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-highlighted@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-hovered.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-hovered@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-hovered@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-hovered@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-pressed.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-pressed@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-pressed@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background-pressed@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background.pngbin0 -> 350 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background@2x.pngbin0 -> 663 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background@3x.pngbin0 -> 922 bytes
-rw-r--r--src/quickcontrols2/imagine/images/roundbutton-background@4x.pngbin0 -> 1290 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-disabled.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-disabled@2x.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-disabled@3x.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-disabled@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle-interactive@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle@2x.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle@3x.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollbar-handle@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollindicator-handle.pngbin0 -> 79 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollindicator-handle@2x.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollindicator-handle@3x.pngbin0 -> 81 bytes
-rw-r--r--src/quickcontrols2/imagine/images/scrollindicator-handle@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-horizontal.9.pngbin0 -> 167 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-horizontal@2x.9.pngbin0 -> 243 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-horizontal@3x.9.pngbin0 -> 332 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-horizontal@4x.9.pngbin0 -> 444 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-vertical.9.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-vertical@2x.9.pngbin0 -> 252 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-vertical@3x.9.pngbin0 -> 328 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-background-vertical@4x.9.pngbin0 -> 464 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-disabled.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-disabled@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-disabled@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-disabled@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-hovered.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-hovered@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-hovered@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-hovered@4x.pngbin0 -> 990 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-pressed.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-pressed@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-pressed@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused-pressed@4x.pngbin0 -> 990 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused@2x.pngbin0 -> 519 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused@3x.pngbin0 -> 765 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-focused@4x.pngbin0 -> 998 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-hovered.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-hovered@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-hovered@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-hovered@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-pressed.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-pressed@2x.pngbin0 -> 484 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-pressed@3x.pngbin0 -> 726 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle-pressed@4x.pngbin0 -> 965 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle.pngbin0 -> 255 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle@2x.pngbin0 -> 487 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle@3x.pngbin0 -> 728 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-handle@4x.pngbin0 -> 976 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled.9.pngbin0 -> 144 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@2x.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@3x.9.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@4x.9.pngbin0 -> 273 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal.9.pngbin0 -> 144 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal@2x.9.pngbin0 -> 185 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal@3x.9.pngbin0 -> 228 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-horizontal@4x.9.pngbin0 -> 273 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical-disabled.9.pngbin0 -> 143 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@2x.9.pngbin0 -> 188 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@3x.9.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@4x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical.9.pngbin0 -> 143 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical@2x.9.pngbin0 -> 188 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical@3x.9.pngbin0 -> 227 bytes
-rw-r--r--src/quickcontrols2/imagine/images/slider-progress-vertical@4x.9.pngbin0 -> 279 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-disabled.9.pngbin0 -> 198 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-disabled@2x.9.pngbin0 -> 277 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-disabled@3x.9.pngbin0 -> 443 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-disabled@4x.9.pngbin0 -> 583 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-editable.9.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-editable@2x.9.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-editable@3x.9.pngbin0 -> 533 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-editable@4x.9.pngbin0 -> 784 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-focused.9.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-focused@2x.9.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-focused@3x.9.pngbin0 -> 533 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background-focused@4x.9.pngbin0 -> 784 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background.9.pngbin0 -> 214 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background@2x.9.pngbin0 -> 337 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background@3x.9.pngbin0 -> 539 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-background@4x.9.pngbin0 -> 767 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-focused.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@2x.9.pngbin0 -> 186 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@3x.9.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@4x.9.pngbin0 -> 261 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down@2x.9.pngbin0 -> 184 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down@3x.9.pngbin0 -> 225 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-down@4x.9.pngbin0 -> 256 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-focused.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored.9.pngbin0 -> 157 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@2x.9.pngbin0 -> 189 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@3x.9.pngbin0 -> 232 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@4x.9.pngbin0 -> 265 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up.9.pngbin0 -> 160 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up@2x.9.pngbin0 -> 191 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up@3x.9.pngbin0 -> 235 bytes
-rw-r--r--src/quickcontrols2/imagine/images/spinbox-indicator-up@4x.9.pngbin0 -> 269 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-disabled.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-disabled@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-disabled@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-disabled@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-hovered.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-hovered@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-hovered@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-hovered@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-pressed.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-pressed@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-pressed@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle-pressed@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle.pngbin0 -> 80 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/splitview-handle@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-disabled.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-focused.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-highlighted.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-hovered.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-hovered@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-hovered@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-hovered@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-pressed.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/swipedelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-disabled.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-disabled@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-disabled@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-disabled@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-pressed.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-pressed@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-pressed@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle-pressed@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-handle@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-focused.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-focused@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-focused@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-focused@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-hovered.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-pressed.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-checked@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-disabled.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-disabled@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-disabled@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-disabled@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-focused.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-focused@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-focused@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-focused@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-hovered.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-hovered@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-hovered@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-hovered@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-pressed.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-pressed@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator-pressed@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switch-indicator@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-disabled.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-focused.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-hovered.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-hovered@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-hovered@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-hovered@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-pressed.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background.9.pngbin0 -> 120 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-disabled.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-pressed.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle@2x.pngbin0 -> 368 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle@3x.pngbin0 -> 517 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-handle@4x.pngbin0 -> 699 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-focused.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator@2x.pngbin0 -> 423 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator@3x.pngbin0 -> 650 bytes
-rw-r--r--src/quickcontrols2/imagine/images/switchdelegate-indicator@4x.pngbin0 -> 834 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbar-background.pngbin0 -> 74 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbar-background@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbar-background@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbar-background@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-checked.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-checked@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-checked@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-checked@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-disabled@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-hovered.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-hovered@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-hovered@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-hovered@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-pressed.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-pressed@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-pressed@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background-pressed@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background@2x.9.pngbin0 -> 137 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background@3x.9.pngbin0 -> 153 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tabbutton-background@4x.9.pngbin0 -> 169 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-disabled.9.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-disabled@2x.9.pngbin0 -> 242 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-disabled@3x.9.pngbin0 -> 312 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-disabled@4x.9.pngbin0 -> 390 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-focused.9.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-focused@2x.9.pngbin0 -> 285 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-focused@3x.9.pngbin0 -> 383 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background-focused@4x.9.pngbin0 -> 503 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background.9.pngbin0 -> 196 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background@2x.9.pngbin0 -> 285 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background@3x.9.pngbin0 -> 383 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textarea-background@4x.9.pngbin0 -> 503 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-disabled.9.pngbin0 -> 188 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-disabled@2x.9.pngbin0 -> 273 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-disabled@3x.9.pngbin0 -> 355 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-disabled@4x.9.pngbin0 -> 533 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-focused.9.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-focused@2x.9.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-focused@3x.9.pngbin0 -> 495 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background-focused@4x.9.pngbin0 -> 712 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background.9.pngbin0 -> 205 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background@2x.9.pngbin0 -> 314 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background@3x.9.pngbin0 -> 495 bytes
-rw-r--r--src/quickcontrols2/imagine/images/textfield-background@4x.9.pngbin0 -> 712 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbar-background.pngbin0 -> 76 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbar-background@2x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbar-background@3x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbar-background@4x.pngbin0 -> 83 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-focused.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-checked@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-focused.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-focused@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-focused@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-focused@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-hovered.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-hovered@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-hovered@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-hovered@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-pressed.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-pressed@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-pressed@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background-pressed@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background.9.pngbin0 -> 122 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background@2x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background@3x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolbutton-background@4x.9.pngbin0 -> 149 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-horizontal.9.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@2x.9.pngbin0 -> 135 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@3x.9.pngbin0 -> 141 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@4x.9.pngbin0 -> 151 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-vertical.9.pngbin0 -> 128 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-vertical@2x.9.pngbin0 -> 133 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-vertical@3x.9.pngbin0 -> 138 bytes
-rw-r--r--src/quickcontrols2/imagine/images/toolseparator-separator-vertical@4x.9.pngbin0 -> 150 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tooltip-background.9.pngbin0 -> 195 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tooltip-background@2x.9.pngbin0 -> 264 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tooltip-background@3x.9.pngbin0 -> 346 bytes
-rw-r--r--src/quickcontrols2/imagine/images/tooltip-background@4x.9.pngbin0 -> 415 bytes
-rw-r--r--src/quickcontrols2/imagine/imagine.pri59
-rw-r--r--src/quickcontrols2/imagine/impl/CMakeLists.txt44
-rw-r--r--src/quickcontrols2/imagine/impl/OpacityMask.qml68
-rw-r--r--src/quickcontrols2/imagine/impl/qquickimageselector.cpp338
-rw-r--r--src/quickcontrols2/imagine/impl/qquickimageselector_p.h157
-rw-r--r--src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp513
-rw-r--r--src/quickcontrols2/imagine/impl/qquickninepatchimage_p.h108
-rw-r--r--src/quickcontrols2/imagine/impl/shaders/+glslcore/OpacityMask.frag13
-rw-r--r--src/quickcontrols2/imagine/impl/shaders/+qsb/OpacityMask.fragbin0 -> 1409 bytes
-rw-r--r--src/quickcontrols2/imagine/impl/shaders/OpacityMask.frag7
-rw-r--r--src/quickcontrols2/imagine/impl/shaders/OpacityMask_rhi.frag17
-rw-r--r--src/quickcontrols2/imagine/impl/shaders/compile.bat40
-rw-r--r--src/quickcontrols2/imagine/qquickimaginestyle.cpp170
-rw-r--r--src/quickcontrols2/imagine/qquickimaginestyle_p.h97
-rw-r--r--src/quickcontrols2/imagine/qquickimaginetheme.cpp66
-rw-r--r--src/quickcontrols2/imagine/qquickimaginetheme_p.h65
-rw-r--r--src/quickcontrols2/imagine/qtquickcontrols2imaginestyleplugin.cpp82
-rw-r--r--src/quickcontrols2/macos/Button.qml45
-rw-r--r--src/quickcontrols2/macos/CMakeLists.txt55
-rw-r--r--src/quickcontrols2/macos/CheckBox.qml46
-rw-r--r--src/quickcontrols2/macos/ComboBox.qml66
-rw-r--r--src/quickcontrols2/macos/Dial.qml43
-rw-r--r--src/quickcontrols2/macos/Frame.qml41
-rw-r--r--src/quickcontrols2/macos/GroupBox.qml61
-rw-r--r--src/quickcontrols2/macos/ProgressBar.qml43
-rw-r--r--src/quickcontrols2/macos/RadioButton.qml45
-rw-r--r--src/quickcontrols2/macos/ScrollBar.qml65
-rw-r--r--src/quickcontrols2/macos/ScrollView.qml75
-rw-r--r--src/quickcontrols2/macos/SelectionRectangle.qml62
-rw-r--r--src/quickcontrols2/macos/Slider.qml69
-rw-r--r--src/quickcontrols2/macos/SpinBox.qml126
-rw-r--r--src/quickcontrols2/macos/TextArea.qml41
-rw-r--r--src/quickcontrols2/macos/TextField.qml44
-rw-r--r--src/quickcontrols2/macos/macos.pri16
-rw-r--r--src/quickcontrols2/macos/qtquickcontrols2macosstyleplugin.cpp76
-rw-r--r--src/quickcontrols2/material/ApplicationWindow.qml46
-rw-r--r--src/quickcontrols2/material/BusyIndicator.qml61
-rw-r--r--src/quickcontrols2/material/Button.qml118
-rw-r--r--src/quickcontrols2/material/CMakeLists.txt152
-rw-r--r--src/quickcontrols2/material/CheckBox.qml83
-rw-r--r--src/quickcontrols2/material/CheckDelegate.qml97
-rw-r--r--src/quickcontrols2/material/ComboBox.qml179
-rw-r--r--src/quickcontrols2/material/DelayButton.qml116
-rw-r--r--src/quickcontrols2/material/Dial.qml85
-rw-r--r--src/quickcontrols2/material/Dialog.qml112
-rw-r--r--src/quickcontrols2/material/DialogButtonBox.qml79
-rw-r--r--src/quickcontrols2/material/Drawer.qml91
-rw-r--r--src/quickcontrols2/material/Frame.qml63
-rw-r--r--src/quickcontrols2/material/GroupBox.qml81
-rw-r--r--src/quickcontrols2/material/HorizontalHeaderView.qml68
-rw-r--r--src/quickcontrols2/material/ItemDelegate.qml88
-rw-r--r--src/quickcontrols2/material/LICENSE_ANGULARJS.txt19
-rw-r--r--src/quickcontrols2/material/Label.qml46
-rw-r--r--src/quickcontrols2/material/Menu.qml107
-rw-r--r--src/quickcontrols2/material/MenuBar.qml64
-rw-r--r--src/quickcontrols2/material/MenuBarItem.qml88
-rw-r--r--src/quickcontrols2/material/MenuItem.qml111
-rw-r--r--src/quickcontrols2/material/MenuSeparator.qml56
-rw-r--r--src/quickcontrols2/material/Page.qml56
-rw-r--r--src/quickcontrols2/material/PageIndicator.qml77
-rw-r--r--src/quickcontrols2/material/Pane.qml61
-rw-r--r--src/quickcontrols2/material/Popup.qml85
-rw-r--r--src/quickcontrols2/material/ProgressBar.qml67
-rw-r--r--src/quickcontrols2/material/RadioButton.qml83
-rw-r--r--src/quickcontrols2/material/RadioDelegate.qml97
-rw-r--r--src/quickcontrols2/material/RangeSlider.qml92
-rw-r--r--src/quickcontrols2/material/RoundButton.qml114
-rw-r--r--src/quickcontrols2/material/ScrollBar.qml89
-rw-r--r--src/quickcontrols2/material/ScrollIndicator.qml75
-rw-r--r--src/quickcontrols2/material/ScrollView.qml64
-rw-r--r--src/quickcontrols2/material/SelectionRectangle.qml66
-rw-r--r--src/quickcontrols2/material/Slider.qml81
-rw-r--r--src/quickcontrols2/material/SpinBox.qml156
-rw-r--r--src/quickcontrols2/material/SplitView.qml73
-rw-r--r--src/quickcontrols2/material/StackView.qml79
-rw-r--r--src/quickcontrols2/material/SwipeDelegate.qml98
-rw-r--r--src/quickcontrols2/material/SwipeView.qml66
-rw-r--r--src/quickcontrols2/material/Switch.qml79
-rw-r--r--src/quickcontrols2/material/SwitchDelegate.qml97
-rw-r--r--src/quickcontrols2/material/TabBar.qml89
-rw-r--r--src/quickcontrols2/material/TabButton.qml78
-rw-r--r--src/quickcontrols2/material/TextArea.qml83
-rw-r--r--src/quickcontrols2/material/TextField.qml85
-rw-r--r--src/quickcontrols2/material/ToolBar.qml66
-rw-r--r--src/quickcontrols2/material/ToolButton.qml86
-rw-r--r--src/quickcontrols2/material/ToolSeparator.qml57
-rw-r--r--src/quickcontrols2/material/ToolTip.qml83
-rw-r--r--src/quickcontrols2/material/Tumbler.qml78
-rw-r--r--src/quickcontrols2/material/VerticalHeaderView.qml68
-rw-r--r--src/quickcontrols2/material/images/arrow-indicator.pngbin0 -> 126 bytes
-rw-r--r--src/quickcontrols2/material/images/arrow-indicator.svg56
-rw-r--r--src/quickcontrols2/material/images/arrow-indicator@2x.pngbin0 -> 152 bytes
-rw-r--r--src/quickcontrols2/material/images/arrow-indicator@3x.pngbin0 -> 174 bytes
-rw-r--r--src/quickcontrols2/material/images/arrow-indicator@4x.pngbin0 -> 172 bytes
-rw-r--r--src/quickcontrols2/material/images/check.pngbin0 -> 631 bytes
-rw-r--r--src/quickcontrols2/material/images/check@2x.pngbin0 -> 1273 bytes
-rw-r--r--src/quickcontrols2/material/images/check@3x.pngbin0 -> 1829 bytes
-rw-r--r--src/quickcontrols2/material/images/check@4x.pngbin0 -> 2241 bytes
-rw-r--r--src/quickcontrols2/material/images/drop-indicator.pngbin0 -> 125 bytes
-rw-r--r--src/quickcontrols2/material/images/drop-indicator.svg5
-rw-r--r--src/quickcontrols2/material/images/drop-indicator@2x.pngbin0 -> 158 bytes
-rw-r--r--src/quickcontrols2/material/images/drop-indicator@3x.pngbin0 -> 180 bytes
-rw-r--r--src/quickcontrols2/material/images/drop-indicator@4x.pngbin0 -> 202 bytes
-rw-r--r--src/quickcontrols2/material/impl/BoxShadow.qml72
-rw-r--r--src/quickcontrols2/material/impl/CMakeLists.txt41
-rw-r--r--src/quickcontrols2/material/impl/CheckIndicator.qml120
-rw-r--r--src/quickcontrols2/material/impl/CursorDelegate.qml65
-rw-r--r--src/quickcontrols2/material/impl/ElevationEffect.qml279
-rw-r--r--src/quickcontrols2/material/impl/RadioIndicator.qml63
-rw-r--r--src/quickcontrols2/material/impl/RectangularGlow.qml240
-rw-r--r--src/quickcontrols2/material/impl/SliderHandle.qml76
-rw-r--r--src/quickcontrols2/material/impl/SwitchIndicator.qml82
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialbusyindicator.cpp247
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialbusyindicator_p.h88
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialprogressbar.cpp247
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialprogressbar_p.h91
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialripple.cpp444
-rw-r--r--src/quickcontrols2/material/impl/qquickmaterialripple_p.h120
-rw-r--r--src/quickcontrols2/material/material.pri61
-rw-r--r--src/quickcontrols2/material/qquickmaterialstyle.cpp1397
-rw-r--r--src/quickcontrols2/material/qquickmaterialstyle_p.h336
-rw-r--r--src/quickcontrols2/material/qquickmaterialtheme.cpp113
-rw-r--r--src/quickcontrols2/material/qquickmaterialtheme_p.h65
-rw-r--r--src/quickcontrols2/material/qt_attribution.json13
-rw-r--r--src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.cpp82
-rw-r--r--src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.qrc20
-rw-r--r--src/quickcontrols2/material/shaders/+glslcore/RectangularGlow.frag25
-rw-r--r--src/quickcontrols2/material/shaders/+hlsl/RectangularGlow.frag21
-rw-r--r--src/quickcontrols2/material/shaders/+qsb/RectangularGlow.fragbin0 -> 2007 bytes
-rw-r--r--src/quickcontrols2/material/shaders/RectangularGlow.frag19
-rw-r--r--src/quickcontrols2/material/shaders/RectangularGlow_rhi.frag28
-rw-r--r--src/quickcontrols2/material/shaders/compile.bat40
-rw-r--r--src/quickcontrols2/qquickstyle.cpp501
-rw-r--r--src/quickcontrols2/qquickstyle.h56
-rw-r--r--src/quickcontrols2/qquickstyle_p.h80
-rw-r--r--src/quickcontrols2/qquickstyleplugin.cpp153
-rw-r--r--src/quickcontrols2/qquickstyleplugin_p.h80
-rw-r--r--src/quickcontrols2/qt_cmdline.cmake6
-rw-r--r--src/quickcontrols2/qtquickcontrols2global.h58
-rw-r--r--src/quickcontrols2/qtquickcontrols2plugin.cpp173
-rw-r--r--src/quickcontrols2/universal/ApplicationWindow.qml54
-rw-r--r--src/quickcontrols2/universal/BusyIndicator.qml60
-rw-r--r--src/quickcontrols2/universal/Button.qml89
-rw-r--r--src/quickcontrols2/universal/CMakeLists.txt151
-rw-r--r--src/quickcontrols2/universal/CheckBox.qml74
-rw-r--r--src/quickcontrols2/universal/CheckDelegate.qml96
-rw-r--r--src/quickcontrols2/universal/ComboBox.qml158
-rw-r--r--src/quickcontrols2/universal/DelayButton.qml94
-rw-r--r--src/quickcontrols2/universal/Dial.qml86
-rw-r--r--src/quickcontrols2/universal/Dialog.qml90
-rw-r--r--src/quickcontrols2/universal/DialogButtonBox.qml76
-rw-r--r--src/quickcontrols2/universal/Drawer.qml78
-rw-r--r--src/quickcontrols2/universal/Frame.qml55
-rw-r--r--src/quickcontrols2/universal/GroupBox.qml75
-rw-r--r--src/quickcontrols2/universal/HorizontalHeaderView.qml69
-rw-r--r--src/quickcontrols2/universal/ItemDelegate.qml86
-rw-r--r--src/quickcontrols2/universal/Label.qml47
-rw-r--r--src/quickcontrols2/universal/Menu.qml82
-rw-r--r--src/quickcontrols2/universal/MenuBar.qml63
-rw-r--r--src/quickcontrols2/universal/MenuBarItem.qml90
-rw-r--r--src/quickcontrols2/universal/MenuItem.qml114
-rw-r--r--src/quickcontrols2/universal/MenuSeparator.qml62
-rw-r--r--src/quickcontrols2/universal/Page.qml56
-rw-r--r--src/quickcontrols2/universal/PageIndicator.qml71
-rw-r--r--src/quickcontrols2/universal/Pane.qml54
-rw-r--r--src/quickcontrols2/universal/Popup.qml64
-rw-r--r--src/quickcontrols2/universal/ProgressBar.qml68
-rw-r--r--src/quickcontrols2/universal/README.md9
-rw-r--r--src/quickcontrols2/universal/RadioButton.qml74
-rw-r--r--src/quickcontrols2/universal/RadioDelegate.qml96
-rw-r--r--src/quickcontrols2/universal/RangeSlider.qml109
-rw-r--r--src/quickcontrols2/universal/RoundButton.qml90
-rw-r--r--src/quickcontrols2/universal/ScrollBar.qml94
-rw-r--r--src/quickcontrols2/universal/ScrollIndicator.qml78
-rw-r--r--src/quickcontrols2/universal/ScrollView.qml64
-rw-r--r--src/quickcontrols2/universal/SelectionRectangle.qml70
-rw-r--r--src/quickcontrols2/universal/Slider.qml96
-rw-r--r--src/quickcontrols2/universal/SpinBox.qml147
-rw-r--r--src/quickcontrols2/universal/SplitView.qml55
-rw-r--r--src/quickcontrols2/universal/StackView.qml76
-rw-r--r--src/quickcontrols2/universal/SwipeDelegate.qml92
-rw-r--r--src/quickcontrols2/universal/Switch.qml74
-rw-r--r--src/quickcontrols2/universal/SwitchDelegate.qml96
-rw-r--r--src/quickcontrols2/universal/TabBar.qml70
-rw-r--r--src/quickcontrols2/universal/TabButton.qml69
-rw-r--r--src/quickcontrols2/universal/TextArea.qml93
-rw-r--r--src/quickcontrols2/universal/TextField.qml93
-rw-r--r--src/quickcontrols2/universal/ToolBar.qml53
-rw-r--r--src/quickcontrols2/universal/ToolButton.qml83
-rw-r--r--src/quickcontrols2/universal/ToolSeparator.qml59
-rw-r--r--src/quickcontrols2/universal/ToolTip.qml72
-rw-r--r--src/quickcontrols2/universal/Tumbler.qml78
-rw-r--r--src/quickcontrols2/universal/VerticalHeaderView.qml69
-rw-r--r--src/quickcontrols2/universal/images/checkmark.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols2/universal/images/checkmark@2x.pngbin0 -> 346 bytes
-rw-r--r--src/quickcontrols2/universal/images/checkmark@3x.pngbin0 -> 796 bytes
-rw-r--r--src/quickcontrols2/universal/images/checkmark@4x.pngbin0 -> 613 bytes
-rw-r--r--src/quickcontrols2/universal/images/downarrow.pngbin0 -> 175 bytes
-rw-r--r--src/quickcontrols2/universal/images/downarrow@2x.pngbin0 -> 267 bytes
-rw-r--r--src/quickcontrols2/universal/images/downarrow@3x.pngbin0 -> 329 bytes
-rw-r--r--src/quickcontrols2/universal/images/downarrow@4x.pngbin0 -> 365 bytes
-rw-r--r--src/quickcontrols2/universal/images/leftarrow.pngbin0 -> 158 bytes
-rw-r--r--src/quickcontrols2/universal/images/leftarrow@2x.pngbin0 -> 222 bytes
-rw-r--r--src/quickcontrols2/universal/images/leftarrow@3x.pngbin0 -> 283 bytes
-rw-r--r--src/quickcontrols2/universal/images/leftarrow@4x.pngbin0 -> 315 bytes
-rw-r--r--src/quickcontrols2/universal/images/rightarrow.pngbin0 -> 152 bytes
-rw-r--r--src/quickcontrols2/universal/images/rightarrow@2x.pngbin0 -> 226 bytes
-rw-r--r--src/quickcontrols2/universal/images/rightarrow@3x.pngbin0 -> 258 bytes
-rw-r--r--src/quickcontrols2/universal/images/rightarrow@4x.pngbin0 -> 338 bytes
-rw-r--r--src/quickcontrols2/universal/impl/CMakeLists.txt36
-rw-r--r--src/quickcontrols2/universal/impl/CheckIndicator.qml81
-rw-r--r--src/quickcontrols2/universal/impl/RadioIndicator.qml80
-rw-r--r--src/quickcontrols2/universal/impl/SwitchIndicator.qml81
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalbusyindicator.cpp253
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalbusyindicator_p.h89
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle.cpp86
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle_p.h69
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalprogressbar.cpp340
-rw-r--r--src/quickcontrols2/universal/impl/qquickuniversalprogressbar_p.h91
-rw-r--r--src/quickcontrols2/universal/qquickuniversalstyle.cpp620
-rw-r--r--src/quickcontrols2/universal/qquickuniversalstyle_p.h246
-rw-r--r--src/quickcontrols2/universal/qquickuniversaltheme.cpp70
-rw-r--r--src/quickcontrols2/universal/qquickuniversaltheme_p.h65
-rw-r--r--src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.cpp81
-rw-r--r--src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.qrc20
-rw-r--r--src/quickcontrols2/universal/universal.pri60
-rw-r--r--src/quickcontrols2/windows/Button.qml76
-rw-r--r--src/quickcontrols2/windows/CMakeLists.txt53
-rw-r--r--src/quickcontrols2/windows/CheckBox.qml107
-rw-r--r--src/quickcontrols2/windows/ComboBox.qml128
-rw-r--r--src/quickcontrols2/windows/Frame.qml41
-rw-r--r--src/quickcontrols2/windows/GroupBox.qml41
-rw-r--r--src/quickcontrols2/windows/ProgressBar.qml41
-rw-r--r--src/quickcontrols2/windows/RadioButton.qml41
-rw-r--r--src/quickcontrols2/windows/ScrollBar.qml128
-rw-r--r--src/quickcontrols2/windows/ScrollView.qml67
-rw-r--r--src/quickcontrols2/windows/SelectionRectangle.qml62
-rw-r--r--src/quickcontrols2/windows/Slider.qml41
-rw-r--r--src/quickcontrols2/windows/SpinBox.qml121
-rw-r--r--src/quickcontrols2/windows/TextArea.qml41
-rw-r--r--src/quickcontrols2/windows/TextField.qml41
-rw-r--r--src/quickcontrols2/windows/qtquickcontrols2windowsstyleplugin.cpp75
-rw-r--r--src/quickcontrols2/windows/windows.pri15
-rw-r--r--src/quickcontrols2impl/CMakeLists.txt47
-rw-r--r--src/quickcontrols2impl/qquickanimatednode.cpp169
-rw-r--r--src/quickcontrols2impl/qquickanimatednode_p.h112
-rw-r--r--src/quickcontrols2impl/qquickattachedobject.cpp276
-rw-r--r--src/quickcontrols2impl/qquickattachedobject_p.h84
-rw-r--r--src/quickcontrols2impl/qquickchecklabel.cpp51
-rw-r--r--src/quickcontrols2impl/qquickchecklabel_p.h78
-rw-r--r--src/quickcontrols2impl/qquickclippedtext.cpp118
-rw-r--r--src/quickcontrols2impl/qquickclippedtext_p.h98
-rw-r--r--src/quickcontrols2impl/qquickcolor.cpp68
-rw-r--r--src/quickcontrols2impl/qquickcolor_p.h74
-rw-r--r--src/quickcontrols2impl/qquickcolorimage.cpp105
-rw-r--r--src/quickcontrols2impl/qquickcolorimage_p.h90
-rw-r--r--src/quickcontrols2impl/qquickiconimage.cpp222
-rw-r--r--src/quickcontrols2impl/qquickiconimage_p.h96
-rw-r--r--src/quickcontrols2impl/qquickiconimage_p_p.h78
-rw-r--r--src/quickcontrols2impl/qquickiconlabel.cpp645
-rw-r--r--src/quickcontrols2impl/qquickiconlabel_p.h142
-rw-r--r--src/quickcontrols2impl/qquickiconlabel_p_p.h111
-rw-r--r--src/quickcontrols2impl/qquickitemgroup.cpp124
-rw-r--r--src/quickcontrols2impl/qquickitemgroup_p.h85
-rw-r--r--src/quickcontrols2impl/qquickmnemoniclabel.cpp134
-rw-r--r--src/quickcontrols2impl/qquickmnemoniclabel_p.h84
-rw-r--r--src/quickcontrols2impl/qquickpaddedrectangle.cpp213
-rw-r--r--src/quickcontrols2impl/qquickpaddedrectangle_p.h121
-rw-r--r--src/quickcontrols2impl/qquickplaceholdertext.cpp75
-rw-r--r--src/quickcontrols2impl/qquickplaceholdertext_p.h76
-rw-r--r--src/quickcontrols2impl/qquicktumblerview.cpp320
-rw-r--r--src/quickcontrols2impl/qquicktumblerview_p.h111
-rw-r--r--src/quickcontrols2impl/qtquickcontrols2foreign_p.h94
-rw-r--r--src/quickcontrols2impl/qtquickcontrols2implglobal_p.h65
-rw-r--r--src/quickcontrolstestutils/CMakeLists.txt25
-rw-r--r--src/quickcontrolstestutils/controlstestutils.cpp182
-rw-r--r--src/quickcontrolstestutils/controlstestutils_p.h85
-rw-r--r--src/quickcontrolstestutils/dialogstestutils.cpp144
-rw-r--r--src/quickcontrolstestutils/dialogstestutils_p.h187
-rw-r--r--src/quickcontrolstestutils/qtest_quickcontrols_p.h101
-rw-r--r--src/quickdialogs2/CMakeLists.txt3
-rw-r--r--src/quickdialogs2/quickdialogs2/CMakeLists.txt44
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-filedialog-gtk.pngbin0 -> 39560 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-fontdialog-gtk.pngbin0 -> 32399 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/qtquickdialogs.qdocconf40
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/src/includes/fallback.qdocinc1
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-index.qdoc68
-rw-r--r--src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-qmltypes.qdoc46
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickabstractdialog.cpp458
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickabstractdialog_p.h161
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickfiledialog.cpp622
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickfiledialog_p.h165
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickfontdialog.cpp229
-rw-r--r--src/quickdialogs2/quickdialogs2/qquickfontdialog_p.h101
-rw-r--r--src/quickdialogs2/quickdialogs2/qtquickdialogs2foreign_p.h75
-rw-r--r--src/quickdialogs2/quickdialogs2/qtquickdialogs2global_p.h68
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/CMakeLists.txt146
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.pngbin0 -> 119 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.svg136
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@2x.pngbin0 -> 268 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@3x.pngbin0 -> 360 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@4x.pngbin0 -> 422 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.pngbin0 -> 135 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.svg134
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@2x.pngbin0 -> 160 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@3x.pngbin0 -> 179 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@4x.pngbin0 -> 196 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.pngbin0 -> 238 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.svg117
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@2x.pngbin0 -> 396 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@3x.pngbin0 -> 546 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@4x.pngbin0 -> 698 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.pngbin0 -> 193 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.svg83
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@2x.pngbin0 -> 294 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@3x.pngbin0 -> 395 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@4x.pngbin0 -> 474 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.pngbin0 -> 205 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.svg93
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@2x.pngbin0 -> 306 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@3x.pngbin0 -> 431 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@4x.pngbin0 -> 574 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.pngbin0 -> 165 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.svg74
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@2x.pngbin0 -> 194 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@3x.pngbin0 -> 241 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@4x.pngbin0 -> 256 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled.9.pngbin0 -> 114 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused.9.pngbin0 -> 114 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted.9.pngbin0 -> 114 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed.9.pngbin0 -> 114 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.9.pngbin0 -> 113 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.svg358
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@2x.9.pngbin0 -> 123 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@3x.9.pngbin0 -> 127 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@4x.9.pngbin0 -> 132 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.pngbin0 -> 281 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.svg86
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@2x.pngbin0 -> 355 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@3x.pngbin0 -> 453 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@4x.pngbin0 -> 569 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.pngbin0 -> 171 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.svg79
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@2x.pngbin0 -> 212 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@3x.pngbin0 -> 251 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@4x.pngbin0 -> 274 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.pngbin0 -> 138 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.svg72
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@2x.pngbin0 -> 163 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@3x.pngbin0 -> 183 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@4x.pngbin0 -> 204 bytes
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialog.qml197
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialogDelegate.qml88
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FolderBreadcrumbBar.qml106
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FontDialog.qml151
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialog.qml191
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialogDelegate.qml100
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FolderBreadcrumbBar.qml90
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FontDialog.qml167
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialog.qml164
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialogDelegate.qml95
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FolderBreadcrumbBar.qml102
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FontDialog.qml142
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialog.qml166
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialogDelegate.qml93
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FolderBreadcrumbBar.qml100
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FontDialog.qml144
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialog.qml184
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegate.qml89
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegateLabel.qml98
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FolderBreadcrumbBar.qml101
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialog.qml148
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialogContent.qml267
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory.cpp84
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory_p.h67
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate.cpp163
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate_p.h93
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl.cpp574
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p.h168
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p_p.h109
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp794
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h126
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h113
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl.cpp865
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p.h217
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p_p.h104
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog.cpp228
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog_p.h91
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog.cpp176
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog_p.h86
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplforeign_p.h115
-rw-r--r--src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplglobal_p.h68
-rw-r--r--src/quickdialogs2/quickdialogs2utils/CMakeLists.txt23
-rw-r--r--src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter.cpp160
-rw-r--r--src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter_p.h102
-rw-r--r--src/quickdialogs2/quickdialogs2utils/qtquickdialogs2utilsglobal_p.h67
-rw-r--r--src/quicklayouts/qquickgridlayoutengine.cpp7
-rw-r--r--src/quicklayouts/qquickgridlayoutengine_p.h1
-rw-r--r--src/quicklayouts/qquicklayout.cpp26
-rw-r--r--src/quicklayouts/qquicklayout_p.h3
-rw-r--r--src/quicklayouts/qquicklinearlayout.cpp19
-rw-r--r--src/quicklayouts/qquickstacklayout.cpp40
-rw-r--r--src/quicklayouts/qquickstacklayout_p.h3
-rw-r--r--src/quicknativestyle/CMakeLists.txt100
-rw-r--r--src/quicknativestyle/controls/DefaultButton.qml78
-rw-r--r--src/quicknativestyle/controls/DefaultCheckBox.qml91
-rw-r--r--src/quicknativestyle/controls/DefaultComboBox.qml127
-rw-r--r--src/quicknativestyle/controls/DefaultDial.qml58
-rw-r--r--src/quicknativestyle/controls/DefaultFrame.qml62
-rw-r--r--src/quicknativestyle/controls/DefaultGroupBox.qml86
-rw-r--r--src/quicknativestyle/controls/DefaultProgressBar.qml58
-rw-r--r--src/quicknativestyle/controls/DefaultRadioButton.qml94
-rw-r--r--src/quicknativestyle/controls/DefaultScrollBar.qml65
-rw-r--r--src/quicknativestyle/controls/DefaultSlider.qml70
-rw-r--r--src/quicknativestyle/controls/DefaultSpinBox.qml107
-rw-r--r--src/quicknativestyle/controls/DefaultTextArea.qml82
-rw-r--r--src/quicknativestyle/controls/DefaultTextField.qml86
-rw-r--r--src/quicknativestyle/controls/controls.pri14
-rw-r--r--src/quicknativestyle/items/items.pri36
-rw-r--r--src/quicknativestyle/items/qquickstyleitem.cpp578
-rw-r--r--src/quicknativestyle/items/qquickstyleitem.h311
-rw-r--r--src/quicknativestyle/items/qquickstyleitembutton.cpp95
-rw-r--r--src/quicknativestyle/items/qquickstyleitembutton.h64
-rw-r--r--src/quicknativestyle/items/qquickstyleitemcheckbox.cpp95
-rw-r--r--src/quicknativestyle/items/qquickstyleitemcheckbox.h64
-rw-r--r--src/quicknativestyle/items/qquickstyleitemcombobox.cpp95
-rw-r--r--src/quicknativestyle/items/qquickstyleitemcombobox.h64
-rw-r--r--src/quicknativestyle/items/qquickstyleitemdial.cpp117
-rw-r--r--src/quicknativestyle/items/qquickstyleitemdial.h64
-rw-r--r--src/quicknativestyle/items/qquickstyleitemframe.cpp73
-rw-r--r--src/quicknativestyle/items/qquickstyleitemframe.h60
-rw-r--r--src/quicknativestyle/items/qquickstyleitemgroupbox.cpp106
-rw-r--r--src/quicknativestyle/items/qquickstyleitemgroupbox.h74
-rw-r--r--src/quicknativestyle/items/qquickstyleitemprogressbar.cpp120
-rw-r--r--src/quicknativestyle/items/qquickstyleitemprogressbar.h65
-rw-r--r--src/quicknativestyle/items/qquickstyleitemradiobutton.cpp89
-rw-r--r--src/quicknativestyle/items/qquickstyleitemradiobutton.h64
-rw-r--r--src/quicknativestyle/items/qquickstyleitemscrollbar.cpp157
-rw-r--r--src/quicknativestyle/items/qquickstyleitemscrollbar.h78
-rw-r--r--src/quicknativestyle/items/qquickstyleitemscrollviewcorner.cpp119
-rw-r--r--src/quicknativestyle/items/qquickstyleitemscrollviewcorner.h56
-rw-r--r--src/quicknativestyle/items/qquickstyleitemslider.cpp129
-rw-r--r--src/quicknativestyle/items/qquickstyleitemslider.h76
-rw-r--r--src/quicknativestyle/items/qquickstyleitemspinbox.cpp116
-rw-r--r--src/quicknativestyle/items/qquickstyleitemspinbox.h77
-rw-r--r--src/quicknativestyle/items/qquickstyleitemtextfield.cpp98
-rw-r--r--src/quicknativestyle/items/qquickstyleitemtextfield.h64
-rw-r--r--src/quicknativestyle/qstyle/mac/mac.pri12
-rw-r--r--src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm6063
-rw-r--r--src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p.h104
-rw-r--r--src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p_p.h230
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstyle.cpp6083
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstyle.h89
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstyle_p.h109
-rw-r--r--src/quicknativestyle/qstyle/qquickcommonstylepixmaps_p.h532
-rw-r--r--src/quicknativestyle/qstyle/qquickdrawutil.cpp1145
-rw-r--r--src/quicknativestyle/qstyle/qquickdrawutil.h170
-rw-r--r--src/quicknativestyle/qstyle/qquicknativestyle.cpp47
-rw-r--r--src/quicknativestyle/qstyle/qquicknativestyle.h69
-rw-r--r--src/quicknativestyle/qstyle/qquickstyle.cpp412
-rw-r--r--src/quicknativestyle/qstyle/qquickstyle.h839
-rw-r--r--src/quicknativestyle/qstyle/qquickstyle_p.h121
-rw-r--r--src/quicknativestyle/qstyle/qquickstylehelper.cpp439
-rw-r--r--src/quicknativestyle/qstyle/qquickstylehelper_p.h103
-rw-r--r--src/quicknativestyle/qstyle/qquickstyleoption.cpp652
-rw-r--r--src/quicknativestyle/qstyle/qquickstyleoption.h796
-rw-r--r--src/quicknativestyle/qstyle/qstyle.pri23
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp2388
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p.h111
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p_p.h122
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle.cpp2494
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p.h109
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p_p.h204
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp4147
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p.h102
-rw-r--r--src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p_p.h348
-rw-r--r--src/quicknativestyle/qstyle/windows/windows.pri18
-rw-r--r--src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp165
-rw-r--r--src/quicknativestyle/util/FocusFrame.qml115
-rw-r--r--src/quicknativestyle/util/qquickmacfocusframe.h73
-rw-r--r--src/quicknativestyle/util/qquickmacfocusframe.mm174
-rw-r--r--src/quicknativestyle/util/util.pri11
-rw-r--r--src/quickshapes/qquickshape.cpp8
-rw-r--r--src/quickshapes/qquickshapegenericrenderer.cpp14
-rw-r--r--src/quickshapes/qquickshapesoftwarerenderer.cpp6
-rw-r--r--src/quickshapes/qquickshapesplugin.cpp3
-rw-r--r--src/quicktemplates2/CMakeLists.txt169
-rw-r--r--src/quicktemplates2/accessible/accessible.pri4
-rw-r--r--src/quicktemplates2/accessible/qaccessiblequickpage.cpp81
-rw-r--r--src/quicktemplates2/accessible/qaccessiblequickpage_p.h70
-rw-r--r--src/quicktemplates2/configure.cmake30
-rw-r--r--src/quicktemplates2/doc/src/qtquicktemplates2-index.qdoc58
-rw-r--r--src/quicktemplates2/doc/src/qtquicktemplates2-qmltypes.qdoc64
-rw-r--r--src/quicktemplates2/qquickabstractbutton.cpp1220
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p.h225
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p_p.h153
-rw-r--r--src/quicktemplates2/qquickaction.cpp587
-rw-r--r--src/quicktemplates2/qquickaction_p.h130
-rw-r--r--src/quicktemplates2/qquickaction_p_p.h135
-rw-r--r--src/quicktemplates2/qquickactiongroup.cpp471
-rw-r--r--src/quicktemplates2/qquickactiongroup_p.h133
-rw-r--r--src/quicktemplates2/qquickapplicationwindow.cpp955
-rw-r--r--src/quicktemplates2/qquickapplicationwindow_p.h198
-rw-r--r--src/quicktemplates2/qquickbusyindicator.cpp132
-rw-r--r--src/quicktemplates2/qquickbusyindicator_p.h91
-rw-r--r--src/quicktemplates2/qquickbutton.cpp164
-rw-r--r--src/quicktemplates2/qquickbutton_p.h92
-rw-r--r--src/quicktemplates2/qquickbutton_p_p.h68
-rw-r--r--src/quicktemplates2/qquickbuttongroup.cpp546
-rw-r--r--src/quicktemplates2/qquickbuttongroup_p.h144
-rw-r--r--src/quicktemplates2/qquickcheckbox.cpp245
-rw-r--r--src/quicktemplates2/qquickcheckbox_p.h97
-rw-r--r--src/quicktemplates2/qquickcheckdelegate.cpp239
-rw-r--r--src/quicktemplates2/qquickcheckdelegate_p.h101
-rw-r--r--src/quicktemplates2/qquickcombobox.cpp2221
-rw-r--r--src/quicktemplates2/qquickcombobox_p.h272
-rw-r--r--src/quicktemplates2/qquickcontainer.cpp913
-rw-r--r--src/quicktemplates2/qquickcontainer_p.h141
-rw-r--r--src/quicktemplates2/qquickcontainer_p_p.h109
-rw-r--r--src/quicktemplates2/qquickcontentitem.cpp63
-rw-r--r--src/quicktemplates2/qquickcontentitem_p.h70
-rw-r--r--src/quicktemplates2/qquickcontrol.cpp2231
-rw-r--r--src/quicktemplates2/qquickcontrol_p.h320
-rw-r--r--src/quicktemplates2/qquickcontrol_p_p.h244
-rw-r--r--src/quicktemplates2/qquickdeferredexecute.cpp150
-rw-r--r--src/quicktemplates2/qquickdeferredexecute_p_p.h94
-rw-r--r--src/quicktemplates2/qquickdeferredpointer_p_p.h188
-rw-r--r--src/quicktemplates2/qquickdelaybutton.cpp266
-rw-r--r--src/quicktemplates2/qquickdelaybutton_p.h100
-rw-r--r--src/quicktemplates2/qquickdial.cpp861
-rw-r--r--src/quicktemplates2/qquickdial_p.h183
-rw-r--r--src/quicktemplates2/qquickdialog.cpp578
-rw-r--r--src/quicktemplates2/qquickdialog_p.h149
-rw-r--r--src/quicktemplates2/qquickdialog_p_p.h84
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox.cpp868
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox_p.h173
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox_p_p.h111
-rw-r--r--src/quicktemplates2/qquickdrawer.cpp822
-rw-r--r--src/quicktemplates2/qquickdrawer_p.h111
-rw-r--r--src/quicktemplates2/qquickdrawer_p_p.h101
-rw-r--r--src/quicktemplates2/qquickframe.cpp90
-rw-r--r--src/quicktemplates2/qquickframe_p.h82
-rw-r--r--src/quicktemplates2/qquickframe_p_p.h63
-rw-r--r--src/quicktemplates2/qquickgroupbox.cpp289
-rw-r--r--src/quicktemplates2/qquickgroupbox_p.h109
-rw-r--r--src/quicktemplates2/qquickheaderview.cpp524
-rw-r--r--src/quicktemplates2/qquickheaderview_p.h137
-rw-r--r--src/quicktemplates2/qquickheaderview_p_p.h136
-rw-r--r--src/quicktemplates2/qquickicon.cpp311
-rw-r--r--src/quicktemplates2/qquickicon_p.h120
-rw-r--r--src/quicktemplates2/qquickindicatorbutton_p.cpp159
-rw-r--r--src/quicktemplates2/qquickindicatorbutton_p.h121
-rw-r--r--src/quicktemplates2/qquickitemdelegate.cpp138
-rw-r--r--src/quicktemplates2/qquickitemdelegate_p.h92
-rw-r--r--src/quicktemplates2/qquickitemdelegate_p_p.h67
-rw-r--r--src/quicktemplates2/qquicklabel.cpp594
-rw-r--r--src/quicktemplates2/qquicklabel_p.h141
-rw-r--r--src/quicktemplates2/qquicklabel_p_p.h141
-rw-r--r--src/quicktemplates2/qquickmenu.cpp1533
-rw-r--r--src/quicktemplates2/qquickmenu_p.h163
-rw-r--r--src/quicktemplates2/qquickmenu_p_p.h144
-rw-r--r--src/quicktemplates2/qquickmenubar.cpp581
-rw-r--r--src/quicktemplates2/qquickmenubar_p.h109
-rw-r--r--src/quicktemplates2/qquickmenubar_p_p.h109
-rw-r--r--src/quicktemplates2/qquickmenubaritem.cpp187
-rw-r--r--src/quicktemplates2/qquickmenubaritem_p.h103
-rw-r--r--src/quicktemplates2/qquickmenubaritem_p_p.h80
-rw-r--r--src/quicktemplates2/qquickmenuitem.cpp281
-rw-r--r--src/quicktemplates2/qquickmenuitem_p.h109
-rw-r--r--src/quicktemplates2/qquickmenuitem_p_p.h88
-rw-r--r--src/quicktemplates2/qquickmenuseparator.cpp96
-rw-r--r--src/quicktemplates2/qquickmenuseparator_p.h82
-rw-r--r--src/quicktemplates2/qquickoverlay.cpp763
-rw-r--r--src/quicktemplates2/qquickoverlay_p.h147
-rw-r--r--src/quicktemplates2/qquickoverlay_p_p.h102
-rw-r--r--src/quicktemplates2/qquickpage.cpp498
-rw-r--r--src/quicktemplates2/qquickpage_p.h123
-rw-r--r--src/quicktemplates2/qquickpage_p_p.h79
-rw-r--r--src/quicktemplates2/qquickpageindicator.cpp354
-rw-r--r--src/quicktemplates2/qquickpageindicator_p.h109
-rw-r--r--src/quicktemplates2/qquickpane.cpp432
-rw-r--r--src/quicktemplates2/qquickpane_p.h107
-rw-r--r--src/quicktemplates2/qquickpane_p_p.h90
-rw-r--r--src/quicktemplates2/qquickpopup.cpp2799
-rw-r--r--src/quicktemplates2/qquickpopup_p.h478
-rw-r--r--src/quicktemplates2/qquickpopup_p_p.h219
-rw-r--r--src/quicktemplates2/qquickpopupanchors.cpp100
-rw-r--r--src/quicktemplates2/qquickpopupanchors_p.h91
-rw-r--r--src/quicktemplates2/qquickpopupanchors_p_p.h75
-rw-r--r--src/quicktemplates2/qquickpopupitem.cpp433
-rw-r--r--src/quicktemplates2/qquickpopupitem_p_p.h150
-rw-r--r--src/quicktemplates2/qquickpopuppositioner.cpp329
-rw-r--r--src/quicktemplates2/qquickpopuppositioner_p_p.h88
-rw-r--r--src/quicktemplates2/qquickpresshandler.cpp147
-rw-r--r--src/quicktemplates2/qquickpresshandler_p_p.h84
-rw-r--r--src/quicktemplates2/qquickprogressbar.cpp273
-rw-r--r--src/quicktemplates2/qquickprogressbar_p.h112
-rw-r--r--src/quicktemplates2/qquickradiobutton.cpp123
-rw-r--r--src/quicktemplates2/qquickradiobutton_p.h79
-rw-r--r--src/quicktemplates2/qquickradiodelegate.cpp124
-rw-r--r--src/quicktemplates2/qquickradiodelegate_p.h81
-rw-r--r--src/quicktemplates2/qquickrangeslider.cpp1344
-rw-r--r--src/quicktemplates2/qquickrangeslider_p.h229
-rw-r--r--src/quicktemplates2/qquickroundbutton.cpp137
-rw-r--r--src/quicktemplates2/qquickroundbutton_p.h86
-rw-r--r--src/quicktemplates2/qquickscrollbar.cpp1281
-rw-r--r--src/quicktemplates2/qquickscrollbar_p.h222
-rw-r--r--src/quicktemplates2/qquickscrollbar_p_p.h152
-rw-r--r--src/quicktemplates2/qquickscrollindicator.cpp667
-rw-r--r--src/quicktemplates2/qquickscrollindicator_p.h162
-rw-r--r--src/quicktemplates2/qquickscrollview.cpp623
-rw-r--r--src/quicktemplates2/qquickscrollview_p.h89
-rw-r--r--src/quicktemplates2/qquickselectionrectangle.cpp574
-rw-r--r--src/quicktemplates2/qquickselectionrectangle_p.h143
-rw-r--r--src/quicktemplates2/qquickselectionrectangle_p_p.h111
-rw-r--r--src/quicktemplates2/qquickshortcutcontext.cpp111
-rw-r--r--src/quicktemplates2/qquickshortcutcontext_p_p.h65
-rw-r--r--src/quicktemplates2/qquickslider.cpp895
-rw-r--r--src/quicktemplates2/qquickslider_p.h190
-rw-r--r--src/quicktemplates2/qquickspinbox.cpp1064
-rw-r--r--src/quicktemplates2/qquickspinbox_p.h183
-rw-r--r--src/quicktemplates2/qquicksplitview.cpp2141
-rw-r--r--src/quicktemplates2/qquicksplitview_p.h227
-rw-r--r--src/quicktemplates2/qquicksplitview_p_p.h183
-rw-r--r--src/quicktemplates2/qquickstackelement.cpp341
-rw-r--r--src/quicktemplates2/qquickstackelement_p_p.h108
-rw-r--r--src/quicktemplates2/qquickstacktransition.cpp150
-rw-r--r--src/quicktemplates2/qquickstacktransition_p_p.h79
-rw-r--r--src/quicktemplates2/qquickstackview.cpp1404
-rw-r--r--src/quicktemplates2/qquickstackview_p.cpp360
-rw-r--r--src/quicktemplates2/qquickstackview_p.h224
-rw-r--r--src/quicktemplates2/qquickstackview_p_p.h126
-rw-r--r--src/quicktemplates2/qquickswipe_p.h142
-rw-r--r--src/quicktemplates2/qquickswipedelegate.cpp1527
-rw-r--r--src/quicktemplates2/qquickswipedelegate_p.h126
-rw-r--r--src/quicktemplates2/qquickswipedelegate_p_p.h82
-rw-r--r--src/quicktemplates2/qquickswipeview.cpp478
-rw-r--r--src/quicktemplates2/qquickswipeview_p.h151
-rw-r--r--src/quicktemplates2/qquickswitch.cpp241
-rw-r--r--src/quicktemplates2/qquickswitch_p.h99
-rw-r--r--src/quicktemplates2/qquickswitchdelegate.cpp238
-rw-r--r--src/quicktemplates2/qquickswitchdelegate_p.h99
-rw-r--r--src/quicktemplates2/qquicktabbar.cpp508
-rw-r--r--src/quicktemplates2/qquicktabbar_p.h136
-rw-r--r--src/quicktemplates2/qquicktabbutton.cpp96
-rw-r--r--src/quicktemplates2/qquicktabbutton_p.h81
-rw-r--r--src/quicktemplates2/qquicktextarea.cpp1181
-rw-r--r--src/quicktemplates2/qquicktextarea_p.h223
-rw-r--r--src/quicktemplates2/qquicktextarea_p_p.h173
-rw-r--r--src/quicktemplates2/qquicktextfield.cpp953
-rw-r--r--src/quicktemplates2/qquicktextfield_p.h194
-rw-r--r--src/quicktemplates2/qquicktextfield_p_p.h160
-rw-r--r--src/quicktemplates2/qquicktheme.cpp177
-rw-r--r--src/quicktemplates2/qquicktheme_p.h104
-rw-r--r--src/quicktemplates2/qquicktheme_p_p.h75
-rw-r--r--src/quicktemplates2/qquicktoolbar.cpp158
-rw-r--r--src/quicktemplates2/qquicktoolbar_p.h95
-rw-r--r--src/quicktemplates2/qquicktoolbutton.cpp88
-rw-r--r--src/quicktemplates2/qquicktoolbutton_p.h77
-rw-r--r--src/quicktemplates2/qquicktoolseparator.cpp150
-rw-r--r--src/quicktemplates2/qquicktoolseparator_p.h94
-rw-r--r--src/quicktemplates2/qquicktooltip.cpp576
-rw-r--r--src/quicktemplates2/qquicktooltip_p.h156
-rw-r--r--src/quicktemplates2/qquicktumbler.cpp1047
-rw-r--r--src/quicktemplates2/qquicktumbler_p.h179
-rw-r--r--src/quicktemplates2/qquicktumbler_p_p.h155
-rw-r--r--src/quicktemplates2/qquickvelocitycalculator.cpp102
-rw-r--r--src/quicktemplates2/qquickvelocitycalculator_p_p.h76
-rw-r--r--src/quicktemplates2/qt_cmdline.cmake0
-rw-r--r--src/quicktemplates2/qtquicktemplates2global.cpp70
-rw-r--r--src/quicktemplates2/qtquicktemplates2global_p.h73
-rw-r--r--src/quicktemplates2/qtquicktemplates2plugin.cpp110
-rw-r--r--src/quicktemplates2/quicktemplates2.pri182
-rw-r--r--src/quicktestutils/CMakeLists.txt45
-rw-r--r--src/quicktestutils/qml/platforminputcontext_p.h123
-rw-r--r--src/quicktestutils/qml/platformquirks_p.h71
-rw-r--r--src/quicktestutils/qml/qmlutils.cpp123
-rw-r--r--src/quicktestutils/qml/qmlutils_p.h120
-rw-r--r--src/quicktestutils/qml/qqmljsastdumper.cpp1088
-rw-r--r--src/quicktestutils/qml/qqmljsastdumper_p.h449
-rw-r--r--src/quicktestutils/qml/testhttpserver.cpp468
-rw-r--r--src/quicktestutils/qml/testhttpserver_p.h143
-rw-r--r--src/quicktestutils/quick/geometrytestutils.cpp49
-rw-r--r--src/quicktestutils/quick/geometrytestutils_p.h64
-rw-r--r--src/quicktestutils/quick/viewtestutils.cpp535
-rw-r--r--src/quicktestutils/quick/viewtestutils_p.h216
-rw-r--r--src/quicktestutils/quick/visualtestutils.cpp228
-rw-r--r--src/quicktestutils/quick/visualtestutils_p.h220
-rw-r--r--src/quickwidgets/qquickwidget.cpp118
3320 files changed, 192286 insertions, 5619 deletions
diff --git a/src/3rdparty/masm/assembler/ARM64Assembler.h b/src/3rdparty/masm/assembler/ARM64Assembler.h
index 1431df50c8..9928da3abd 100644
--- a/src/3rdparty/masm/assembler/ARM64Assembler.h
+++ b/src/3rdparty/masm/assembler/ARM64Assembler.h
@@ -677,11 +677,11 @@ public:
struct RealTypes {
int64_t m_from : 48;
int64_t m_to : 48;
+ RegisterID m_compareRegister;
JumpType m_type : 8;
JumpLinkType m_linkType : 8;
Condition m_condition : 4;
unsigned m_bitNumber : 6;
- RegisterID m_compareRegister : 6;
bool m_is64Bit : 1;
} realTypes;
} data;
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index 1061021227..ab80e42e79 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -20,7 +20,7 @@
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef X86Assembler_h
@@ -164,7 +164,7 @@ private:
OP_HLT = 0xF4,
OP_GROUP3_EbIb = 0xF6,
OP_GROUP3_Ev = 0xF7,
- OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test.
+ OP_GROUP3_EvIz = 0xF7, // OP_GROUP3_Ev has an immediate, when instruction is a test.
OP_GROUP5_Ev = 0xFF,
} OneByteOpcodeID;
@@ -202,12 +202,12 @@ private:
TwoByteOpcodeID jccRel32(Condition cond)
{
- return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond);
+ return (TwoByteOpcodeID)(int(OP2_JCC_rel32) + cond);
}
TwoByteOpcodeID setccOpcode(Condition cond)
{
- return (TwoByteOpcodeID)(OP_SETCC + cond);
+ return (TwoByteOpcodeID)(int(OP_SETCC) + cond);
}
typedef enum {
@@ -220,12 +220,12 @@ private:
GROUP1_OP_CMP = 7,
GROUP1A_OP_POP = 0,
-
+
GROUP2_OP_ROL = 0,
GROUP2_OP_ROR = 1,
GROUP2_OP_RCL = 2,
GROUP2_OP_RCR = 3,
-
+
GROUP2_OP_SHL = 4,
GROUP2_OP_SHR = 5,
GROUP2_OP_SAR = 7,
@@ -246,7 +246,7 @@ private:
ESCAPE_DD_FSTP_doubleReal = 3,
} GroupOpcodeID;
-
+
class X86InstructionFormatter;
public:
@@ -308,7 +308,7 @@ public:
{
m_formatter.oneByteOp(OP_ADD_GvEv, dst, base, offset);
}
-
+
#if !CPU(X86_64)
void addl_mr(const void* addr, RegisterID dst)
{
@@ -577,7 +577,7 @@ public:
m_formatter.immediate32(imm);
}
}
-
+
void subl_im(int imm, int offset, RegisterID base)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
@@ -671,12 +671,12 @@ public:
m_formatter.immediate32(imm);
}
}
-
+
void xorq_rm(RegisterID src, int offset, RegisterID base)
{
m_formatter.oneByteOp64(OP_XOR_EvGv, src, base, offset);
}
-
+
void rorq_i8r(int imm, RegisterID dst)
{
if (imm == 1)
@@ -749,7 +749,7 @@ public:
{
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
}
-
+
void shrl_i8r(int imm, RegisterID dst)
{
if (imm == 1)
@@ -759,7 +759,7 @@ public:
m_formatter.immediate8(imm);
}
}
-
+
void shrl_CLr(RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHR, dst);
@@ -834,7 +834,7 @@ public:
m_formatter.oneByteOp(OP_GROUP1_EvIz, GROUP1_OP_CMP, dst);
m_formatter.immediate32(imm);
}
-
+
void cmpl_im(int imm, int offset, RegisterID base)
{
if (CAN_SIGN_EXTEND_8_32(imm)) {
@@ -845,19 +845,19 @@ public:
m_formatter.immediate32(imm);
}
}
-
+
void cmpb_im(int imm, int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, offset);
m_formatter.immediate8(imm);
}
-
+
void cmpb_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.oneByteOp(OP_GROUP1_EbIb, GROUP1_OP_CMP, base, index, scale, offset);
m_formatter.immediate8(imm);
}
-
+
#if CPU(X86)
void cmpb_im(int imm, const void* addr)
{
@@ -985,7 +985,7 @@ public:
{
m_formatter.oneByteOp(OP_TEST_EvGv, src, dst);
}
-
+
void testl_i32r(int imm, RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP3_EvIz, GROUP3_OP_TEST, dst);
@@ -1008,7 +1008,7 @@ public:
m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, offset);
m_formatter.immediate8(imm);
}
-
+
void testb_im(int imm, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.oneByteOp(OP_GROUP3_EbIb, GROUP3_OP_TEST, base, index, scale, offset);
@@ -1057,14 +1057,14 @@ public:
m_formatter.oneByteOp64(OP_GROUP3_EvIz, GROUP3_OP_TEST, base, index, scale, offset);
m_formatter.immediate32(imm);
}
-#endif
+#endif
void testw_rr(RegisterID src, RegisterID dst)
{
m_formatter.prefix(PRE_OPERAND_SIZE);
m_formatter.oneByteOp(OP_TEST_EvGv, src, dst);
}
-
+
void testb_i8r(int imm, RegisterID dst)
{
m_formatter.oneByteOp8(OP_GROUP3_EbIb, GROUP3_OP_TEST, dst);
@@ -1124,7 +1124,7 @@ public:
{
m_formatter.oneByteOp(OP_MOV_EvGv, src, dst);
}
-
+
void movl_rm(RegisterID src, int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_MOV_EvGv, src, base, offset);
@@ -1139,7 +1139,7 @@ public:
{
m_formatter.oneByteOp(OP_MOV_EvGv, src, base, index, scale, offset);
}
-
+
void movl_mEAX(const void* addr)
{
m_formatter.oneByteOp(OP_MOV_EAXOv);
@@ -1159,7 +1159,7 @@ public:
{
m_formatter.oneByteOp_disp32(OP_MOV_GvEv, dst, base, offset);
}
-
+
void movl_mr_disp8(int offset, RegisterID base, RegisterID dst)
{
m_formatter.oneByteOp_disp8(OP_MOV_GvEv, dst, base, offset);
@@ -1181,7 +1181,7 @@ public:
m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, offset);
m_formatter.immediate32(imm);
}
-
+
void movl_i32m(int imm, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.oneByteOp(OP_GROUP11_EvIz, GROUP11_MOV, base, index, scale, offset);
@@ -1210,12 +1210,12 @@ public:
m_formatter.oneByteOp(OP_GROUP11_EvIb, GROUP11_MOV, base, index, scale, offset);
m_formatter.immediate8(imm);
}
-
+
void movb_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.oneByteOp8(OP_MOV_EbGb, src, base, index, scale, offset);
}
-
+
void movw_rm(RegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.prefix(PRE_OPERAND_SIZE);
@@ -1296,22 +1296,22 @@ public:
m_formatter.oneByteOp64(OP_MOV_EAXIv, dst);
m_formatter.immediate64(imm);
}
-
+
void movsxd_rr(RegisterID src, RegisterID dst)
{
m_formatter.oneByteOp64(OP_MOVSXD_GvEv, dst, src);
}
-
-
+
+
#else
void movl_rm(RegisterID src, const void* addr)
{
if (src == X86Registers::eax)
movl_EAXm(addr);
- else
+ else
m_formatter.oneByteOp(OP_MOV_EvGv, src, addr);
}
-
+
void movl_mr(const void* addr, RegisterID dst)
{
if (dst == X86Registers::eax)
@@ -1351,7 +1351,7 @@ public:
{
m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, offset);
}
-
+
void movzbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
m_formatter.twoByteOp(OP2_MOVZX_GvEb, dst, base, index, scale, offset);
@@ -1361,7 +1361,7 @@ public:
{
m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, offset);
}
-
+
void movsbl_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
{
m_formatter.twoByteOp(OP2_MOVSX_GvEb, dst, base, index, scale, offset);
@@ -1404,13 +1404,13 @@ public:
m_formatter.oneByteOp(OP_CALL_rel32);
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel call(RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, dst);
return m_formatter.label();
}
-
+
void call_m(int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_CALLN, base, offset);
@@ -1421,7 +1421,7 @@ public:
m_formatter.oneByteOp(OP_JMP_rel32);
return m_formatter.immediateRel32();
}
-
+
// Return a AssemblerLabel so we have a label to the jump, so we can use this
// To make a tail recursive call on x86-64. The MacroAssembler
// really shouldn't wrap this as a Jump, since it can't be linked. :-/
@@ -1430,12 +1430,12 @@ public:
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, dst);
return m_formatter.label();
}
-
+
void jmp_m(int offset, RegisterID base)
{
m_formatter.oneByteOp(OP_GROUP5_Ev, GROUP5_OP_JMPN, base, offset);
}
-
+
#if !CPU(X86_64)
void jmp_m(const void* address)
{
@@ -1448,7 +1448,7 @@ public:
m_formatter.twoByteOp(jccRel32(ConditionNE));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jnz()
{
return jne();
@@ -1459,7 +1459,7 @@ public:
m_formatter.twoByteOp(jccRel32(ConditionE));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jz()
{
return je();
@@ -1470,25 +1470,25 @@ public:
m_formatter.twoByteOp(jccRel32(ConditionL));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jb()
{
m_formatter.twoByteOp(jccRel32(ConditionB));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jle()
{
m_formatter.twoByteOp(jccRel32(ConditionLE));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jbe()
{
m_formatter.twoByteOp(jccRel32(ConditionBE));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jge()
{
m_formatter.twoByteOp(jccRel32(ConditionGE));
@@ -1506,13 +1506,13 @@ public:
m_formatter.twoByteOp(jccRel32(ConditionA));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jae()
{
m_formatter.twoByteOp(jccRel32(ConditionAE));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel jo()
{
m_formatter.twoByteOp(jccRel32(ConditionO));
@@ -1530,7 +1530,7 @@ public:
m_formatter.twoByteOp(jccRel32(ConditionP));
return m_formatter.immediateRel32();
}
-
+
AssemblerLabel js()
{
m_formatter.twoByteOp(jccRel32(ConditionS));
@@ -1611,7 +1611,7 @@ public:
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_CVTSS2SD_VsdWsd, dst, (RegisterID)src);
}
-
+
#if CPU(X86_64)
void cvttsd2siq_rr(XMMRegisterID src, RegisterID dst)
{
@@ -1657,19 +1657,19 @@ public:
m_formatter.prefix(PRE_SSE_F2);
m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, offset);
}
-
+
void movsd_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.prefix(PRE_SSE_F2);
m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset);
}
-
+
void movss_rm(XMMRegisterID src, int offset, RegisterID base, RegisterID index, int scale)
{
m_formatter.prefix(PRE_SSE_F3);
m_formatter.twoByteOp(OP2_MOVSD_WsdVsd, (RegisterID)src, base, index, scale, offset);
}
-
+
void movsd_mr(int offset, RegisterID base, XMMRegisterID dst)
{
m_formatter.prefix(PRE_SSE_F2);
@@ -1681,7 +1681,7 @@ public:
m_formatter.prefix(PRE_SSE_F2);
m_formatter.twoByteOp(OP2_MOVSD_VsdWsd, dst, base, index, scale, offset);
}
-
+
void movss_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst)
{
m_formatter.prefix(PRE_SSE_F3);
@@ -1800,7 +1800,7 @@ public:
{
m_formatter.oneByteOp(OP_INT3);
}
-
+
void ret()
{
m_formatter.oneByteOp(OP_RET);
@@ -1817,7 +1817,7 @@ public:
{
return m_formatter.codeSize();
}
-
+
AssemblerLabel labelForWatchpoint()
{
AssemblerLabel result = m_formatter.label();
@@ -1827,7 +1827,7 @@ public:
m_indexOfTailOfLastWatchpoint = result.m_offset + maxJumpReplacementSize();
return result;
}
-
+
AssemblerLabel labelIgnoringWatchpoints()
{
return m_formatter.label();
@@ -1877,7 +1877,7 @@ public:
memcpy(&val, t_ptr, sizeof(T));
return val;
}
-
+
static void linkJump(void* code, AssemblerLabel from, void* to)
{
ASSERT(from.isSet());
@@ -1903,12 +1903,12 @@ public:
{
setRel32(from, to);
}
-
+
static void relinkCall(void* from, void* to)
{
setRel32(from, to);
}
-
+
static void repatchCompact(void* where, int32_t value)
{
ASSERT(value >= std::numeric_limits<int8_t>::min());
@@ -1925,7 +1925,7 @@ public:
{
setPointer(where, value);
}
-
+
static void* readPointer(void* where)
{
return reinterpret_cast<void**>(where)[-1];
@@ -1939,12 +1939,12 @@ public:
ptr[0] = static_cast<uint8_t>(OP_JMP_rel32);
*reinterpret_cast<int32_t*>(ptr + 1) = static_cast<int32_t>(distance);
}
-
+
static ptrdiff_t maxJumpReplacementSize()
{
return 5;
}
-
+
#if CPU(X86_64)
static void revertJumpTo_movq_i64r(void* instructionStart, int64_t imm, RegisterID dst)
{
@@ -1954,7 +1954,7 @@ public:
uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
ptr[0] = PRE_REX | (1 << 3) | (dst >> 3);
ptr[1] = OP_MOV_EAXIv | (dst & 7);
-
+
union {
uint64_t asWord;
uint8_t asBytes[8];
@@ -1964,7 +1964,7 @@ public:
ptr[i] = u.asBytes[i - rexBytes - opcodeBytes];
}
#endif
-
+
static void revertJumpTo_cmpl_ir_force32(void* instructionStart, int32_t imm, RegisterID dst)
{
const int opcodeBytes = 1;
@@ -1981,7 +1981,7 @@ public:
for (unsigned i = opcodeBytes + modRMBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
ptr[i] = u.asBytes[i - opcodeBytes - modRMBytes];
}
-
+
static void revertJumpTo_cmpl_im_force32(void* instructionStart, int32_t imm, int offset, RegisterID dst)
{
ASSERT_UNUSED(offset, !offset);
@@ -1999,7 +1999,7 @@ public:
for (unsigned i = opcodeBytes + modRMBytes; i < static_cast<unsigned>(maxJumpReplacementSize()); ++i)
ptr[i] = u.asBytes[i - opcodeBytes - modRMBytes];
}
-
+
static void replaceWithLoad(void* instructionStart)
{
uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
@@ -2017,7 +2017,7 @@ public:
RELEASE_ASSERT_NOT_REACHED();
}
}
-
+
static void replaceWithAddressComputation(void* instructionStart)
{
uint8_t* ptr = reinterpret_cast<uint8_t*>(instructionStart);
@@ -2035,7 +2035,7 @@ public:
RELEASE_ASSERT_NOT_REACHED();
}
}
-
+
static unsigned getCallReturnOffset(AssemblerLabel call)
{
ASSERT(call.isSet());
@@ -2047,12 +2047,12 @@ public:
ASSERT(label.isSet());
return reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(code) + label.m_offset);
}
-
+
static int getDifferenceBetweenLabels(AssemblerLabel a, AssemblerLabel b)
{
return b.m_offset - a.m_offset;
}
-
+
PassRefPtr<ExecutableMemoryHandle> executableCopy(JSGlobalData& globalData, void* ownerUID, JITCompilationEffort effort)
{
return m_formatter.executableCopy(globalData, ownerUID, effort);
@@ -2086,7 +2086,7 @@ private:
T *ptr = &reinterpret_cast<T*>(where)[idx];
memcpy(ptr, &value, sizeof(T));
}
-
+
static void setInt8(void* where, int8_t value)
{
reinterpret_cast<int8_t*>(where)[-1] = value;
@@ -2172,7 +2172,7 @@ private:
m_buffer.putByteUnchecked(opcode);
memoryModRM_disp32(reg, base, offset);
}
-
+
void oneByteOp_disp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
{
m_buffer.ensureSpace(maxInstructionSize);
@@ -2286,7 +2286,7 @@ private:
m_buffer.putByteUnchecked(opcode);
memoryModRM_disp32(reg, base, offset);
}
-
+
void oneByteOp64_disp8(OneByteOpcodeID opcode, int reg, RegisterID base, int offset)
{
m_buffer.ensureSpace(maxInstructionSize);
@@ -2365,7 +2365,7 @@ private:
void twoByteOp8(TwoByteOpcodeID opcode, RegisterID reg, RegisterID rm)
{
m_buffer.ensureSpace(maxInstructionSize);
- emitRexIf(byteRegRequiresRex(reg)|byteRegRequiresRex(rm), reg, 0, rm);
+ emitRexIf(byteRegRequiresRex(reg) || byteRegRequiresRex(rm), reg, 0, rm);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
m_buffer.putByteUnchecked(opcode);
registerModRM(reg, rm);
@@ -2567,7 +2567,7 @@ private:
m_buffer.putIntUnchecked(offset);
}
}
-
+
void memoryModRM(int reg, RegisterID base, RegisterID index, int scale, int offset)
{
ASSERT(index != noIndex);
diff --git a/src/3rdparty/masm/stubs/WTFStubs.cpp b/src/3rdparty/masm/stubs/WTFStubs.cpp
index f408b355f5..facba7d937 100644
--- a/src/3rdparty/masm/stubs/WTFStubs.cpp
+++ b/src/3rdparty/masm/stubs/WTFStubs.cpp
@@ -44,6 +44,10 @@
#include <qbytearray.h> // qvsnprintf
#include <FilePrintStream.h>
+#if ENABLE(ASSEMBLER) && CPU(X86) && !OS(MAC_OS_X)
+#include <MacroAssemblerX86Common.h>
+#endif
+
namespace WTF {
void* fastMalloc(size_t size)
@@ -142,8 +146,6 @@ void WTFInvokeCrashHook()
#if ENABLE(ASSEMBLER) && CPU(X86) && !OS(MAC_OS_X)
-#include <MacroAssemblerX86Common.h>
-
JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse2CheckState = JSC::MacroAssemblerX86Common::NotCheckedSSE2;
#endif
diff --git a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
index d59fdcd675..d799f913a4 100644
--- a/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
+++ b/src/3rdparty/masm/wtf/OSAllocatorPosix.cpp
@@ -98,6 +98,9 @@ static int memfdForUsage(size_t bytes, OSAllocator::Usage usage)
void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
{
#if OS(QNX)
+ UNUSED_PARAM(usage);
+ UNUSED_PARAM(writable);
+ UNUSED_PARAM(executable);
// Reserve memory with PROT_NONE and MAP_LAZY so it isn't committed now.
void* result = mmap(0, bytes, PROT_NONE, MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
if (result == MAP_FAILED)
@@ -111,7 +114,11 @@ void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable,
(fd == -1 ? MAP_ANON : 0), fd, 0);
if (result == MAP_FAILED)
CRASH();
- madvise(result, bytes, MADV_DONTNEED);
+
+ while (madvise(result, bytes, MADV_DONTNEED)) {
+ if (errno != EAGAIN)
+ CRASH();
+ }
if (fd != -1)
close(fd);
@@ -218,7 +225,12 @@ void OSAllocator::commit(void* address, size_t bytes, bool writable, bool execut
protection |= PROT_EXEC;
if (mprotect(address, bytes, protection))
CRASH();
- madvise(address, bytes, MADV_WILLNEED);
+
+ while (madvise(address, bytes, MADV_WILLNEED)) {
+ if (errno != EAGAIN)
+ break; // We don't have to crash here. MADV_WILLNEED is only advisory
+ }
+
#elif HAVE(MADV_FREE_REUSE)
UNUSED_PARAM(writable);
UNUSED_PARAM(executable);
@@ -238,7 +250,10 @@ void OSAllocator::decommit(void* address, size_t bytes)
// Use PROT_NONE and MAP_LAZY to decommit the pages.
mmap(address, bytes, PROT_NONE, MAP_FIXED | MAP_LAZY | MAP_PRIVATE | MAP_ANON, -1, 0);
#elif OS(LINUX)
- madvise(address, bytes, MADV_DONTNEED);
+ while (madvise(address, bytes, MADV_DONTNEED)) {
+ if (errno != EAGAIN)
+ CRASH();
+ }
if (mprotect(address, bytes, PROT_NONE))
CRASH();
#elif HAVE(MADV_FREE_REUSE)
diff --git a/src/3rdparty/masm/yarr/Yarr.h b/src/3rdparty/masm/yarr/Yarr.h
index ccf78f9880..2955ea7e72 100644
--- a/src/3rdparty/masm/yarr/Yarr.h
+++ b/src/3rdparty/masm/yarr/Yarr.h
@@ -28,6 +28,7 @@
#pragma once
#include <limits.h>
+#include <limits>
#include "YarrErrorCode.h"
namespace JSC { namespace Yarr {
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ca221d9f5f..3c6a28072f 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -28,9 +28,12 @@ if(TARGET Qt::Gui AND TARGET Qt::qsb AND QT_FEATURE_qml_animation)
add_subdirectory(quickshapes)
add_subdirectory(quicklayouts)
- find_package(Qt6 ${PROJECT_VERSION} CONFIG COMPONENTS Test) # special case
- if(QT_FEATURE_testlib AND TARGET Qt::Test) # special case
+ find_package(Qt6 ${PROJECT_VERSION} QUIET CONFIG OPTIONAL_COMPONENTS Test)
+ if(QT_FEATURE_testlib AND TARGET Qt::Test)
add_subdirectory(qmltest)
+ if(QT_FEATURE_network)
+ add_subdirectory(quicktestutils)
+ endif()
endif()
if(QT_FEATURE_quick_particles)
@@ -40,6 +43,16 @@ if(TARGET Qt::Gui AND TARGET Qt::qsb AND QT_FEATURE_qml_animation)
if(TARGET Qt::Widgets)
add_subdirectory(quickwidgets)
endif()
+
+ add_subdirectory(quicktemplates2)
+ add_subdirectory(quickcontrols2impl)
+ add_subdirectory(quickcontrols2)
+ add_subdirectory(quickdialogs2)
+ add_subdirectory(quicknativestyle)
+
+ if(QT_FEATURE_testlib AND QT_FEATURE_network AND TARGET Qt::Test AND TARGET Qt::QuickControls2)
+ add_subdirectory(quickcontrolstestutils)
+ endif()
else()
qt_configure_add_summary_section(NAME "Qt Quick")
qt_configure_add_summary_entry(TYPE "message" ARGS "Qt Quick support" MESSAGE "no")
diff --git a/src/core/qqmlstandardpaths.cpp b/src/core/qqmlstandardpaths.cpp
index 39c5eb3ebf..12f401b565 100644
--- a/src/core/qqmlstandardpaths.cpp
+++ b/src/core/qqmlstandardpaths.cpp
@@ -149,3 +149,5 @@ QUrl QQmlStandardPaths::writableLocation(QStandardPaths::StandardLocation type)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlstandardpaths_p.cpp"
diff --git a/src/imports/builtins/CMakeLists.txt b/src/imports/builtins/CMakeLists.txt
index fb6984a961..e1632e1b09 100644
--- a/src/imports/builtins/CMakeLists.txt
+++ b/src/imports/builtins/CMakeLists.txt
@@ -4,3 +4,10 @@ qt_path_join(qml_install_dir "${QT_INSTALL_DIR}" "${INSTALL_QMLDIR}")
qt_copy_or_install(FILES ${qml_type_files}
DESTINATION ${qml_install_dir}
)
+
+# in prefix builds we also need to copy the files into the build directory of
+# the module, so that they are located together with the QML modules
+if(QT_WILL_INSTALL)
+ qt_path_join(qml_build_dir "${QT_BUILD_DIR}" "${INSTALL_QMLDIR}")
+ file(COPY ${qml_type_files} DESTINATION ${qml_build_dir})
+endif()
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index f1a57cfab3..907f24fef6 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -5,6 +5,8 @@ Module {
Component {
name: "void"
+ extension: "undefined"
+ exports: ["QML/void 1.0"]
accessSemantics: "none"
}
@@ -87,14 +89,8 @@ Module {
}
Component {
- name: "number"
- extension: "Number"
- accessSemantics: "value"
- }
-
- Component {
name: "int"
- prototype: "number"
+ extension: "Number"
exports: ["QML/int 1.0"]
exportMetaObjectRevisions: [256]
accessSemantics: "value"
@@ -102,13 +98,13 @@ Module {
Component {
name: "float"
- prototype: "number"
+ extension: "Number"
accessSemantics: "value"
}
Component {
name: "double"
- prototype: "number"
+ extension: "Number"
exports: ["QML/real 1.0", "QML/double 1.0"]
exportMetaObjectRevisions: [256]
accessSemantics: "value"
@@ -124,6 +120,7 @@ Module {
Component {
name: "bool"
+ extension: "Boolean"
exports: ["QML/bool 1.0"]
exportMetaObjectRevisions: [256]
accessSemantics: "value"
@@ -139,6 +136,7 @@ Module {
Component {
name: "QUrl"
+ extension: "Url"
exports: ["QML/url 1.0"]
exportMetaObjectRevisions: [256]
accessSemantics: "value"
@@ -160,4 +158,9 @@ Module {
extension: "RegExp"
accessSemantics: "value"
}
+
+ Component {
+ name: "QByteArray"
+ accessSemantics: "value"
+ }
}
diff --git a/src/imports/builtins/jsroot.qmltypes b/src/imports/builtins/jsroot.qmltypes
index 419a4e5726..0a8b70babe 100644
--- a/src/imports/builtins/jsroot.qmltypes
+++ b/src/imports/builtins/jsroot.qmltypes
@@ -623,7 +623,7 @@ Module {
Property { name: "Math"; type: "Math" }
Property { name: "JSON"; type: "JSON" }
Property { name: "Reflect"; type: "Reflect" }
- Property { name: "undefined" }
+ Property { name: "undefined"; isReadonly: true }
Property { name: "NaN"; type: "number"; isReadonly: true }
Property { name: "Infinity"; type: "number"; isReadonly: true }
Property { name: "Qt"; type: "Qt" }
diff --git a/src/imports/tooling/CMakeLists.txt b/src/imports/tooling/CMakeLists.txt
index a39f9ee91b..f8daf9f4eb 100644
--- a/src/imports/tooling/CMakeLists.txt
+++ b/src/imports/tooling/CMakeLists.txt
@@ -10,7 +10,7 @@ set(qml_files
)
set_source_files_properties(${qml_files} PROPERTIES
- QT_QML_SOURCE_VERSION "1.2;6.0"
+ QT_QML_SOURCE_VERSIONS "1.2;6.0"
)
qt_internal_add_qml_module(quicktooling
diff --git a/src/imports/tooling/Method.qml b/src/imports/tooling/Method.qml
index 3b019c4549..b43aaf6912 100644
--- a/src/imports/tooling/Method.qml
+++ b/src/imports/tooling/Method.qml
@@ -44,4 +44,6 @@ Member {
property string type
property int revision: 0
property bool isConstructor: false
+ property bool isList: false
+ property bool isPointer: false
}
diff --git a/src/imports/tooling/Parameter.qml b/src/imports/tooling/Parameter.qml
index 073f83c51a..ee110c8b39 100644
--- a/src/imports/tooling/Parameter.qml
+++ b/src/imports/tooling/Parameter.qml
@@ -43,4 +43,5 @@ QtObject {
property string name
property string type
property bool isPointer: false
+ property bool isList: false
}
diff --git a/src/imports/tooling/Signal.qml b/src/imports/tooling/Signal.qml
index 4ac1dc1fea..1fa8a96b3a 100644
--- a/src/imports/tooling/Signal.qml
+++ b/src/imports/tooling/Signal.qml
@@ -42,4 +42,5 @@ import QML
Member {
default property list<Parameter> parameters
property int revision: 0
+ property string type
}
diff --git a/src/labs/CMakeLists.txt b/src/labs/CMakeLists.txt
index 6ca0d7a695..fc340e42e5 100644
--- a/src/labs/CMakeLists.txt
+++ b/src/labs/CMakeLists.txt
@@ -12,6 +12,10 @@ if(TARGET Qt::Quick)
add_subdirectory(animation)
endif()
+if(TARGET Qt::QuickTemplates2)
+ add_subdirectory(platform)
+endif()
+
if(QT_FEATURE_quick_shadereffect AND TARGET Qt::Quick)
add_subdirectory(wavefrontmesh)
endif()
@@ -19,3 +23,4 @@ endif()
if(QT_FEATURE_systemsemaphore AND TARGET Qt::Quick)
add_subdirectory(sharedimage)
endif()
+
diff --git a/src/labs/animation/CMakeLists.txt b/src/labs/animation/CMakeLists.txt
index 88e756f3a6..6524c65477 100644
--- a/src/labs/animation/CMakeLists.txt
+++ b/src/labs/animation/CMakeLists.txt
@@ -3,6 +3,8 @@ qt_internal_add_qml_module(LabsAnimation
VERSION "${PROJECT_VERSION}"
PLUGIN_TARGET labsanimationplugin
CLASS_NAME QtLabsAnimationPlugin
+ DEPENDENCIES
+ QtQml
SOURCES
qquickboundaryrule.cpp qquickboundaryrule_p.h
qqmlanimationglobal_p.h
diff --git a/src/labs/animation/doc/src/qmlanimation.qdoc b/src/labs/animation/doc/src/qmlanimation.qdoc
index c8d949b27b..2104b8f9f5 100644
--- a/src/labs/animation/doc/src/qmlanimation.qdoc
+++ b/src/labs/animation/doc/src/qmlanimation.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule Qt.labs.animation 1.0
+ \qmlmodule Qt.labs.animation
\title Qt Quick experimental animation types
\ingroup qmlmodules
\brief Provides QML experimental types for animation
diff --git a/src/labs/animation/qquickboundaryrule.cpp b/src/labs/animation/qquickboundaryrule.cpp
index 61e5d007d5..0b2d2e2856 100644
--- a/src/labs/animation/qquickboundaryrule.cpp
+++ b/src/labs/animation/qquickboundaryrule.cpp
@@ -146,7 +146,7 @@ void QQuickBoundaryReturnJob::updateState(QAbstractAnimationJob::State newState,
Note that a property cannot have more than one assigned BoundaryRule.
- \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML}
+ \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML}, {Pointer Handlers Example}
*/
QQuickBoundaryRule::QQuickBoundaryRule(QObject *parent)
@@ -353,7 +353,7 @@ qreal QQuickBoundaryRule::peakOvershoot() const
}
/*!
- \qmlproperty enum QtQuick::BoundaryRule::overshootFilter
+ \qmlproperty enumeration QtQuick::BoundaryRule::overshootFilter
This property specifies the aggregation function that will be applied to
the intercepted property value.
@@ -419,7 +419,7 @@ bool QQuickBoundaryRule::returnToBounds()
}
/*!
- \qmlproperty qreal QtQuick::BoundaryRule::easing
+ \qmlproperty enumeration QtQuick::BoundaryRule::easing
This property holds the easing curve to be applied in overshoot mode
(whenever the \l minimum or \l maximum constraint is violated, while
diff --git a/src/labs/folderlistmodel/fileinfothread.cpp b/src/labs/folderlistmodel/fileinfothread.cpp
index a93edd3b1b..69dcedef77 100644
--- a/src/labs/folderlistmodel/fileinfothread.cpp
+++ b/src/labs/folderlistmodel/fileinfothread.cpp
@@ -44,6 +44,7 @@
#include <QDebug>
+QT_BEGIN_NAMESPACE
FileInfoThread::FileInfoThread(QObject *parent)
: QThread(parent),
@@ -367,3 +368,7 @@ void FileInfoThread::findChangeRange(const QList<FileProperty> &list, int &fromI
// For now I let the rest of the list be updated..
toIndex = list.size() > currentFileList.size() ? list.size() - 1 : currentFileList.size() - 1;
}
+
+QT_END_NAMESPACE
+
+#include "moc_fileinfothread_p.cpp"
diff --git a/src/labs/folderlistmodel/fileinfothread_p.h b/src/labs/folderlistmodel/fileinfothread_p.h
index 1ed3a9904b..903a95efa1 100644
--- a/src/labs/folderlistmodel/fileinfothread_p.h
+++ b/src/labs/folderlistmodel/fileinfothread_p.h
@@ -63,6 +63,8 @@
#include "fileproperty_p.h"
#include "qquickfolderlistmodel_p.h"
+QT_BEGIN_NAMESPACE
+
class FileInfoThread : public QThread
{
Q_OBJECT
@@ -130,4 +132,6 @@ private:
bool caseSensitive;
};
+QT_END_NAMESPACE
+
#endif // FILEINFOTHREAD_P_H
diff --git a/src/labs/folderlistmodel/fileproperty_p.h b/src/labs/folderlistmodel/fileproperty_p.h
index 48be4a3d85..26f2b71b47 100644
--- a/src/labs/folderlistmodel/fileproperty_p.h
+++ b/src/labs/folderlistmodel/fileproperty_p.h
@@ -54,6 +54,8 @@
#include <QFileInfo>
#include <QDateTime>
+QT_BEGIN_NAMESPACE
+
class FileProperty
{
public:
@@ -100,4 +102,7 @@ private:
QDateTime mLastModified;
QDateTime mLastRead;
};
+
+QT_END_NAMESPACE
+
#endif // FILEPROPERTY_P_H
diff --git a/src/labs/models/CMakeLists.txt b/src/labs/models/CMakeLists.txt
index e417013ea6..fa4ebbd70b 100644
--- a/src/labs/models/CMakeLists.txt
+++ b/src/labs/models/CMakeLists.txt
@@ -10,6 +10,8 @@ qt_internal_add_qml_module(LabsQmlModels
PUBLIC_LIBRARIES
Qt::QmlModelsPrivate
Qt::QmlPrivate
+ DEPENDENCIES
+ QtQml.Models
)
qt_internal_extend_target(LabsQmlModels CONDITION QT_FEATURE_qml_table_model
diff --git a/src/labs/models/doc/src/qmllabsmodels.qdoc b/src/labs/models/doc/src/qmllabsmodels.qdoc
index f780a75687..598786f1f6 100644
--- a/src/labs/models/doc/src/qmllabsmodels.qdoc
+++ b/src/labs/models/doc/src/qmllabsmodels.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule Qt.labs.qmlmodels 1.0
+ \qmlmodule Qt.labs.qmlmodels
\title Qt QML Models experimental QML Types
\ingroup qmlmodules
\brief Provides QML experimental types for data models.
diff --git a/src/labs/models/qqmldelegatecomponent.cpp b/src/labs/models/qqmldelegatecomponent.cpp
index f7b778e574..1ef7f532a0 100644
--- a/src/labs/models/qqmldelegatecomponent.cpp
+++ b/src/labs/models/qqmldelegatecomponent.cpp
@@ -155,7 +155,17 @@ bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
if (!m_value.isValid() && m_row < 0 && m_column < 0)
return true;
- const bool roleMatched = (m_value.isValid()) ? value == m_value : true;
+ bool roleMatched = true;
+ if (m_value.isValid()) {
+ roleMatched = (value == m_value);
+ if (!roleMatched) {
+ bool valueOk = false;
+ bool mValueOk = false;
+ roleMatched = (value.toInt(&valueOk) == m_value.toInt(&mValueOk) && valueOk && mValueOk);
+ }
+ if (!roleMatched)
+ roleMatched = (value.toString() == m_value.toString());
+ }
const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
return roleMatched && rowMatched && columnMatched;
@@ -330,3 +340,5 @@ QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int
}
QT_END_NAMESPACE
+
+#include "moc_qqmldelegatecomponent_p.cpp"
diff --git a/src/labs/models/qqmltablemodel.cpp b/src/labs/models/qqmltablemodel.cpp
index e60c525b0d..ea1671fb11 100644
--- a/src/labs/models/qqmltablemodel.cpp
+++ b/src/labs/models/qqmltablemodel.cpp
@@ -1085,3 +1085,5 @@ bool QQmlTableModel::validateRowIndex(const char *functionName, const char *argu
}
QT_END_NAMESPACE
+
+#include "moc_qqmltablemodel_p.cpp"
diff --git a/src/labs/models/qqmltablemodelcolumn.cpp b/src/labs/models/qqmltablemodelcolumn.cpp
index 93da0642de..73dfd595fb 100644
--- a/src/labs/models/qqmltablemodelcolumn.cpp
+++ b/src/labs/models/qqmltablemodelcolumn.cpp
@@ -198,3 +198,5 @@ const QHash<int, QString> QQmlTableModelColumn::supportedRoleNames()
}
QT_END_NAMESPACE
+
+#include "moc_qqmltablemodelcolumn_p.cpp"
diff --git a/src/labs/models/qqmltablemodelcolumn_p.h b/src/labs/models/qqmltablemodelcolumn_p.h
index 7da31c9e2a..ef0fd18fe0 100644
--- a/src/labs/models/qqmltablemodelcolumn_p.h
+++ b/src/labs/models/qqmltablemodelcolumn_p.h
@@ -216,8 +216,6 @@ Q_SIGNALS:
void setSizeHintChanged();
private:
- int mIndex = -1;
-
// We store these in hashes because QQuickTableModel needs string-based lookup in certain situations.
QHash<QString, QJSValue> mGetters;
QHash<QString, QJSValue> mSetters;
diff --git a/src/labs/platform/CMakeLists.txt b/src/labs/platform/CMakeLists.txt
new file mode 100644
index 0000000000..92a41808da
--- /dev/null
+++ b/src/labs/platform/CMakeLists.txt
@@ -0,0 +1,91 @@
+#####################################################################
+## qtlabsplatformplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(qtlabsplatformplugin
+ URI "Qt.labs.platform"
+ VERSION "1.1"
+ CLASS_NAME QtLabsPlatformPlugin
+ DEPENDENCIES
+ QtQuick
+ PLUGIN_TARGET qtlabsplatformplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquicklabsplatformcolordialog.cpp qquicklabsplatformcolordialog_p.h
+ qquicklabsplatformdialog.cpp qquicklabsplatformdialog_p.h
+ qquicklabsplatformfiledialog.cpp qquicklabsplatformfiledialog_p.h
+ qquicklabsplatformfolderdialog.cpp qquicklabsplatformfolderdialog_p.h
+ qquicklabsplatformfontdialog.cpp qquicklabsplatformfontdialog_p.h
+ qquicklabsplatformicon.cpp qquicklabsplatformicon_p.h
+ qquicklabsplatformiconloader.cpp qquicklabsplatformiconloader_p.h
+ qquicklabsplatformmenu.cpp qquicklabsplatformmenu_p.h
+ qquicklabsplatformmenubar.cpp qquicklabsplatformmenubar_p.h
+ qquicklabsplatformmenuitem.cpp qquicklabsplatformmenuitem_p.h
+ qquicklabsplatformmenuitemgroup.cpp qquicklabsplatformmenuitemgroup_p.h
+ qquicklabsplatformmenuseparator.cpp qquicklabsplatformmenuseparator_p.h
+ qquicklabsplatformmessagedialog.cpp qquicklabsplatformmessagedialog_p.h
+ qquicklabsplatformstandardpaths.cpp qquicklabsplatformstandardpaths_p.h
+ qtlabsplatformplugin.cpp
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets
+ SOURCES
+ widgets/qwidgetplatform_p.h
+ LIBRARIES
+ Qt::Widgets
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_systemtrayicon AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformsystemtrayicon.cpp widgets/qwidgetplatformsystemtrayicon_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND (QT_FEATURE_colordialog OR QT_FEATURE_filedialog OR QT_FEATURE_fontdialog OR QT_FEATURE_messagebox)
+ SOURCES
+ widgets/qwidgetplatformdialog.cpp widgets/qwidgetplatformdialog_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_colordialog AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformcolordialog.cpp widgets/qwidgetplatformcolordialog_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_filedialog AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformfiledialog.cpp widgets/qwidgetplatformfiledialog_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_fontdialog AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformfontdialog.cpp widgets/qwidgetplatformfontdialog_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_menu AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformmenu.cpp widgets/qwidgetplatformmenu_p.h
+ widgets/qwidgetplatformmenuitem.cpp widgets/qwidgetplatformmenuitem_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION TARGET Qt::Widgets AND QT_FEATURE_messagebox AND TARGET Qt::Widgets # special case
+ SOURCES
+ widgets/qwidgetplatformmessagedialog.cpp widgets/qwidgetplatformmessagedialog_p.h
+)
+
+qt_internal_extend_target(qtlabsplatformplugin CONDITION QT_FEATURE_systemtrayicon
+ SOURCES
+ qquicklabsplatformsystemtrayicon.cpp qquicklabsplatformsystemtrayicon_p.h
+)
+
+qt_internal_add_docs(qtlabsplatformplugin
+ doc/qtlabsplatform.qdocconf
+)
diff --git a/src/labs/platform/doc/images/qtlabsplatform-colordialog-gtk.png b/src/labs/platform/doc/images/qtlabsplatform-colordialog-gtk.png
new file mode 100644
index 0000000000..12197f7f74
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-colordialog-gtk.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-filedialog-gtk.png b/src/labs/platform/doc/images/qtlabsplatform-filedialog-gtk.png
new file mode 100644
index 0000000000..9360d747a2
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-filedialog-gtk.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-folderdialog-gtk.png b/src/labs/platform/doc/images/qtlabsplatform-folderdialog-gtk.png
new file mode 100644
index 0000000000..45f0585c5d
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-folderdialog-gtk.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-fontdialog-gtk.png b/src/labs/platform/doc/images/qtlabsplatform-fontdialog-gtk.png
new file mode 100644
index 0000000000..0c6217bdb4
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-fontdialog-gtk.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-menu.png b/src/labs/platform/doc/images/qtlabsplatform-menu.png
new file mode 100644
index 0000000000..7945b45fbe
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-menu.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-menubar.png b/src/labs/platform/doc/images/qtlabsplatform-menubar.png
new file mode 100644
index 0000000000..7faa81412b
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-menubar.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-messagedialog-android.png b/src/labs/platform/doc/images/qtlabsplatform-messagedialog-android.png
new file mode 100644
index 0000000000..3986694f7d
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-messagedialog-android.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-messagedialog-informative-android.png b/src/labs/platform/doc/images/qtlabsplatform-messagedialog-informative-android.png
new file mode 100644
index 0000000000..b2d3cd37cb
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-messagedialog-informative-android.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-menu.png b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-menu.png
new file mode 100644
index 0000000000..670df8ed13
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-menu.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-message.png b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-message.png
new file mode 100644
index 0000000000..beaeed92c4
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon-message.png
Binary files differ
diff --git a/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon.png b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon.png
new file mode 100644
index 0000000000..2f7a851c88
--- /dev/null
+++ b/src/labs/platform/doc/images/qtlabsplatform-systemtrayicon.png
Binary files differ
diff --git a/src/labs/platform/doc/qtlabsplatform.qdocconf b/src/labs/platform/doc/qtlabsplatform.qdocconf
new file mode 100644
index 0000000000..8f64cae794
--- /dev/null
+++ b/src/labs/platform/doc/qtlabsplatform.qdocconf
@@ -0,0 +1,40 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtquickcontrols2.qdocconf)
+
+project = QtLabsPlatform
+description = Qt Labs Platform Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtLabsPlatform
+
+qhp.QtLabsPlatform.file = qtlabsplatform.qhp
+qhp.QtLabsPlatform.namespace = org.qt-project.qtlabsplatform.$QT_VERSION_TAG
+qhp.QtLabsPlatform.virtualFolder = qtlabsplatform
+qhp.QtLabsPlatform.indexTitle = Qt Labs Platform
+qhp.QtLabsPlatform.indexRoot =
+
+qhp.QtLabsPlatform.filterAttributes = qtlabsplatform $QT_VERSION qtrefdoc
+qhp.QtLabsPlatform.customFilters.Qt.name = QtLabsPlatform $QT_VERSION
+qhp.QtLabsPlatform.customFilters.Qt.filterAttributes = qtlabsplatform $QT_VERSION
+
+qhp.QtLabsPlatform.subprojects = qmltypes
+qhp.QtLabsPlatform.subprojects.qmltypes.title = QML Types
+qhp.QtLabsPlatform.subprojects.qmltypes.indexTitle = Qt Labs Platform QML Types
+qhp.QtLabsPlatform.subprojects.qmltypes.selectors = qmlclass
+qhp.QtLabsPlatform.subprojects.qmltypes.sortPages = true
+
+depends = qtcore qtgui qtdoc qtqml qtqmlmodels qtquick qtquickcontrols qtwidgets
+
+# This module has no documented C++ types, clear the module header
+moduleheader =
+
+{headerdirs,sourcedirs} += ..
+
+imagedirs += images
+
+navigation.landingpage = "Qt Labs Platform"
+navigation.qmltypespage = "Qt Labs Platform QML Types"
+
+tagfile = qtlabsplatform.tags
+
+macro.labs = "\\note \\e{Types in Qt.labs modules are not guaranteed to remain compatible in future versions.}"
diff --git a/src/labs/platform/doc/src/includes/widgets.qdocinc b/src/labs/platform/doc/src/includes/widgets.qdocinc
new file mode 100644
index 0000000000..44ebba6de6
--- /dev/null
+++ b/src/labs/platform/doc/src/includes/widgets.qdocinc
@@ -0,0 +1,28 @@
+//! [1]
+The Qt Labs Platform module uses Qt Widgets as a fallback on platforms that
+do not have a native implementation available. Therefore, applications that
+use types from the Qt Labs Platform module should link to QtWidgets and use
+\l QApplication instead of \l QGuiApplication.
+
+To link against the QtWidgets library, add the following to your qmake project
+file:
+
+\code
+QT += widgets
+\endcode
+
+Create an instance of \l QApplication in \c main():
+
+\code
+#include <QApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ return app.exec();
+}
+\endcode
+//! [1]
diff --git a/src/labs/platform/doc/src/qt6-changes.qdoc b/src/labs/platform/doc/src/qt6-changes.qdoc
new file mode 100644
index 0000000000..de1c7a292f
--- /dev/null
+++ b/src/labs/platform/doc/src/qt6-changes.qdoc
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquicklabsplatform-changes-qt6.html
+ \title Changes to Qt Quick Labs Platform
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt Quick Labs Platform to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain compatibility for all the public APIs in each release.
+ Some changes were inevitable in an effort to make Qt a better framework.
+
+ In this topic we summarize those changes in Qt Quick Labs Platform, and
+ provide guidance to handle them.
+
+ \section1 The Menu type
+
+ The deprecated \c iconName and \c iconSource properties were removed. Use
+ the \l {Menu::}{icon} property instead.
+
+ \section1 The MenuItem type
+
+ The deprecated \c iconName and \c iconSource properties were removed. Use
+ the \l {MenuItem::}{icon} property instead.
+
+ \section1 The SystemTrayIcon type
+
+ The deprecated \c iconName and \c iconSource properties were removed. Use
+ the \l {SystemTrayIcon::}{icon} property instead.
+*/
diff --git a/src/labs/platform/doc/src/qtlabsplatform-index.qdoc b/src/labs/platform/doc/src/qtlabsplatform-index.qdoc
new file mode 100644
index 0000000000..c6eff0baa0
--- /dev/null
+++ b/src/labs/platform/doc/src/qtlabsplatform-index.qdoc
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtlabsplatform-index.html
+ \title Qt Labs Platform
+
+ \brief The experimental Qt Labs Platform module provides QML types for
+ native platform extensions.
+
+ The experimental Qt Labs Platform module provides QML types for native
+ platform extensions. The module was introduced in Qt 5.8.
+
+ \section1 QML Types
+
+ \generatelist {qmltypesbymodule Qt.labs.platform}
+
+ \labs
+
+ \section1 Module Evolution
+ \l{Changes to Qt Quick Labs Platform} lists important changes in the
+ module API and functionality that were done for the Qt 6 series of Qt.
+
+ \section1 Related Information
+
+ \list
+ \li \l{Qt Quick}
+ \li \l{Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/labs/platform/doc/src/qtlabsplatform-qmltypes.qdoc b/src/labs/platform/doc/src/qtlabsplatform-qmltypes.qdoc
new file mode 100644
index 0000000000..8a7d33a151
--- /dev/null
+++ b/src/labs/platform/doc/src/qtlabsplatform-qmltypes.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule Qt.labs.platform
+ \title Qt Labs Platform QML Types
+ \ingroup qmlmodules
+ \brief Provides QML types for native platform extensions.
+
+ The experimental \l{Qt Labs Platform} module provides QML types for native
+ platform extensions. These QML types work in conjunction with \l{Qt Quick}
+ and \l{Qt Quick Controls}.
+
+ The QML types can be imported into your application using the
+ following import statement in your .qml file:
+
+ \qml
+ import Qt.labs.platform
+ \endqml
+
+ \section1 QML Types
+
+ \generatelist {qmltypesbymodule Qt.labs.platform}
+
+ \labs
+
+ \section1 Related Information
+
+ \list
+ \li \l {Qt Quick Controls QML Types}
+ \endlist
+
+ \noautolist
+*/
diff --git a/src/labs/platform/platform.pri b/src/labs/platform/platform.pri
new file mode 100644
index 0000000000..c145663c23
--- /dev/null
+++ b/src/labs/platform/platform.pri
@@ -0,0 +1,39 @@
+HEADERS += \
+ $$PWD/qquicklabsplatformcolordialog_p.h \
+ $$PWD/qquicklabsplatformdialog_p.h \
+ $$PWD/qquicklabsplatformfiledialog_p.h \
+ $$PWD/qquicklabsplatformfolderdialog_p.h \
+ $$PWD/qquicklabsplatformfontdialog_p.h \
+ $$PWD/qquicklabsplatformicon_p.h \
+ $$PWD/qquicklabsplatformiconloader_p.h \
+ $$PWD/qquicklabsplatformmenu_p.h \
+ $$PWD/qquicklabsplatformmenubar_p.h \
+ $$PWD/qquicklabsplatformmenuitem_p.h \
+ $$PWD/qquicklabsplatformmenuitemgroup_p.h \
+ $$PWD/qquicklabsplatformmenuseparator_p.h \
+ $$PWD/qquicklabsplatformmessagedialog_p.h \
+ $$PWD/qquicklabsplatformstandardpaths_p.h
+
+SOURCES += \
+ $$PWD/qquicklabsplatformcolordialog.cpp \
+ $$PWD/qquicklabsplatformdialog.cpp \
+ $$PWD/qquicklabsplatformfiledialog.cpp \
+ $$PWD/qquicklabsplatformfolderdialog.cpp \
+ $$PWD/qquicklabsplatformfontdialog.cpp \
+ $$PWD/qquicklabsplatformicon.cpp \
+ $$PWD/qquicklabsplatformiconloader.cpp \
+ $$PWD/qquicklabsplatformmenu.cpp \
+ $$PWD/qquicklabsplatformmenubar.cpp \
+ $$PWD/qquicklabsplatformmenuitem.cpp \
+ $$PWD/qquicklabsplatformmenuitemgroup.cpp \
+ $$PWD/qquicklabsplatformmenuseparator.cpp \
+ $$PWD/qquicklabsplatformmessagedialog.cpp \
+ $$PWD/qquicklabsplatformstandardpaths.cpp
+
+
+qtConfig(systemtrayicon) {
+ HEADERS += \
+ $$PWD/qquicklabsplatformsystemtrayicon_p.h
+ SOURCES += \
+ $$PWD/qquicklabsplatformsystemtrayicon.cpp
+}
diff --git a/src/labs/platform/qquicklabsplatformcolordialog.cpp b/src/labs/platform/qquicklabsplatformcolordialog.cpp
new file mode 100644
index 0000000000..b6177cdf68
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformcolordialog.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformcolordialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ColorDialog
+ \inherits Dialog
+//! \instantiates QQuickLabsPlatformColorDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native color dialog.
+
+ The ColorDialog type provides a QML API for native platform color dialogs.
+
+ \image qtlabsplatform-colordialog-gtk.png
+
+ To show a color dialog, construct an instance of ColorDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentColor
+ property can be used to determine the currently selected color in the
+ dialog. The \l color property is updated only after the final selection
+ has been made by accepting the dialog.
+
+ \code
+ MenuItem {
+ text: "Color"
+ onTriggered: colorDialog.open()
+ }
+
+ ColorDialog {
+ id: colorDialog
+ currentColor: document.color
+ }
+
+ MyDocument {
+ id: document
+ color: colorDialog.color
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform color dialog is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li Linux (when running with the GTK+ platform theme)
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+*/
+
+QQuickLabsPlatformColorDialog::QQuickLabsPlatformColorDialog(QObject *parent)
+ : QQuickLabsPlatformDialog(QPlatformTheme::ColorDialog, parent),
+ m_options(QColorDialogOptions::create())
+{
+}
+
+/*!
+ \qmlproperty color Qt.labs.platform::ColorDialog::color
+
+ This property holds the final accepted color.
+
+ Unlike the \l currentColor property, the \c color property is not updated
+ while the user is selecting colors in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol OK
+ to accept a color. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentColor, {Dialog::}{accepted()}
+*/
+QColor QQuickLabsPlatformColorDialog::color() const
+{
+ return m_color;
+}
+
+void QQuickLabsPlatformColorDialog::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ setCurrentColor(color);
+ emit colorChanged();
+}
+
+/*!
+ \qmlproperty color Qt.labs.platform::ColorDialog::currentColor
+
+ This property holds the currently selected color in the dialog.
+
+ Unlike the \l color property, the \c currentColor property is updated
+ while the user is selecting colors in the dialog, even before the final
+ selection has been made.
+
+ \sa color
+*/
+QColor QQuickLabsPlatformColorDialog::currentColor() const
+{
+ if (QPlatformColorDialogHelper *colorDialog = qobject_cast<QPlatformColorDialogHelper *>(handle()))
+ return colorDialog->currentColor();
+ return m_currentColor;
+}
+
+void QQuickLabsPlatformColorDialog::setCurrentColor(const QColor &color)
+{
+ if (QPlatformColorDialogHelper *colorDialog = qobject_cast<QPlatformColorDialogHelper *>(handle()))
+ colorDialog->setCurrentColor(color);
+ m_currentColor = color;
+}
+
+/*!
+ \qmlproperty flags Qt.labs.platform::ColorDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value ColorDialog.ShowAlphaChannel Allow the user to select the alpha component of a color.
+ \value ColorDialog.NoButtons Don't display \uicontrol OK and \uicontrol Cancel buttons (useful for "live dialogs").
+*/
+QColorDialogOptions::ColorDialogOptions QQuickLabsPlatformColorDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickLabsPlatformColorDialog::setOptions(QColorDialogOptions::ColorDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+bool QQuickLabsPlatformColorDialog::useNativeDialog() const
+{
+ return QQuickLabsPlatformDialog::useNativeDialog()
+ && !m_options->testOption(QColorDialogOptions::DontUseNativeDialog);
+}
+
+void QQuickLabsPlatformColorDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformColorDialogHelper *colorDialog = qobject_cast<QPlatformColorDialogHelper *>(dialog)) {
+ connect(colorDialog, &QPlatformColorDialogHelper::currentColorChanged, this, &QQuickLabsPlatformColorDialog::currentColorChanged);
+ colorDialog->setOptions(m_options);
+ colorDialog->setCurrentColor(m_currentColor);
+ }
+}
+
+void QQuickLabsPlatformColorDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformColorDialogHelper *colorDialog = qobject_cast<QPlatformColorDialogHelper *>(dialog))
+ colorDialog->setOptions(m_options);
+}
+
+void QQuickLabsPlatformColorDialog::accept()
+{
+ setColor(currentColor());
+ QQuickLabsPlatformDialog::accept();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformcolordialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformcolordialog_p.h b/src/labs/platform/qquicklabsplatformcolordialog_p.h
new file mode 100644
index 0000000000..7eef090ffc
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformcolordialog_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMCOLORDIALOG_P_H
+#define QQUICKLABSPLATFORMCOLORDIALOG_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 "qquicklabsplatformdialog_p.h"
+#include <QtGui/qcolor.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformColorDialog : public QQuickLabsPlatformDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)
+ Q_PROPERTY(QColor currentColor READ currentColor WRITE setCurrentColor NOTIFY currentColorChanged FINAL)
+ Q_PROPERTY(QColorDialogOptions::ColorDialogOptions options READ options WRITE setOptions NOTIFY optionsChanged FINAL)
+ Q_FLAGS(QColorDialogOptions::ColorDialogOptions)
+
+public:
+ explicit QQuickLabsPlatformColorDialog(QObject *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ QColor currentColor() const;
+ void setCurrentColor(const QColor &color);
+
+ QColorDialogOptions::ColorDialogOptions options() const;
+ void setOptions(QColorDialogOptions::ColorDialogOptions options);
+
+Q_SIGNALS:
+ void colorChanged();
+ void currentColorChanged();
+ void optionsChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QColor m_color;
+ QColor m_currentColor; // TODO: QColorDialogOptions::initialColor
+ QSharedPointer<QColorDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformColorDialog)
+
+#endif // QQUICKLABSPLATFORMCOLORDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformdialog.cpp b/src/labs/platform/qquicklabsplatformdialog.cpp
new file mode 100644
index 0000000000..a05129e5aa
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformdialog.cpp
@@ -0,0 +1,411 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformdialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
+
+#include "widgets/qwidgetplatform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Dialog
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief The base class of native dialogs.
+
+ The Dialog type provides common QML API for native platform dialogs.
+
+ To show a native dialog, construct an instance of one of the concrete
+ Dialog implementations, set the desired properties, and call \l open().
+ Dialog emits \l accepted() or \l rejected() when the user is done with
+ the dialog.
+
+ \labs
+*/
+
+/*!
+ \qmlsignal void Qt.labs.platform::Dialog::accepted()
+
+ This signal is emitted when the dialog has been accepted either
+ interactively or by calling \l accept().
+
+ \note This signal is \e not emitted when closing the dialog with \l close().
+
+ \sa rejected()
+*/
+
+/*!
+ \qmlsignal void Qt.labs.platform::Dialog::rejected()
+
+ This signal is emitted when the dialog has been rejected either
+ interactively or by calling \l reject().
+
+ \note This signal is \e not emitted when closing the dialog with \l close().
+
+ \sa accepted()
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformDialogs)
+
+QQuickLabsPlatformDialog::QQuickLabsPlatformDialog(QPlatformTheme::DialogType type, QObject *parent)
+ : QObject(parent),
+ m_visible(false),
+ m_complete(false),
+ m_result(0),
+ m_parentWindow(nullptr),
+ m_flags(Qt::Dialog),
+ m_modality(Qt::WindowModal),
+ m_type(type),
+ m_handle(nullptr)
+{
+}
+
+QQuickLabsPlatformDialog::~QQuickLabsPlatformDialog()
+{
+ destroy();
+}
+
+QPlatformDialogHelper *QQuickLabsPlatformDialog::handle() const
+{
+ return m_handle;
+}
+
+/*!
+ \qmldefault
+ \qmlproperty list<QtObject> Qt.labs.platform::Dialog::data
+
+ This default property holds the list of all objects declared as children of
+ the dialog.
+*/
+QQmlListProperty<QObject> QQuickLabsPlatformDialog::data()
+{
+ return QQmlListProperty<QObject>(this, &m_data);
+}
+
+/*!
+ \qmlproperty Window Qt.labs.platform::Dialog::parentWindow
+
+ This property holds the parent window of the dialog.
+
+ Unless explicitly set, the window is automatically resolved by iterating
+ the QML parent objects until a \l Window or an \l Item that has a window
+ is found.
+*/
+QWindow *QQuickLabsPlatformDialog::parentWindow() const
+{
+ return m_parentWindow;
+}
+
+void QQuickLabsPlatformDialog::setParentWindow(QWindow *window)
+{
+ if (m_parentWindow == window)
+ return;
+
+ m_parentWindow = window;
+ emit parentWindowChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::Dialog::title
+
+ This property holds the title of the dialog.
+*/
+QString QQuickLabsPlatformDialog::title() const
+{
+ return m_title;
+}
+
+void QQuickLabsPlatformDialog::setTitle(const QString &title)
+{
+ if (m_title == title)
+ return;
+
+ m_title = title;
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty Qt::WindowFlags Qt.labs.platform::Dialog::flags
+
+ This property holds the window flags of the dialog. The default value is \c Qt.Dialog.
+*/
+Qt::WindowFlags QQuickLabsPlatformDialog::flags() const
+{
+ return m_flags;
+}
+
+void QQuickLabsPlatformDialog::setFlags(Qt::WindowFlags flags)
+{
+ if (m_flags == flags)
+ return;
+
+ m_flags = flags;
+ emit flagsChanged();
+}
+
+/*!
+ \qmlproperty Qt::WindowModality Qt.labs.platform::Dialog::modality
+
+ This property holds the modality of the dialog. The default value is \c Qt.WindowModal.
+
+ Available values:
+ \value Qt.NonModal The dialog is not modal and does not block input to other windows.
+ \value Qt.WindowModal The dialog is modal to a single window hierarchy and blocks input to its parent window, all grandparent windows, and all siblings of its parent and grandparent windows.
+ \value Qt.ApplicationModal The dialog is modal to the application and blocks input to all windows.
+*/
+Qt::WindowModality QQuickLabsPlatformDialog::modality() const
+{
+ return m_modality;
+}
+
+void QQuickLabsPlatformDialog::setModality(Qt::WindowModality modality)
+{
+ if (m_modality == modality)
+ return;
+
+ m_modality = modality;
+ emit modalityChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Dialog::visible
+
+ This property holds the visibility of the dialog. The default value is \c false.
+
+ \sa open(), close()
+*/
+bool QQuickLabsPlatformDialog::isVisible() const
+{
+ return m_handle && m_visible;
+}
+
+void QQuickLabsPlatformDialog::setVisible(bool visible)
+{
+ if (visible)
+ open();
+ else
+ close();
+}
+
+/*!
+ \qmlproperty int Qt.labs.platform::Dialog::result
+
+ This property holds the result code.
+
+ Standard result codes:
+ \value Dialog.Accepted
+ \value Dialog.Rejected
+
+ \note MessageDialog sets the result to the value of the clicked standard
+ button instead of using the standard result codes.
+*/
+int QQuickLabsPlatformDialog::result() const
+{
+ return m_result;
+}
+
+void QQuickLabsPlatformDialog::setResult(int result)
+{
+ if (m_result == result)
+ return;
+
+ m_result = result;
+ emit resultChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Dialog::open()
+
+ Opens the dialog.
+
+ \sa visible, close()
+*/
+void QQuickLabsPlatformDialog::open()
+{
+ if (m_visible || !create())
+ return;
+
+ onShow(m_handle);
+ m_visible = m_handle->show(m_flags, m_modality, m_parentWindow);
+ if (m_visible)
+ emit visibleChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Dialog::close()
+
+ Closes the dialog.
+
+ \sa visible, open()
+*/
+void QQuickLabsPlatformDialog::close()
+{
+ if (!m_handle || !m_visible)
+ return;
+
+ onHide(m_handle);
+ m_handle->hide();
+ m_visible = false;
+ emit visibleChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Dialog::accept()
+
+ Closes the dialog and emits the \l accepted() signal.
+
+ \sa reject()
+*/
+void QQuickLabsPlatformDialog::accept()
+{
+ done(Accepted);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Dialog::reject()
+
+ Closes the dialog and emits the \l rejected() signal.
+
+ \sa accept()
+*/
+void QQuickLabsPlatformDialog::reject()
+{
+ done(Rejected);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Dialog::done(int result)
+
+ Closes the dialog and sets the \a result.
+
+ \sa accept(), reject(), result
+*/
+void QQuickLabsPlatformDialog::done(int result)
+{
+ close();
+ setResult(result);
+
+ if (result == Accepted)
+ emit accepted();
+ else if (result == Rejected)
+ emit rejected();
+}
+
+void QQuickLabsPlatformDialog::classBegin()
+{
+}
+
+void QQuickLabsPlatformDialog::componentComplete()
+{
+ m_complete = true;
+ if (!m_parentWindow)
+ setParentWindow(findParentWindow());
+}
+
+static const char *qmlTypeName(const QObject *object)
+{
+ return object->metaObject()->className() + qstrlen("QQuickLabsPlatform");
+}
+
+bool QQuickLabsPlatformDialog::create()
+{
+ if (!m_handle) {
+ if (useNativeDialog())
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformDialogHelper(m_type);
+ if (!m_handle)
+ m_handle = QWidgetPlatform::createDialog(m_type, this);
+ qCDebug(qtLabsPlatformDialogs) << qmlTypeName(this) << "->" << m_handle;
+ if (m_handle) {
+ onCreate(m_handle);
+ connect(m_handle, &QPlatformDialogHelper::accept, this, &QQuickLabsPlatformDialog::accept);
+ connect(m_handle, &QPlatformDialogHelper::reject, this, &QQuickLabsPlatformDialog::reject);
+ }
+ }
+ return m_handle;
+}
+
+void QQuickLabsPlatformDialog::destroy()
+{
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+bool QQuickLabsPlatformDialog::useNativeDialog() const
+{
+ return !QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)
+ && QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(m_type);
+}
+
+void QQuickLabsPlatformDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+void QQuickLabsPlatformDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+void QQuickLabsPlatformDialog::onHide(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+QWindow *QQuickLabsPlatformDialog::findParentWindow() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformdialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformdialog_p.h b/src/labs/platform/qquicklabsplatformdialog_p.h
new file mode 100644
index 0000000000..802a846106
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformdialog_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMDIALOG_P_H
+#define QQUICKLABSPLATFORMDIALOG_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 <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QPlatformDialogHelper;
+
+class QQuickLabsPlatformDialog : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QWindow *parentWindow READ parentWindow WRITE setParentWindow NOTIFY parentWindowChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(Qt::WindowFlags flags READ flags WRITE setFlags NOTIFY flagsChanged FINAL)
+ Q_PROPERTY(Qt::WindowModality modality READ modality WRITE setModality NOTIFY modalityChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(int result READ result WRITE setResult NOTIFY resultChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ explicit QQuickLabsPlatformDialog(QPlatformTheme::DialogType type, QObject *parent = nullptr);
+ ~QQuickLabsPlatformDialog();
+
+ QPlatformDialogHelper *handle() const;
+
+ QQmlListProperty<QObject> data();
+
+ QWindow *parentWindow() const;
+ void setParentWindow(QWindow *window);
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ Qt::WindowFlags flags() const;
+ void setFlags(Qt::WindowFlags flags);
+
+ Qt::WindowModality modality() const;
+ void setModality(Qt::WindowModality modality);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ enum StandardCode { Rejected, Accepted };
+ Q_ENUM(StandardCode)
+
+ int result() const;
+ void setResult(int result);
+
+public Q_SLOTS:
+ void open();
+ void close();
+ virtual void accept();
+ virtual void reject();
+ virtual void done(int result);
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+ void parentWindowChanged();
+ void titleChanged();
+ void flagsChanged();
+ void modalityChanged();
+ void visibleChanged();
+ void resultChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ bool create();
+ void destroy();
+
+ virtual bool useNativeDialog() const;
+ virtual void onCreate(QPlatformDialogHelper *dialog);
+ virtual void onShow(QPlatformDialogHelper *dialog);
+ virtual void onHide(QPlatformDialogHelper *dialog);
+
+ QWindow *findParentWindow() const;
+
+private:
+ bool m_visible;
+ bool m_complete;
+ int m_result;
+ QWindow *m_parentWindow;
+ QString m_title;
+ Qt::WindowFlags m_flags;
+ Qt::WindowModality m_modality;
+ QPlatformTheme::DialogType m_type;
+ QList<QObject *> m_data;
+ QPlatformDialogHelper *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformDialog)
+
+#endif // QQUICKLABSPLATFORMDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformfiledialog.cpp b/src/labs/platform/qquicklabsplatformfiledialog.cpp
new file mode 100644
index 0000000000..82da455ef4
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfiledialog.cpp
@@ -0,0 +1,669 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformfiledialog_p.h"
+
+#include <QtCore/qlist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FileDialog
+ \inherits Dialog
+//! \instantiates QQuickLabsPlatformFileDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native file dialog.
+
+ The FileDialog type provides a QML API for native platform file dialogs.
+
+ \image qtlabsplatform-filedialog-gtk.png
+
+ To show a file dialog, construct an instance of FileDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentFile
+ or \l currentFiles properties can be used to determine the currently
+ selected file(s) in the dialog. The \l file and \l files properties
+ are updated only after the final selection has been made by accepting
+ the dialog.
+
+ \code
+ MenuItem {
+ text: "Open..."
+ onTriggered: fileDialog.open()
+ }
+
+ FileDialog {
+ id: fileDialog
+ currentFile: document.source
+ folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
+ }
+
+ MyDocument {
+ id: document
+ source: fileDialog.file
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform file dialog is currently available on the following platforms:
+
+ \list
+ \li iOS
+ \li Linux (when running with the GTK+ platform theme)
+ \li macOS
+ \li Windows
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+
+ \sa FolderDialog, StandardPaths
+*/
+
+QQuickLabsPlatformFileDialog::QQuickLabsPlatformFileDialog(QObject *parent)
+ : QQuickLabsPlatformDialog(QPlatformTheme::FileDialog, parent),
+ m_fileMode(OpenFile),
+ m_options(QFileDialogOptions::create()),
+ m_selectedNameFilter(nullptr)
+{
+ m_options->setFileMode(QFileDialogOptions::ExistingFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::FileDialog::fileMode
+
+ This property holds the mode of the dialog.
+
+ Available values:
+ \value FileDialog.OpenFile The dialog is used to select an existing file (default).
+ \value FileDialog.OpenFiles The dialog is used to select multiple existing files.
+ \value FileDialog.SaveFile The dialog is used to select any file. The file does not have to exist.
+*/
+QQuickLabsPlatformFileDialog::FileMode QQuickLabsPlatformFileDialog::fileMode() const
+{
+ return m_fileMode;
+}
+
+void QQuickLabsPlatformFileDialog::setFileMode(FileMode mode)
+{
+ if (mode == m_fileMode)
+ return;
+
+ switch (mode) {
+ case OpenFile:
+ m_options->setFileMode(QFileDialogOptions::ExistingFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+ break;
+ case OpenFiles:
+ m_options->setFileMode(QFileDialogOptions::ExistingFiles);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+ break;
+ case SaveFile:
+ m_options->setFileMode(QFileDialogOptions::AnyFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptSave);
+ break;
+ default:
+ break;
+ }
+
+ m_fileMode = mode;
+ emit fileModeChanged();
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::FileDialog::file
+
+ This property holds the final accepted file.
+
+ Unlike the \l currentFile property, the \c file property is not updated
+ while the user is selecting files in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol OK
+ to accept a file. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentFile, {Dialog::}{accepted()}
+*/
+QUrl QQuickLabsPlatformFileDialog::file() const
+{
+ return addDefaultSuffix(m_files.value(0));
+}
+
+void QQuickLabsPlatformFileDialog::setFile(const QUrl &file)
+{
+ setFiles(QList<QUrl>() << file);
+}
+
+/*!
+ \qmlproperty list<url> Qt.labs.platform::FileDialog::files
+
+ This property holds the final accepted files.
+
+ Unlike the \l currentFiles property, the \c files property is not updated
+ while the user is selecting files in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol OK
+ to accept files. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentFiles, {Dialog::}{accepted()}
+*/
+QList<QUrl> QQuickLabsPlatformFileDialog::files() const
+{
+ return addDefaultSuffixes(m_files);
+}
+
+void QQuickLabsPlatformFileDialog::setFiles(const QList<QUrl> &files)
+{
+ if (m_files == files)
+ return;
+
+ bool firstChanged = m_files.value(0) != files.value(0);
+ m_files = files;
+ if (firstChanged)
+ emit fileChanged();
+ emit filesChanged();
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::FileDialog::currentFile
+
+ This property holds the currently selected file in the dialog.
+
+ Unlike the \l file property, the \c currentFile property is updated
+ while the user is selecting files in the dialog, even before the final
+ selection has been made.
+
+ \sa file, currentFiles
+*/
+QUrl QQuickLabsPlatformFileDialog::currentFile() const
+{
+ return currentFiles().value(0);
+}
+
+void QQuickLabsPlatformFileDialog::setCurrentFile(const QUrl &file)
+{
+ setCurrentFiles(QList<QUrl>() << file);
+}
+
+/*!
+ \qmlproperty list<url> Qt.labs.platform::FileDialog::currentFiles
+
+ This property holds the currently selected files in the dialog.
+
+ Unlike the \l files property, the \c currentFiles property is updated
+ while the user is selecting files in the dialog, even before the final
+ selection has been made.
+
+ \sa files, currentFile
+*/
+QList<QUrl> QQuickLabsPlatformFileDialog::currentFiles() const
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ return fileDialog->selectedFiles();
+ return m_options->initiallySelectedFiles();
+}
+
+void QQuickLabsPlatformFileDialog::setCurrentFiles(const QList<QUrl> &files)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
+ for (const QUrl &file : files)
+ fileDialog->selectFile(file);
+ }
+ m_options->setInitiallySelectedFiles(files);
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::FileDialog::folder
+
+ This property holds the folder where files are selected.
+ For selecting a folder, use FolderDialog instead.
+
+ \sa FolderDialog
+*/
+QUrl QQuickLabsPlatformFileDialog::folder() const
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ return fileDialog->directory();
+ return m_options->initialDirectory();
+}
+
+void QQuickLabsPlatformFileDialog::setFolder(const QUrl &folder)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ fileDialog->setDirectory(folder);
+ m_options->setInitialDirectory(folder);
+}
+
+/*!
+ \qmlproperty flags Qt.labs.platform::FileDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value FileDialog.DontResolveSymlinks Don't resolve symlinks in the file dialog. By default symlinks are resolved.
+ \value FileDialog.DontConfirmOverwrite Don't ask for confirmation if an existing file is selected. By default confirmation is requested.
+ \value FileDialog.ReadOnly Indicates that the dialog doesn't allow creating directories.
+ \value FileDialog.HideNameFilterDetails Indicates if the file name filter details are hidden or not.
+*/
+QFileDialogOptions::FileDialogOptions QQuickLabsPlatformFileDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickLabsPlatformFileDialog::setOptions(QFileDialogOptions::FileDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+void QQuickLabsPlatformFileDialog::resetOptions()
+{
+ setOptions({});
+}
+
+/*!
+ \qmlproperty list<string> Qt.labs.platform::FileDialog::nameFilters
+
+ This property holds the filters that restrict the types of files that
+ can be selected.
+
+ \code
+ FileDialog {
+ nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)"]
+ }
+ \endcode
+
+ \note \b{*.*} is not a portable filter, because the historical assumption
+ that the file extension determines the file type is not consistent on every
+ operating system. It is possible to have a file with no dot in its name (for
+ example, \c Makefile). In a native Windows file dialog, \b{*.*} will match
+ such files, while in other types of file dialogs it may not. So it is better
+ to use \b{*} if you mean to select any file.
+
+ \sa selectedNameFilter
+*/
+QStringList QQuickLabsPlatformFileDialog::nameFilters() const
+{
+ return m_options->nameFilters();
+}
+
+void QQuickLabsPlatformFileDialog::setNameFilters(const QStringList &filters)
+{
+ if (filters == m_options->nameFilters())
+ return;
+
+ m_options->setNameFilters(filters);
+ if (m_selectedNameFilter) {
+ int index = m_selectedNameFilter->index();
+ if (index < 0 || index >= filters.count())
+ index = 0;
+ m_selectedNameFilter->update(filters.value(index));
+ }
+ emit nameFiltersChanged();
+}
+
+void QQuickLabsPlatformFileDialog::resetNameFilters()
+{
+ setNameFilters(QStringList());
+}
+
+/*!
+ \qmlproperty int Qt.labs.platform::FileDialog::selectedNameFilter.index
+ \qmlproperty string Qt.labs.platform::FileDialog::selectedNameFilter.name
+ \qmlproperty list<string> Qt.labs.platform::FileDialog::selectedNameFilter.extensions
+
+ These properties hold the currently selected name filter.
+
+ \table
+ \header
+ \li Name
+ \li Description
+ \row
+ \li \b index : int
+ \li This property determines which \l {nameFilters}{name filter} is selected.
+ The specified filter is selected when the dialog is opened. The value is
+ updated when the user selects another filter.
+ \row
+ \li [read-only] \b name : string
+ \li This property holds the name of the selected filter. In the
+ example below, the name of the first filter is \c {"Text files"}
+ and the second is \c {"HTML files"}.
+ \row
+ \li [read-only] \b extensions : list<string>
+ \li This property holds the list of extensions of the selected filter.
+ In the example below, the list of extensions of the first filter is
+ \c {["txt"]} and the second is \c {["html", "htm"]}.
+ \endtable
+
+ \code
+ FileDialog {
+ id: fileDialog
+ selectedNameFilter.index: 1
+ nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)"]
+ }
+
+ MyDocument {
+ id: document
+ fileType: fileDialog.selectedNameFilter.extensions[0]
+ }
+ \endcode
+
+ \sa nameFilters
+*/
+QQuickLabsPlatformFileNameFilter *QQuickLabsPlatformFileDialog::selectedNameFilter() const
+{
+ if (!m_selectedNameFilter) {
+ QQuickLabsPlatformFileDialog *that = const_cast<QQuickLabsPlatformFileDialog *>(this);
+ m_selectedNameFilter = new QQuickLabsPlatformFileNameFilter(that);
+ m_selectedNameFilter->setOptions(m_options);
+ }
+ return m_selectedNameFilter;
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::FileDialog::defaultSuffix
+
+ This property holds a suffix that is added to selected files that have
+ no suffix specified. The suffix is typically used to indicate the file
+ type (e.g. "txt" indicates a text file).
+
+ If the first character is a dot ('.'), it is removed.
+*/
+QString QQuickLabsPlatformFileDialog::defaultSuffix() const
+{
+ return m_options->defaultSuffix();
+}
+
+void QQuickLabsPlatformFileDialog::setDefaultSuffix(const QString &suffix)
+{
+ if (suffix == m_options->defaultSuffix())
+ return;
+
+ m_options->setDefaultSuffix(suffix);
+ emit defaultSuffixChanged();
+}
+
+void QQuickLabsPlatformFileDialog::resetDefaultSuffix()
+{
+ setDefaultSuffix(QString());
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::FileDialog::acceptLabel
+
+ This property holds the label text shown on the button that accepts the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Open or \uicontrol Save depending on which
+ \l fileMode the dialog is used in.
+
+ The default value is an empty string.
+
+ \sa rejectLabel
+*/
+QString QQuickLabsPlatformFileDialog::acceptLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Accept);
+}
+
+void QQuickLabsPlatformFileDialog::setAcceptLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Accept))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Accept, label);
+ emit acceptLabelChanged();
+}
+
+void QQuickLabsPlatformFileDialog::resetAcceptLabel()
+{
+ setAcceptLabel(QString());
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::FileDialog::rejectLabel
+
+ This property holds the label text shown on the button that rejects the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Cancel.
+
+ The default value is an empty string.
+
+ \sa acceptLabel
+*/
+QString QQuickLabsPlatformFileDialog::rejectLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Reject);
+}
+
+void QQuickLabsPlatformFileDialog::setRejectLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Reject))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Reject, label);
+ emit rejectLabelChanged();
+}
+
+void QQuickLabsPlatformFileDialog::resetRejectLabel()
+{
+ setRejectLabel(QString());
+}
+
+bool QQuickLabsPlatformFileDialog::useNativeDialog() const
+{
+ return QQuickLabsPlatformDialog::useNativeDialog()
+ && !m_options->testOption(QFileDialogOptions::DontUseNativeDialog);
+}
+
+void QQuickLabsPlatformFileDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ // TODO: emit currentFileChanged only when the first entry in currentFiles changes
+ connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickLabsPlatformFileDialog::currentFileChanged);
+ connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickLabsPlatformFileDialog::currentFilesChanged);
+ connect(fileDialog, &QPlatformFileDialogHelper::directoryEntered, this, &QQuickLabsPlatformFileDialog::folderChanged);
+ fileDialog->setOptions(m_options);
+ }
+}
+
+void QQuickLabsPlatformFileDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ fileDialog->setOptions(m_options); // setOptions only assigns a member and isn't virtual
+ if (m_firstShow && m_options->initialDirectory().isValid())
+ fileDialog->setDirectory(m_options->initialDirectory());
+ if (m_selectedNameFilter) {
+ const int index = m_selectedNameFilter->index();
+ const QString filter = m_options->nameFilters().value(index);
+ m_options->setInitiallySelectedNameFilter(filter);
+ fileDialog->selectNameFilter(filter);
+ connect(fileDialog, &QPlatformFileDialogHelper::filterSelected, m_selectedNameFilter, &QQuickLabsPlatformFileNameFilter::update);
+ }
+ }
+ if (m_firstShow)
+ m_firstShow = false;
+}
+
+void QQuickLabsPlatformFileDialog::onHide(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ if (m_selectedNameFilter)
+ disconnect(fileDialog, &QPlatformFileDialogHelper::filterSelected, m_selectedNameFilter, &QQuickLabsPlatformFileNameFilter::update);
+ }
+}
+
+void QQuickLabsPlatformFileDialog::accept()
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ setFiles(fileDialog->selectedFiles());
+ QQuickLabsPlatformDialog::accept();
+}
+
+QUrl QQuickLabsPlatformFileDialog::addDefaultSuffix(const QUrl &file) const
+{
+ QUrl url = file;
+ const QString path = url.path();
+ const QString suffix = m_options->defaultSuffix();
+ // Urls with "content" scheme do not require suffixes. Such schemes are
+ // used on Android.
+ const bool isContentScheme = url.scheme() == u"content"_qs;
+ if (!isContentScheme && !suffix.isEmpty() && !path.endsWith(QLatin1Char('/'))
+ && path.lastIndexOf(QLatin1Char('.')) == -1) {
+ url.setPath(path + QLatin1Char('.') + suffix);
+ }
+ return url;
+}
+
+QList<QUrl> QQuickLabsPlatformFileDialog::addDefaultSuffixes(const QList<QUrl> &files) const
+{
+ QList<QUrl> urls;
+ urls.reserve(files.size());
+ for (const QUrl &file : files)
+ urls += addDefaultSuffix(file);
+ return urls;
+}
+
+QQuickLabsPlatformFileNameFilter::QQuickLabsPlatformFileNameFilter(QObject *parent)
+ : QObject(parent), m_index(-1)
+{
+}
+
+int QQuickLabsPlatformFileNameFilter::index() const
+{
+ return m_index;
+}
+
+void QQuickLabsPlatformFileNameFilter::setIndex(int index)
+{
+ if (m_index == index)
+ return;
+
+ m_index = index;
+ emit indexChanged(index);
+}
+
+QString QQuickLabsPlatformFileNameFilter::name() const
+{
+ return m_name;
+}
+
+QStringList QQuickLabsPlatformFileNameFilter::extensions() const
+{
+ return m_extensions;
+}
+
+QSharedPointer<QFileDialogOptions> QQuickLabsPlatformFileNameFilter::options() const
+{
+ return m_options;
+}
+
+void QQuickLabsPlatformFileNameFilter::setOptions(const QSharedPointer<QFileDialogOptions> &options)
+{
+ m_options = options;
+}
+
+static QString extractName(const QString &filter)
+{
+ return filter.left(filter.indexOf(QLatin1Char('(')) - 1);
+}
+
+static QString extractExtension(QStringView filter)
+{
+ return filter.mid(filter.indexOf(QLatin1Char('.')) + 1).toString();
+}
+
+static QStringList extractExtensions(QStringView filter)
+{
+ QStringList extensions;
+ const int from = filter.indexOf(QLatin1Char('('));
+ const int to = filter.lastIndexOf(QLatin1Char(')')) - 1;
+ if (from >= 0 && from < to) {
+ const QStringView ref = filter.mid(from + 1, to - from);
+ const QList<QStringView> exts = ref.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ for (const QStringView &ref : exts)
+ extensions += extractExtension(ref);
+ }
+
+ return extensions;
+}
+
+void QQuickLabsPlatformFileNameFilter::update(const QString &filter)
+{
+ const QStringList filters = nameFilters();
+
+ const int oldIndex = m_index;
+ const QString oldName = m_name;
+ const QStringList oldExtensions = m_extensions;
+
+ m_index = filters.indexOf(filter);
+ m_name = extractName(filter);
+ m_extensions = extractExtensions(filter);
+
+ if (oldIndex != m_index)
+ emit indexChanged(m_index);
+ if (oldName != m_name)
+ emit nameChanged(m_name);
+ if (oldExtensions != m_extensions)
+ emit extensionsChanged(m_extensions);
+}
+
+QStringList QQuickLabsPlatformFileNameFilter::nameFilters() const
+{
+ return m_options ? m_options->nameFilters() : QStringList();
+}
+
+QString QQuickLabsPlatformFileNameFilter::nameFilter(int index) const
+{
+ return m_options ? m_options->nameFilters().value(index) : QString();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformfiledialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformfiledialog_p.h b/src/labs/platform/qquicklabsplatformfiledialog_p.h
new file mode 100644
index 0000000000..782b598047
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfiledialog_p.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMFILEDIALOG_P_H
+#define QQUICKLABSPLATFORMFILEDIALOG_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 "qquicklabsplatformdialog_p.h"
+#include <QtCore/qurl.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformFileNameFilter;
+
+class QQuickLabsPlatformFileDialog : public QQuickLabsPlatformDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode NOTIFY fileModeChanged FINAL)
+ Q_PROPERTY(QUrl file READ file WRITE setFile NOTIFY fileChanged FINAL)
+ Q_PROPERTY(QList<QUrl> files READ files WRITE setFiles NOTIFY filesChanged FINAL)
+ Q_PROPERTY(QUrl currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged FINAL)
+ Q_PROPERTY(QList<QUrl> currentFiles READ currentFiles WRITE setCurrentFiles NOTIFY currentFilesChanged FINAL)
+ Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged FINAL)
+ Q_PROPERTY(QFileDialogOptions::FileDialogOptions options READ options WRITE setOptions RESET resetOptions NOTIFY optionsChanged FINAL)
+ Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters RESET resetNameFilters NOTIFY nameFiltersChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformFileNameFilter *selectedNameFilter READ selectedNameFilter CONSTANT)
+ Q_PROPERTY(QString defaultSuffix READ defaultSuffix WRITE setDefaultSuffix RESET resetDefaultSuffix NOTIFY defaultSuffixChanged FINAL)
+ Q_PROPERTY(QString acceptLabel READ acceptLabel WRITE setAcceptLabel RESET resetAcceptLabel NOTIFY acceptLabelChanged FINAL)
+ Q_PROPERTY(QString rejectLabel READ rejectLabel WRITE setRejectLabel RESET resetRejectLabel NOTIFY rejectLabelChanged FINAL)
+ Q_FLAGS(QFileDialogOptions::FileDialogOptions)
+
+public:
+ explicit QQuickLabsPlatformFileDialog(QObject *parent = nullptr);
+
+ enum FileMode {
+ OpenFile,
+ OpenFiles,
+ SaveFile
+ };
+ Q_ENUM(FileMode)
+
+ FileMode fileMode() const;
+ void setFileMode(FileMode fileMode);
+
+ QUrl file() const;
+ void setFile(const QUrl &file);
+
+ QList<QUrl> files() const;
+ void setFiles(const QList<QUrl> &files);
+
+ QUrl currentFile() const;
+ void setCurrentFile(const QUrl &file);
+
+ QList<QUrl> currentFiles() const;
+ void setCurrentFiles(const QList<QUrl> &files);
+
+ QUrl folder() const;
+ void setFolder(const QUrl &folder);
+
+ QFileDialogOptions::FileDialogOptions options() const;
+ void setOptions(QFileDialogOptions::FileDialogOptions options);
+ void resetOptions();
+
+ QStringList nameFilters() const;
+ void setNameFilters(const QStringList &filters);
+ void resetNameFilters();
+
+ QQuickLabsPlatformFileNameFilter *selectedNameFilter() const;
+
+ QString defaultSuffix() const;
+ void setDefaultSuffix(const QString &suffix);
+ void resetDefaultSuffix();
+
+ QString acceptLabel() const;
+ void setAcceptLabel(const QString &label);
+ void resetAcceptLabel();
+
+ QString rejectLabel() const;
+ void setRejectLabel(const QString &label);
+ void resetRejectLabel();
+
+Q_SIGNALS:
+ void fileModeChanged();
+ void fileChanged();
+ void filesChanged();
+ void currentFileChanged();
+ void currentFilesChanged();
+ void folderChanged();
+ void optionsChanged();
+ void nameFiltersChanged();
+ void defaultSuffixChanged();
+ void acceptLabelChanged();
+ void rejectLabelChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void onHide(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QUrl addDefaultSuffix(const QUrl &file) const;
+ QList<QUrl> addDefaultSuffixes(const QList<QUrl> &files) const;
+
+ FileMode m_fileMode;
+ QList<QUrl> m_files;
+ bool m_firstShow = true;
+ QSharedPointer<QFileDialogOptions> m_options;
+ mutable QQuickLabsPlatformFileNameFilter *m_selectedNameFilter;
+};
+
+class QQuickLabsPlatformFileNameFilter : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged FINAL)
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged FINAL)
+ Q_PROPERTY(QStringList extensions READ extensions NOTIFY extensionsChanged FINAL)
+
+public:
+ explicit QQuickLabsPlatformFileNameFilter(QObject *parent = nullptr);
+
+ int index() const;
+ void setIndex(int index);
+
+ QString name() const;
+ QStringList extensions() const;
+
+ QSharedPointer<QFileDialogOptions> options() const;
+ void setOptions(const QSharedPointer<QFileDialogOptions> &options);
+
+ void update(const QString &filter);
+
+Q_SIGNALS:
+ void indexChanged(int index);
+ void nameChanged(const QString &name);
+ void extensionsChanged(const QStringList &extensions);
+
+private:
+ QStringList nameFilters() const;
+ QString nameFilter(int index) const;
+
+ int m_index;
+ QString m_name;
+ QStringList m_extensions;
+ QSharedPointer<QFileDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformFileDialog)
+
+#endif // QQUICKLABSPLATFORMFILEDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformfolderdialog.cpp b/src/labs/platform/qquicklabsplatformfolderdialog.cpp
new file mode 100644
index 0000000000..83e615e5b8
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfolderdialog.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformfolderdialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FolderDialog
+ \inherits Dialog
+//! \instantiates QQuickLabsPlatformFolderDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native folder dialog.
+
+ The FolderDialog type provides a QML API for native platform folder dialogs.
+
+ \image qtlabsplatform-folderdialog-gtk.png
+
+ To show a folder dialog, construct an instance of FolderDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentFolder
+ property can be used to determine the currently selected folder in the
+ dialog. The \l folder property is updated only after the final selection
+ has been made by accepting the dialog.
+
+ \code
+ MenuItem {
+ text: "Open..."
+ onTriggered: folderDialog.open()
+ }
+
+ FolderDialog {
+ id: folderDialog
+ currentFolder: viewer.folder
+ folder: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
+ }
+
+ MyViewer {
+ id: viewer
+ folder: folderDialog.folder
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform folder dialog is currently available on the following platforms:
+
+ \list
+ \li iOS
+ \li Linux (when running with the GTK+ platform theme)
+ \li macOS
+ \li Windows
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+
+ \sa FileDialog, StandardPaths
+*/
+
+QQuickLabsPlatformFolderDialog::QQuickLabsPlatformFolderDialog(QObject *parent)
+ : QQuickLabsPlatformDialog(QPlatformTheme::FileDialog, parent),
+ m_options(QFileDialogOptions::create())
+{
+ m_options->setFileMode(QFileDialogOptions::Directory);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::FolderDialog::folder
+
+ This property holds the final accepted folder.
+
+ Unlike the \l currentFolder property, the \c folder property is not updated
+ while the user is selecting folders in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol OK
+ to accept a folder. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentFolder, {Dialog::}{accepted()}
+*/
+QUrl QQuickLabsPlatformFolderDialog::folder() const
+{
+ return m_folder;
+}
+
+void QQuickLabsPlatformFolderDialog::setFolder(const QUrl &folder)
+{
+ if (m_folder == folder)
+ return;
+
+ m_folder = folder;
+ emit folderChanged();
+}
+
+/*!
+ \qmlproperty url Qt.labs.platform::FolderDialog::currentFolder
+
+ This property holds the currently selected folder in the dialog.
+
+ Unlike the \l folder property, the \c currentFolder property is updated
+ while the user is selecting folders in the dialog, even before the final
+ selection has been made.
+
+ \sa folder
+*/
+QUrl QQuickLabsPlatformFolderDialog::currentFolder() const
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
+ const QList<QUrl> selectedFiles = fileDialog->selectedFiles();
+ if (!selectedFiles.isEmpty())
+ return selectedFiles.first();
+ return fileDialog->directory();
+ }
+ return m_options->initialDirectory();
+}
+
+void QQuickLabsPlatformFolderDialog::setCurrentFolder(const QUrl &folder)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ fileDialog->setDirectory(folder);
+ m_options->setInitialDirectory(folder);
+}
+
+/*!
+ \qmlproperty flags Qt.labs.platform::FolderDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value FolderDialog.ShowDirsOnly Only show directories in the folder dialog. By default both folders and directories are shown.
+ \value FolderDialog.DontResolveSymlinks Don't resolve symlinks in the folder dialog. By default symlinks are resolved.
+ \value FolderDialog.ReadOnly Indicates that the dialog doesn't allow creating directories.
+*/
+QFileDialogOptions::FileDialogOptions QQuickLabsPlatformFolderDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickLabsPlatformFolderDialog::setOptions(QFileDialogOptions::FileDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+void QQuickLabsPlatformFolderDialog::resetOptions()
+{
+ setOptions({});
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::FolderDialog::acceptLabel
+
+ This property holds the label text shown on the button that accepts the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Open.
+
+ The default value is an empty string.
+
+ \sa rejectLabel
+*/
+QString QQuickLabsPlatformFolderDialog::acceptLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Accept);
+}
+
+void QQuickLabsPlatformFolderDialog::setAcceptLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Accept))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Accept, label);
+ emit acceptLabelChanged();
+}
+
+void QQuickLabsPlatformFolderDialog::resetAcceptLabel()
+{
+ setAcceptLabel(QString());
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::FolderDialog::rejectLabel
+
+ This property holds the label text shown on the button that rejects the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Cancel.
+
+ The default value is an empty string.
+
+ \sa acceptLabel
+*/
+QString QQuickLabsPlatformFolderDialog::rejectLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Reject);
+}
+
+void QQuickLabsPlatformFolderDialog::setRejectLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Reject))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Reject, label);
+ emit rejectLabelChanged();
+}
+
+void QQuickLabsPlatformFolderDialog::resetRejectLabel()
+{
+ setRejectLabel(QString());
+}
+
+bool QQuickLabsPlatformFolderDialog::useNativeDialog() const
+{
+ return QQuickLabsPlatformDialog::useNativeDialog()
+ && !m_options->testOption(QFileDialogOptions::DontUseNativeDialog);
+}
+
+void QQuickLabsPlatformFolderDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickLabsPlatformFolderDialog::currentFolderChanged);
+ fileDialog->setOptions(m_options);
+ }
+}
+
+void QQuickLabsPlatformFolderDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog))
+ fileDialog->setOptions(m_options);
+}
+
+void QQuickLabsPlatformFolderDialog::accept()
+{
+ setFolder(currentFolder());
+ QQuickLabsPlatformDialog::accept();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformfolderdialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformfolderdialog_p.h b/src/labs/platform/qquicklabsplatformfolderdialog_p.h
new file mode 100644
index 0000000000..21ee3c6c43
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfolderdialog_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMFOLDERDIALOG_P_H
+#define QQUICKLABSPLATFORMFOLDERDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This folder is not part of the Qt API. It exists purely as an
+// implementation detail. This header folder may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquicklabsplatformdialog_p.h"
+#include <QtCore/qurl.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformFolderDialog : public QQuickLabsPlatformDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl folder READ folder WRITE setFolder NOTIFY folderChanged FINAL)
+ Q_PROPERTY(QUrl currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged FINAL)
+ Q_PROPERTY(QFileDialogOptions::FileDialogOptions options READ options WRITE setOptions RESET resetOptions NOTIFY optionsChanged FINAL)
+ Q_PROPERTY(QString acceptLabel READ acceptLabel WRITE setAcceptLabel RESET resetAcceptLabel NOTIFY acceptLabelChanged FINAL)
+ Q_PROPERTY(QString rejectLabel READ rejectLabel WRITE setRejectLabel RESET resetRejectLabel NOTIFY rejectLabelChanged FINAL)
+ Q_FLAGS(QFileDialogOptions::FileDialogOptions)
+
+public:
+ explicit QQuickLabsPlatformFolderDialog(QObject *parent = nullptr);
+
+ QUrl folder() const;
+ void setFolder(const QUrl &folder);
+
+ QUrl currentFolder() const;
+ void setCurrentFolder(const QUrl &folder);
+
+ QFileDialogOptions::FileDialogOptions options() const;
+ void setOptions(QFileDialogOptions::FileDialogOptions options);
+ void resetOptions();
+
+ QString acceptLabel() const;
+ void setAcceptLabel(const QString &label);
+ void resetAcceptLabel();
+
+ QString rejectLabel() const;
+ void setRejectLabel(const QString &label);
+ void resetRejectLabel();
+
+Q_SIGNALS:
+ void folderChanged();
+ void currentFolderChanged();
+ void optionsChanged();
+ void acceptLabelChanged();
+ void rejectLabelChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QUrl m_folder;
+ QSharedPointer<QFileDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformFolderDialog)
+
+#endif // QQUICKLABSPLATFORMFOLDERDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformfontdialog.cpp b/src/labs/platform/qquicklabsplatformfontdialog.cpp
new file mode 100644
index 0000000000..a473d0f2a8
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfontdialog.cpp
@@ -0,0 +1,210 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformfontdialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FontDialog
+ \inherits Dialog
+//! \instantiates QQuickLabsPlatformFontDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native font dialog.
+
+ The FontDialog type provides a QML API for native platform font dialogs.
+
+ \image qtlabsplatform-fontdialog-gtk.png
+
+ To show a font dialog, construct an instance of FontDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentFont
+ property can be used to determine the currently selected font in the
+ dialog. The \l font property is updated only after the final selection
+ has been made by accepting the dialog.
+
+ \code
+ MenuItem {
+ text: "Font"
+ onTriggered: fontDialog.open()
+ }
+
+ FontDialog {
+ id: fontDialog
+ currentFont.family: document.font
+ }
+
+ MyDocument {
+ id: document
+ font: fontDialog.font
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform font dialog is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li Linux (when running with the GTK+ platform theme)
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+*/
+
+QQuickLabsPlatformFontDialog::QQuickLabsPlatformFontDialog(QObject *parent)
+ : QQuickLabsPlatformDialog(QPlatformTheme::FontDialog, parent),
+ m_options(QFontDialogOptions::create())
+{
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::FontDialog::font
+
+ This property holds the final accepted font.
+
+ Unlike the \l currentFont property, the \c font property is not updated
+ while the user is selecting fonts in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol OK
+ to accept a font. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentFont, {Dialog::}{accepted()}
+*/
+QFont QQuickLabsPlatformFontDialog::font() const
+{
+ return m_font;
+}
+
+void QQuickLabsPlatformFontDialog::setFont(const QFont &font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ setCurrentFont(font);
+ emit fontChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::FontDialog::currentFont
+
+ This property holds the currently selected font in the dialog.
+
+ Unlike the \l font property, the \c currentFont property is updated
+ while the user is selecting fonts in the dialog, even before the final
+ selection has been made.
+
+ \sa font
+*/
+QFont QQuickLabsPlatformFontDialog::currentFont() const
+{
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(handle()))
+ return fontDialog->currentFont();
+ return m_currentFont;
+}
+
+void QQuickLabsPlatformFontDialog::setCurrentFont(const QFont &font)
+{
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(handle()))
+ fontDialog->setCurrentFont(font);
+ m_currentFont = font;
+}
+
+/*!
+ \qmlproperty flags Qt.labs.platform::FontDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value FontDialog.ScalableFonts Show scalable fonts.
+ \value FontDialog.NonScalableFonts Show non-scalable fonts.
+ \value FontDialog.MonospacedFonts Show monospaced fonts.
+ \value FontDialog.ProportionalFonts Show proportional fonts.
+ \value FontDialog.NoButtons Don't display \uicontrol OK and \uicontrol Cancel buttons (useful for "live dialogs").
+*/
+QFontDialogOptions::FontDialogOptions QQuickLabsPlatformFontDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickLabsPlatformFontDialog::setOptions(QFontDialogOptions::FontDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+bool QQuickLabsPlatformFontDialog::useNativeDialog() const
+{
+ return QQuickLabsPlatformDialog::useNativeDialog()
+ && !m_options->testOption(QFontDialogOptions::DontUseNativeDialog);
+}
+
+void QQuickLabsPlatformFontDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(dialog)) {
+ connect(fontDialog, &QPlatformFontDialogHelper::currentFontChanged, this, &QQuickLabsPlatformFontDialog::currentFontChanged);
+ fontDialog->setOptions(m_options);
+ }
+}
+
+void QQuickLabsPlatformFontDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(dialog))
+ fontDialog->setOptions(m_options);
+}
+
+void QQuickLabsPlatformFontDialog::accept()
+{
+ setFont(currentFont());
+ QQuickLabsPlatformDialog::accept();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformfontdialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformfontdialog_p.h b/src/labs/platform/qquicklabsplatformfontdialog_p.h
new file mode 100644
index 0000000000..eb9399d998
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformfontdialog_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMFONTDIALOG_P_H
+#define QQUICKLABSPLATFORMFONTDIALOG_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 "qquicklabsplatformdialog_p.h"
+#include <QtGui/qfont.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformFontDialog : public QQuickLabsPlatformDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged FINAL)
+ Q_PROPERTY(QFontDialogOptions::FontDialogOptions options READ options WRITE setOptions NOTIFY optionsChanged FINAL)
+ Q_FLAGS(QFontDialogOptions::FontDialogOptions)
+
+public:
+ explicit QQuickLabsPlatformFontDialog(QObject *parent = nullptr);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QFont currentFont() const;
+ void setCurrentFont(const QFont &font);
+
+ QFontDialogOptions::FontDialogOptions options() const;
+ void setOptions(QFontDialogOptions::FontDialogOptions options);
+
+Q_SIGNALS:
+ void fontChanged();
+ void currentFontChanged();
+ void optionsChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QFont m_font;
+ QFont m_currentFont; // TODO: QFontDialogOptions::initialFont
+ QSharedPointer<QFontDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformFontDialog)
+
+#endif // QQUICKLABSPLATFORMFONTDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformicon.cpp b/src/labs/platform/qquicklabsplatformicon.cpp
new file mode 100644
index 0000000000..ae7c8ef10d
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformicon.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QUrl QQuickLabsPlatformIcon::source() const
+{
+ return m_source;
+}
+
+void QQuickLabsPlatformIcon::setSource(const QUrl& source)
+{
+ m_source = source;
+}
+
+QString QQuickLabsPlatformIcon::name() const
+{
+ return m_name;
+}
+
+void QQuickLabsPlatformIcon::setName(const QString& name)
+{
+ m_name = name;
+}
+
+bool QQuickLabsPlatformIcon::isMask() const
+{
+ return m_mask;
+}
+
+void QQuickLabsPlatformIcon::setMask(bool mask)
+{
+ m_mask = mask;
+}
+
+bool QQuickLabsPlatformIcon::operator==(const QQuickLabsPlatformIcon &other) const
+{
+ return m_source == other.m_source && m_name == other.m_name && m_mask == other.m_mask;
+}
+
+bool QQuickLabsPlatformIcon::operator!=(const QQuickLabsPlatformIcon &other) const
+{
+ return !(*this == other);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformicon_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformicon_p.h b/src/labs/platform/qquicklabsplatformicon_p.h
new file mode 100644
index 0000000000..eaf0c2d3df
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformicon_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMICON_P_H
+#define QQUICKLABSPLATFORMICON_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>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickLabsPlatformIcon
+{
+ Q_GADGET
+ Q_PROPERTY(QUrl source READ source WRITE setSource)
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(bool mask READ isMask WRITE setMask)
+
+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 QQuickLabsPlatformIcon &other) const;
+ bool operator!=(const QQuickLabsPlatformIcon &other) const;
+
+private:
+ bool m_mask = false;
+ QUrl m_source;
+ QString m_name;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKLABSPLATFORMICON_P_H
diff --git a/src/labs/platform/qquicklabsplatformiconloader.cpp b/src/labs/platform/qquicklabsplatformiconloader.cpp
new file mode 100644
index 0000000000..6d6deb5812
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformiconloader.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformiconloader_p.h"
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmetaobject.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickLabsPlatformIconLoader::QQuickLabsPlatformIconLoader(int slot, QObject *parent)
+ : m_parent(parent),
+ m_slot(slot),
+ m_enabled(false)
+{
+ Q_ASSERT(slot != -1 && parent);
+}
+
+bool QQuickLabsPlatformIconLoader::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickLabsPlatformIconLoader::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+ if (m_enabled)
+ loadIcon();
+}
+
+QIcon QQuickLabsPlatformIconLoader::toQIcon() const
+{
+ QIcon fallback = QPixmap::fromImage(image());
+ QIcon icon = QIcon::fromTheme(m_icon.name(), fallback);
+ icon.setIsMask(m_icon.isMask());
+ return icon;
+}
+
+QQuickLabsPlatformIcon QQuickLabsPlatformIconLoader::icon() const
+{
+ return m_icon;
+}
+
+void QQuickLabsPlatformIconLoader::setIcon(const QQuickLabsPlatformIcon& icon)
+{
+ m_icon = icon;
+ if (m_enabled)
+ loadIcon();
+}
+
+void QQuickLabsPlatformIconLoader::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/labs/platform/qquicklabsplatformiconloader_p.h b/src/labs/platform/qquicklabsplatformiconloader_p.h
new file mode 100644
index 0000000000..ed48e1cf67
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformiconloader_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMICONLOADER_P_H
+#define QQUICKLABSPLATFORMICONLOADER_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/qquickpixmapcache_p.h>
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+class QQuickLabsPlatformIconLoader : public QQuickPixmap
+{
+public:
+ QQuickLabsPlatformIconLoader(int slot, QObject *parent);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ QIcon toQIcon() const;
+
+ QQuickLabsPlatformIcon icon() const;
+ void setIcon(const QQuickLabsPlatformIcon &icon);
+
+private:
+ void loadIcon();
+
+ QObject *m_parent;
+ int m_slot;
+ bool m_enabled;
+ QQuickLabsPlatformIcon m_icon;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKLABSPLATFORMICONLOADER_P_H
diff --git a/src/labs/platform/qquicklabsplatformmenu.cpp b/src/labs/platform/qquicklabsplatformmenu.cpp
new file mode 100644
index 0000000000..e5cf45d386
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenu.cpp
@@ -0,0 +1,895 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenu_p.h"
+#include "qquicklabsplatformmenubar_p.h"
+#include "qquicklabsplatformmenuitem_p.h"
+#include "qquicklabsplatformiconloader_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qcursor.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQuick/qquickrendercontrol.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickitem.h>
+
+#include "widgets/qwidgetplatform_p.h"
+
+#if QT_CONFIG(systemtrayicon)
+#include "qquicklabsplatformsystemtrayicon_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Menu
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformMenu
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu.
+
+ The Menu type provides a QML API for native platform menu popups.
+
+ \image qtlabsplatform-menu.png
+
+ Menu can be used in a \l MenuBar, or as a stand-alone context menu.
+ The following example shows how to open a context menu on right mouse
+ click:
+
+ \code
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: zoomMenu.open()
+ }
+
+ Menu {
+ id: zoomMenu
+
+ MenuItem {
+ text: qsTr("Zoom In")
+ shortcut: StandardKey.ZoomIn
+ onTriggered: zoomIn()
+ }
+
+ MenuItem {
+ text: qsTr("Zoom Out")
+ shortcut: StandardKey.ZoomOut
+ onTriggered: zoomOut()
+ }
+ }
+ \endcode
+
+ \section2 Submenus
+
+ To create submenus, declare a Menu as a child of another Menu:
+
+ \qml
+ Menu {
+ title: qsTr("Edit")
+
+ Menu {
+ title: qsTr("Advanced")
+
+ MenuItem {
+ text: qsTr("Auto-indent Selection")
+ onTriggered: autoIndentSelection()
+ }
+
+ MenuItem {
+ text: qsTr("Rewrap Paragraph")
+ onTriggered: rewrapParagraph()
+ }
+ }
+ }
+ \endqml
+
+ \section2 Dynamically Generating Menu Items
+
+ It is possible to dynamically generate menu items. One of the easiest ways
+ to do so is with \l Instantiator. For example, to implement a
+ "Recent Files" submenu, where the items are based on a list of files stored
+ in settings, the following code could be used:
+
+ \qml
+ Menu {
+ title: qsTr("File")
+
+ Menu {
+ id: recentFilesSubMenu
+ title: qsTr("Recent Files")
+ enabled: recentFilesInstantiator.count > 0
+
+ Instantiator {
+ id: recentFilesInstantiator
+ model: settings.recentFiles
+ delegate: MenuItem {
+ text: settings.displayableFilePath(modelData)
+ onTriggered: loadFile(modelData)
+ }
+
+ onObjectAdded: recentFilesSubMenu.insertItem(index, object)
+ onObjectRemoved: recentFilesSubMenu.removeItem(object)
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: qsTr("Clear Recent Files")
+ onTriggered: settings.clearRecentFiles()
+ }
+ }
+ }
+ \endqml
+
+ \section2 Availability
+
+ A native platform menu is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li iOS
+ \li Android
+ \li Linux (only available as a stand-alone context menu when running with the GTK+ platform theme)
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+
+ \sa MenuItem, MenuSeparator, MenuBar
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToShow()
+
+ This signal is emitted when the menu is about to be shown to the user.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::Menu::aboutToHide()
+
+ This signal is emitted when the menu is about to be hidden from the user.
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformMenus)
+
+QQuickLabsPlatformMenu::QQuickLabsPlatformMenu(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_enabled(true),
+ m_visible(true),
+ m_minimumWidth(-1),
+ m_type(QPlatformMenu::DefaultMenu),
+ m_menuBar(nullptr),
+ m_parentMenu(nullptr),
+ m_systemTrayIcon(nullptr),
+ m_menuItem(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+}
+
+QQuickLabsPlatformMenu::~QQuickLabsPlatformMenu()
+{
+ if (m_menuBar)
+ m_menuBar->removeMenu(this);
+ if (m_parentMenu)
+ m_parentMenu->removeMenu(this);
+
+ unparentSubmenus();
+
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+void QQuickLabsPlatformMenu::unparentSubmenus()
+{
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ if (QQuickLabsPlatformMenu *subMenu = item->subMenu())
+ subMenu->setParentMenu(nullptr);
+ item->setMenu(nullptr);
+ }
+}
+
+QPlatformMenu *QQuickLabsPlatformMenu::handle() const
+{
+ return m_handle;
+}
+
+QPlatformMenu * QQuickLabsPlatformMenu::create()
+{
+ if (!m_handle) {
+ if (m_menuBar && m_menuBar->handle())
+ m_handle = m_menuBar->handle()->createMenu();
+ else if (m_parentMenu && m_parentMenu->handle())
+ m_handle = m_parentMenu->handle()->createSubMenu();
+#if QT_CONFIG(systemtrayicon)
+ else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+ m_handle = m_systemTrayIcon->handle()->createMenu();
+#endif
+
+ // TODO: implement ^
+ // - QCocoaMenuBar::createMenu()
+ // - QCocoaMenu::createSubMenu()
+ // - QCocoaSystemTrayIcon::createMenu()
+ if (!m_handle)
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
+
+ if (!m_handle)
+ m_handle = QWidgetPlatform::createMenu();
+
+ qCDebug(qtLabsPlatformMenus) << "Menu ->" << m_handle;
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformMenu::aboutToShow, this, &QQuickLabsPlatformMenu::aboutToShow);
+ connect(m_handle, &QPlatformMenu::aboutToHide, this, &QQuickLabsPlatformMenu::aboutToHide);
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items))
+ m_handle->insertMenuItem(item->create(), nullptr);
+
+ if (m_menuItem) {
+ if (QPlatformMenuItem *handle = m_menuItem->create())
+ handle->setMenu(m_handle);
+ }
+ }
+ }
+ return m_handle;
+}
+
+void QQuickLabsPlatformMenu::destroy()
+{
+ if (!m_handle)
+ return;
+
+ // Ensure that all submenus are unparented before we are destroyed,
+ // so that they don't try to access a destroyed menu.
+ unparentSubmenus();
+
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+void QQuickLabsPlatformMenu::sync()
+{
+ if (!m_complete || !create())
+ return;
+
+ m_handle->setText(m_title);
+ m_handle->setEnabled(m_enabled);
+ m_handle->setVisible(m_visible);
+ m_handle->setMinimumWidth(m_minimumWidth);
+ m_handle->setMenuType(m_type);
+ m_handle->setFont(m_font);
+
+ if (m_menuBar && m_menuBar->handle())
+ m_menuBar->handle()->syncMenu(m_handle);
+#if QT_CONFIG(systemtrayicon)
+ else if (m_systemTrayIcon && m_systemTrayIcon->handle())
+ m_systemTrayIcon->handle()->updateMenu(m_handle);
+#endif
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items))
+ item->sync();
+}
+
+/*!
+ \qmldefault
+ \qmlproperty list<QtObject> Qt.labs.platform::Menu::data
+
+ This default property holds the list of all objects declared as children of
+ the menu. The data property includes objects that are not \l MenuItem instances,
+ such as \l Timer and \l QtObject.
+
+ \sa items
+*/
+QQmlListProperty<QObject> QQuickLabsPlatformMenu::data()
+{
+ return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
+}
+
+/*!
+ \qmlproperty list<MenuItem> Qt.labs.platform::Menu::items
+
+ This property holds the list of items in the menu.
+*/
+QQmlListProperty<QQuickLabsPlatformMenuItem> QQuickLabsPlatformMenu::items()
+{
+ return QQmlListProperty<QQuickLabsPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuBar Qt.labs.platform::Menu::menuBar
+
+ This property holds the menubar that the menu belongs to, or \c null if the
+ menu is not in a menubar.
+*/
+QQuickLabsPlatformMenuBar *QQuickLabsPlatformMenu::menuBar() const
+{
+ return m_menuBar;
+}
+
+void QQuickLabsPlatformMenu::setMenuBar(QQuickLabsPlatformMenuBar *menuBar)
+{
+ if (m_menuBar == menuBar)
+ return;
+
+ m_menuBar = menuBar;
+ destroy();
+ emit menuBarChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::Menu::parentMenu
+
+ This property holds the parent menu that the menu belongs to, or \c null if the
+ menu is not a sub-menu.
+*/
+QQuickLabsPlatformMenu *QQuickLabsPlatformMenu::parentMenu() const
+{
+ return m_parentMenu;
+}
+
+void QQuickLabsPlatformMenu::setParentMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (m_parentMenu == menu)
+ return;
+
+ m_parentMenu = menu;
+ destroy();
+ emit parentMenuChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty SystemTrayIcon Qt.labs.platform::Menu::systemTrayIcon
+
+ This property holds the system tray icon that the menu belongs to, or \c null
+ if the menu is not in a system tray icon.
+*/
+QQuickLabsPlatformSystemTrayIcon *QQuickLabsPlatformMenu::systemTrayIcon() const
+{
+ return m_systemTrayIcon;
+}
+
+void QQuickLabsPlatformMenu::setSystemTrayIcon(QQuickLabsPlatformSystemTrayIcon *icon)
+{
+ if (m_systemTrayIcon == icon)
+ return;
+
+ m_systemTrayIcon = icon;
+ destroy();
+ emit systemTrayIconChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty MenuItem Qt.labs.platform::Menu::menuItem
+
+ This property holds the item that presents the menu (in a parent menu).
+*/
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenu::menuItem() const
+{
+ if (!m_menuItem) {
+ QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
+ m_menuItem = new QQuickLabsPlatformMenuItem(that);
+ m_menuItem->setSubMenu(that);
+ m_menuItem->setText(m_title);
+ m_menuItem->setIcon(icon());
+ m_menuItem->setVisible(m_visible);
+ m_menuItem->setEnabled(m_enabled);
+ m_menuItem->componentComplete();
+ }
+ return m_menuItem;
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::enabled
+
+ This property holds whether the menu is enabled. The default value is \c true.
+*/
+bool QQuickLabsPlatformMenu::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickLabsPlatformMenu::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setEnabled(enabled);
+
+ m_enabled = enabled;
+ sync();
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::Menu::visible
+
+ This property holds whether the menu is visible. The default value is \c true.
+*/
+bool QQuickLabsPlatformMenu::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickLabsPlatformMenu::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setVisible(visible);
+
+ m_visible = visible;
+ sync();
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty int Qt.labs.platform::Menu::minimumWidth
+
+ This property holds the minimum width of the menu. The default value is \c -1 (no minimum width).
+*/
+int QQuickLabsPlatformMenu::minimumWidth() const
+{
+ return m_minimumWidth;
+}
+
+void QQuickLabsPlatformMenu::setMinimumWidth(int width)
+{
+ if (m_minimumWidth == width)
+ return;
+
+ m_minimumWidth = width;
+ sync();
+ emit minimumWidthChanged();
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::Menu::type
+
+ This property holds the type of the menu.
+
+ Available values:
+ \value Menu.DefaultMenu A normal menu (default).
+ \value Menu.EditMenu An edit menu with pre-populated cut, copy and paste items.
+*/
+QPlatformMenu::MenuType QQuickLabsPlatformMenu::type() const
+{
+ return m_type;
+}
+
+void QQuickLabsPlatformMenu::setType(QPlatformMenu::MenuType type)
+{
+ if (m_type == type)
+ return;
+
+ m_type = type;
+ sync();
+ emit typeChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::Menu::title
+
+ This property holds the menu's title.
+*/
+QString QQuickLabsPlatformMenu::title() const
+{
+ return m_title;
+}
+
+void QQuickLabsPlatformMenu::setTitle(const QString &title)
+{
+ if (m_title == title)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setText(title);
+
+ m_title = title;
+ sync();
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::Menu::font
+
+ This property holds the menu's font.
+
+ \sa title
+*/
+QFont QQuickLabsPlatformMenu::font() const
+{
+ return m_font;
+}
+
+void QQuickLabsPlatformMenu::setFont(const QFont& font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ sync();
+ emit fontChanged();
+}
+
+/*!
+ \since Qt.labs.platform 1.1 (Qt 5.12)
+ \qmlproperty url Qt.labs.platform::Menu::icon.source
+ \qmlproperty string Qt.labs.platform::Menu::icon.name
+ \qmlproperty bool Qt.labs.platform::Menu::icon.mask
+
+ This property holds the menu item's icon.
+*/
+QQuickLabsPlatformIcon QQuickLabsPlatformMenu::icon() const
+{
+ if (!m_iconLoader)
+ return QQuickLabsPlatformIcon();
+
+ return iconLoader()->icon();
+}
+
+void QQuickLabsPlatformMenu::setIcon(const QQuickLabsPlatformIcon &icon)
+{
+ if (iconLoader()->icon() == icon)
+ return;
+
+ if (m_menuItem)
+ m_menuItem->setIcon(icon);
+
+ iconLoader()->setIcon(icon);
+ emit iconChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addItem(MenuItem item)
+
+ Adds an \a item to the end of the menu.
+*/
+void QQuickLabsPlatformMenu::addItem(QQuickLabsPlatformMenuItem *item)
+{
+ insertItem(m_items.count(), item);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertItem(int index, MenuItem item)
+
+ Inserts an \a item at the specified \a index in the menu.
+*/
+void QQuickLabsPlatformMenu::insertItem(int index, QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || m_items.contains(item))
+ return;
+
+ m_items.insert(index, item);
+ m_data.append(item);
+ item->setMenu(this);
+ if (m_handle && item->create()) {
+ QQuickLabsPlatformMenuItem *before = m_items.value(index + 1);
+ m_handle->insertMenuItem(item->handle(), before ? before->create() : nullptr);
+ }
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeItem(MenuItem item)
+
+ Removes an \a item from the menu.
+*/
+void QQuickLabsPlatformMenu::removeItem(QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || !m_items.removeOne(item))
+ return;
+
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::addMenu(Menu submenu)
+
+ Adds a \a submenu to the end of the menu.
+*/
+void QQuickLabsPlatformMenu::addMenu(QQuickLabsPlatformMenu *menu)
+{
+ insertMenu(m_items.count(), menu);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::insertMenu(int index, Menu submenu)
+
+ Inserts a \a submenu at the specified \a index in the menu.
+*/
+void QQuickLabsPlatformMenu::insertMenu(int index, QQuickLabsPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(this);
+ insertItem(index, menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::removeMenu(Menu submenu)
+
+ Removes a \a submenu from the menu.
+*/
+void QQuickLabsPlatformMenu::removeMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (!menu)
+ return;
+
+ menu->setParentMenu(nullptr);
+ removeItem(menu->menuItem());
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::clear()
+
+ Removes all items from the menu.
+*/
+void QQuickLabsPlatformMenu::clear()
+{
+ if (m_items.isEmpty())
+ return;
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ m_data.removeOne(item);
+ if (m_handle)
+ m_handle->removeMenuItem(item->handle());
+ item->setMenu(nullptr);
+ delete item;
+ }
+
+ m_items.clear();
+ sync();
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(MenuItem item)
+
+ Opens the menu at the current mouse position, optionally aligned to a menu \a item.
+*/
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::open(Item target, MenuItem item)
+
+ Opens the menu at the specified \a target item, optionally aligned to a menu \a item.
+*/
+void QQuickLabsPlatformMenu::open(QQmlV4Function *args)
+{
+ if (!m_handle)
+ return;
+
+ if (args->length() > 2) {
+ args->v4engine()->throwTypeError();
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ QQuickItem *targetItem = nullptr;
+ if (args->length() > 0) {
+ QV4::ScopedValue value(scope, (*args)[0]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ targetItem = qobject_cast<QQuickItem *>(object->object());
+ }
+
+ QQuickLabsPlatformMenuItem *menuItem = nullptr;
+ if (args->length() > 1) {
+ QV4::ScopedValue value(scope, (*args)[1]);
+ QV4::Scoped<QV4::QObjectWrapper> object(scope, value->as<QV4::QObjectWrapper>());
+ if (object)
+ menuItem = qobject_cast<QQuickLabsPlatformMenuItem *>(object->object());
+ }
+
+ QPoint offset;
+ QWindow *window = findWindow(targetItem, &offset);
+
+ QRect targetRect;
+ if (targetItem) {
+ QRectF sceneBounds = targetItem->mapRectToScene(targetItem->boundingRect());
+ targetRect = sceneBounds.toAlignedRect().translated(offset);
+ } else {
+#if QT_CONFIG(cursor)
+ QPoint pos = QCursor::pos();
+ if (window)
+ pos = window->mapFromGlobal(pos);
+ targetRect.moveTo(pos);
+#endif
+ }
+ m_handle->showPopup(window,
+ QHighDpi::toNativePixels(targetRect, window),
+ menuItem ? menuItem->handle() : nullptr);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::Menu::close()
+
+ Closes the menu.
+*/
+void QQuickLabsPlatformMenu::close()
+{
+ if (m_handle)
+ m_handle->dismiss();
+}
+
+void QQuickLabsPlatformMenu::classBegin()
+{
+}
+
+void QQuickLabsPlatformMenu::componentComplete()
+{
+ m_complete = true;
+ if (m_handle && m_iconLoader)
+ m_iconLoader->setEnabled(true);
+ sync();
+}
+
+QQuickLabsPlatformIconLoader *QQuickLabsPlatformMenu::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickLabsPlatformMenu *that = const_cast<QQuickLabsPlatformMenu *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+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;
+}
+
+QWindow *QQuickLabsPlatformMenu::findWindow(QQuickItem *target, QPoint *offset) const
+{
+ if (target)
+ return effectiveWindow(target->window(), offset);
+
+ if (m_menuBar && m_menuBar->window())
+ return effectiveWindow(m_menuBar->window(), offset);
+
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return effectiveWindow(window, offset);
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return effectiveWindow(item->window(), offset);
+
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+void QQuickLabsPlatformMenu::data_append(QQmlListProperty<QObject> *property, QObject *object)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ if (QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem *>(object))
+ menu->addItem(item);
+ else if (QQuickLabsPlatformMenu *subMenu = qobject_cast<QQuickLabsPlatformMenu *>(object))
+ menu->addMenu(subMenu);
+ else
+ menu->m_data.append(object);
+}
+
+qsizetype QQuickLabsPlatformMenu::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_data.count();
+}
+
+QObject *QQuickLabsPlatformMenu::data_at(QQmlListProperty<QObject> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_data.value(index);
+}
+
+void QQuickLabsPlatformMenu::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->m_data.clear();
+}
+
+void QQuickLabsPlatformMenu::items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, QQuickLabsPlatformMenuItem *item)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->addItem(item);
+}
+
+qsizetype QQuickLabsPlatformMenu::items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_items.count();
+}
+
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenu::items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ return menu->m_items.value(index);
+}
+
+void QQuickLabsPlatformMenu::items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *property)
+{
+ QQuickLabsPlatformMenu *menu = static_cast<QQuickLabsPlatformMenu *>(property->object);
+ menu->clear();
+}
+
+void QQuickLabsPlatformMenu::updateIcon()
+{
+ if (!m_handle || !m_iconLoader)
+ return;
+
+ m_handle->setIcon(m_iconLoader->toQIcon());
+ sync();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenu_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmenu_p.h b/src/labs/platform/qquicklabsplatformmenu_p.h
new file mode 100644
index 0000000000..cd41dec13e
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenu_p.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMENU_P_H
+#define QQUICKLABSPLATFORMMENU_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/qurl.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QIcon;
+class QWindow;
+class QQuickItem;
+class QPlatformMenu;
+class QQmlV4Function;
+class QQuickLabsPlatformMenuBar;
+class QQuickLabsPlatformMenuItem;
+class QQuickLabsPlatformIconLoader;
+class QQuickLabsPlatformSystemTrayIcon;
+
+class QQuickLabsPlatformMenu : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickLabsPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenuBar *menuBar READ menuBar NOTIFY menuBarChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenu *parentMenu READ parentMenu NOTIFY parentMenuChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformSystemTrayIcon *systemTrayIcon READ systemTrayIcon NOTIFY systemTrayIconChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenuItem *menuItem READ menuItem CONSTANT FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(int minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged FINAL)
+ Q_PROPERTY(QPlatformMenu::MenuType type READ type WRITE setType NOTIFY typeChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformIcon icon READ icon WRITE setIcon NOTIFY iconChanged FINAL REVISION(1, 1))
+ Q_ENUMS(QPlatformMenu::MenuType)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ explicit QQuickLabsPlatformMenu(QObject *parent = nullptr);
+ ~QQuickLabsPlatformMenu();
+
+ QPlatformMenu *handle() const;
+ QPlatformMenu *create();
+ void destroy();
+ void sync();
+
+ QQmlListProperty<QObject> data();
+ QQmlListProperty<QQuickLabsPlatformMenuItem> items();
+
+ QQuickLabsPlatformMenuBar *menuBar() const;
+ void setMenuBar(QQuickLabsPlatformMenuBar *menuBar);
+
+ QQuickLabsPlatformMenu *parentMenu() const;
+ void setParentMenu(QQuickLabsPlatformMenu *menu);
+
+ QQuickLabsPlatformSystemTrayIcon *systemTrayIcon() const;
+ void setSystemTrayIcon(QQuickLabsPlatformSystemTrayIcon *icon);
+
+ QQuickLabsPlatformMenuItem *menuItem() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ int minimumWidth() const;
+ void setMinimumWidth(int width);
+
+ QPlatformMenu::MenuType type() const;
+ void setType(QPlatformMenu::MenuType type);
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QQuickLabsPlatformIcon icon() const;
+ void setIcon(const QQuickLabsPlatformIcon &icon);
+
+ Q_INVOKABLE void addItem(QQuickLabsPlatformMenuItem *item);
+ Q_INVOKABLE void insertItem(int index, QQuickLabsPlatformMenuItem *item);
+ Q_INVOKABLE void removeItem(QQuickLabsPlatformMenuItem *item);
+
+ Q_INVOKABLE void addMenu(QQuickLabsPlatformMenu *menu);
+ Q_INVOKABLE void insertMenu(int index, QQuickLabsPlatformMenu *menu);
+ Q_INVOKABLE void removeMenu(QQuickLabsPlatformMenu *menu);
+
+ Q_INVOKABLE void clear();
+
+public Q_SLOTS:
+ void open(QQmlV4Function *args);
+ void close();
+
+Q_SIGNALS:
+ void aboutToShow();
+ void aboutToHide();
+
+ void itemsChanged();
+ void menuBarChanged();
+ void parentMenuChanged();
+ void systemTrayIconChanged();
+ void titleChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void minimumWidthChanged();
+ void fontChanged();
+ void typeChanged();
+ Q_REVISION(2, 1) void iconChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QQuickLabsPlatformIconLoader *iconLoader() const;
+
+ QWindow *findWindow(QQuickItem *target, QPoint *offset) const;
+
+ static void data_append(QQmlListProperty<QObject> *property, QObject *object);
+ static qsizetype data_count(QQmlListProperty<QObject> *property);
+ static QObject *data_at(QQmlListProperty<QObject> *property, qsizetype index);
+ static void data_clear(QQmlListProperty<QObject> *property);
+
+ static void items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, QQuickLabsPlatformMenuItem *item);
+ static qsizetype items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *property);
+ static QQuickLabsPlatformMenuItem *items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *property, qsizetype index);
+ static void items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *property);
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ void unparentSubmenus();
+
+ bool m_complete;
+ bool m_enabled;
+ bool m_visible;
+ int m_minimumWidth;
+ QPlatformMenu::MenuType m_type;
+ QString m_title;
+ QFont m_font;
+ QList<QObject *> m_data;
+ QList<QQuickLabsPlatformMenuItem *> m_items;
+ QQuickLabsPlatformMenuBar *m_menuBar;
+ QQuickLabsPlatformMenu *m_parentMenu;
+ QQuickLabsPlatformSystemTrayIcon *m_systemTrayIcon;
+ mutable QQuickLabsPlatformMenuItem *m_menuItem;
+ mutable QQuickLabsPlatformIconLoader *m_iconLoader;
+ QPlatformMenu *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMenu)
+Q_DECLARE_METATYPE(QPlatformMenu::MenuType)
+
+#endif // QQUICKLABSPLATFORMMENU_P_H
diff --git a/src/labs/platform/qquicklabsplatformmenubar.cpp b/src/labs/platform/qquicklabsplatformmenubar.cpp
new file mode 100644
index 0000000000..0ebc699008
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenubar.cpp
@@ -0,0 +1,334 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenubar_p.h"
+#include "qquicklabsplatformmenu_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuBar
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformMenuBar
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menubar.
+
+ The MenuBar type provides a QML API for native platform menubars.
+
+ \image qtlabsplatform-menubar.png
+
+ A menubar consists of a list of drop-down menus.
+
+ \code
+ MenuBar {
+ id: menuBar
+
+ Menu {
+ id: fileMenu
+ title: qsTr("File")
+ // ...
+ }
+
+ Menu {
+ id: editMenu
+ title: qsTr("&Edit")
+ // ...
+ }
+
+ Menu {
+ id: viewMenu
+ title: qsTr("&View")
+ // ...
+ }
+
+ Menu {
+ id: helpMenu
+ title: qsTr("&Help")
+ // ...
+ }
+ }
+ \endcode
+
+ MenuBar is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li Android
+ \li Linux (only available on desktop environments that provide a global D-Bus menu bar)
+ \li Windows
+ \endlist
+
+ \labs
+
+ \sa Menu
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformMenus)
+
+QQuickLabsPlatformMenuBar::QQuickLabsPlatformMenuBar(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_window(nullptr),
+ m_handle(nullptr)
+{
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuBar();
+ qCDebug(qtLabsPlatformMenus) << "MenuBar ->" << m_handle;
+}
+
+QQuickLabsPlatformMenuBar::~QQuickLabsPlatformMenuBar()
+{
+ for (QQuickLabsPlatformMenu *menu : qAsConst(m_menus))
+ menu->setMenuBar(nullptr);
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformMenuBar *QQuickLabsPlatformMenuBar::handle() const
+{
+ return m_handle;
+}
+
+/*!
+ \qmldefault
+ \qmlproperty list<QtObject> Qt.labs.platform::MenuBar::data
+
+ This default property holds the list of all objects declared as children of
+ the menubar. The data property includes objects that are not \l Menu instances,
+ such as \l Timer and \l QtObject.
+
+ \sa menus
+*/
+QQmlListProperty<QObject> QQuickLabsPlatformMenuBar::data()
+{
+ return QQmlListProperty<QObject>(this, nullptr, data_append, data_count, data_at, data_clear);
+}
+
+/*!
+ \qmlproperty list<Menu> Qt.labs.platform::MenuBar::menus
+
+ This property holds the list of menus in the menubar.
+*/
+QQmlListProperty<QQuickLabsPlatformMenu> QQuickLabsPlatformMenuBar::menus()
+{
+ return QQmlListProperty<QQuickLabsPlatformMenu>(this, nullptr, menus_append, menus_count, menus_at, menus_clear);
+}
+
+/*!
+ \qmlproperty Window Qt.labs.platform::MenuBar::window
+
+ This property holds the menubar's window.
+
+ Unless explicitly set, the window is automatically resolved by iterating
+ the QML parent objects until a \l Window or an \l Item that has a window
+ is found.
+*/
+QWindow *QQuickLabsPlatformMenuBar::window() const
+{
+ return m_window;
+}
+
+void QQuickLabsPlatformMenuBar::setWindow(QWindow *window)
+{
+ if (m_window == window)
+ return;
+
+ if (m_handle)
+ m_handle->handleReparent(window);
+
+ m_window = window;
+ emit windowChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::addMenu(Menu menu)
+
+ Adds a \a menu to end of the menubar.
+*/
+void QQuickLabsPlatformMenuBar::addMenu(QQuickLabsPlatformMenu *menu)
+{
+ insertMenu(m_menus.count(), menu);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::insertMenu(int index, Menu menu)
+
+ Inserts a \a menu at the specified \a index in the menubar.
+*/
+void QQuickLabsPlatformMenuBar::insertMenu(int index, QQuickLabsPlatformMenu *menu)
+{
+ if (!menu || m_menus.contains(menu))
+ return;
+
+ QQuickLabsPlatformMenu *before = m_menus.value(index);
+ m_menus.insert(index, menu);
+ m_data.append(menu);
+ menu->setMenuBar(this);
+ if (m_handle)
+ m_handle->insertMenu(menu->create(), before ? before->handle() : nullptr);
+ menu->sync();
+ emit menusChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::removeMenu(Menu menu)
+
+ Removes a \a menu from the menubar.
+*/
+void QQuickLabsPlatformMenuBar::removeMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (!menu || !m_menus.removeOne(menu))
+ return;
+
+ m_data.removeOne(menu);
+ if (m_handle)
+ m_handle->removeMenu(menu->handle());
+ menu->setMenuBar(nullptr);
+ emit menusChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuBar::clear()
+
+ Removes all menus from the menubar.
+*/
+void QQuickLabsPlatformMenuBar::clear()
+{
+ if (m_menus.isEmpty())
+ return;
+
+ for (QQuickLabsPlatformMenu *menu : qAsConst(m_menus)) {
+ m_data.removeOne(menu);
+ if (m_handle)
+ m_handle->removeMenu(menu->handle());
+ menu->setMenuBar(nullptr);
+ delete menu;
+ }
+
+ m_menus.clear();
+ emit menusChanged();
+}
+
+void QQuickLabsPlatformMenuBar::classBegin()
+{
+}
+
+void QQuickLabsPlatformMenuBar::componentComplete()
+{
+ m_complete = true;
+ for (QQuickLabsPlatformMenu *menu : qAsConst(m_menus))
+ menu->sync();
+ if (!m_window)
+ setWindow(findWindow());
+}
+
+QWindow *QQuickLabsPlatformMenuBar::findWindow() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+void QQuickLabsPlatformMenuBar::data_append(QQmlListProperty<QObject> *property, QObject *object)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ QQuickLabsPlatformMenu *menu = qobject_cast<QQuickLabsPlatformMenu *>(object);
+ if (menu)
+ menuBar->addMenu(menu);
+ else
+ menuBar->m_data.append(object);
+}
+
+qsizetype QQuickLabsPlatformMenuBar::data_count(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ return menuBar->m_data.count();
+}
+
+QObject *QQuickLabsPlatformMenuBar::data_at(QQmlListProperty<QObject> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ return menuBar->m_data.value(index);
+}
+
+void QQuickLabsPlatformMenuBar::data_clear(QQmlListProperty<QObject> *property)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ menuBar->m_data.clear();
+}
+
+void QQuickLabsPlatformMenuBar::menus_append(QQmlListProperty<QQuickLabsPlatformMenu> *property, QQuickLabsPlatformMenu *menu)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ menuBar->addMenu(menu);
+}
+
+qsizetype QQuickLabsPlatformMenuBar::menus_count(QQmlListProperty<QQuickLabsPlatformMenu> *property)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ return menuBar->m_menus.count();
+}
+
+QQuickLabsPlatformMenu *QQuickLabsPlatformMenuBar::menus_at(QQmlListProperty<QQuickLabsPlatformMenu> *property, qsizetype index)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ return menuBar->m_menus.value(index);
+}
+
+void QQuickLabsPlatformMenuBar::menus_clear(QQmlListProperty<QQuickLabsPlatformMenu> *property)
+{
+ QQuickLabsPlatformMenuBar *menuBar = static_cast<QQuickLabsPlatformMenuBar *>(property->object);
+ menuBar->clear();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenubar_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmenubar_p.h b/src/labs/platform/qquicklabsplatformmenubar_p.h
new file mode 100644
index 0000000000..25583bee52
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenubar_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMENUBAR_P_H
+#define QQUICKLABSPLATFORMMENUBAR_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 <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QPlatformMenuBar;
+class QQuickLabsPlatformMenu;
+
+class QQuickLabsPlatformMenuBar : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickLabsPlatformMenu> menus READ menus NOTIFY menusChanged FINAL)
+ Q_PROPERTY(QWindow *window READ window WRITE setWindow NOTIFY windowChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "data")
+
+public:
+ explicit QQuickLabsPlatformMenuBar(QObject *parent = nullptr);
+ ~QQuickLabsPlatformMenuBar();
+
+ QPlatformMenuBar *handle() const;
+
+ QQmlListProperty<QObject> data();
+ QQmlListProperty<QQuickLabsPlatformMenu> menus();
+
+ QWindow *window() const;
+ void setWindow(QWindow *window);
+
+ Q_INVOKABLE void addMenu(QQuickLabsPlatformMenu *menu);
+ Q_INVOKABLE void insertMenu(int index, QQuickLabsPlatformMenu *menu);
+ Q_INVOKABLE void removeMenu(QQuickLabsPlatformMenu *menu);
+ Q_INVOKABLE void clear();
+
+Q_SIGNALS:
+ void menusChanged();
+ void windowChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QWindow *findWindow() const;
+
+ static void data_append(QQmlListProperty<QObject> *property, QObject *object);
+ static qsizetype data_count(QQmlListProperty<QObject> *property);
+ static QObject *data_at(QQmlListProperty<QObject> *property, qsizetype index);
+ static void data_clear(QQmlListProperty<QObject> *property);
+
+ static void menus_append(QQmlListProperty<QQuickLabsPlatformMenu> *property, QQuickLabsPlatformMenu *menu);
+ static qsizetype menus_count(QQmlListProperty<QQuickLabsPlatformMenu> *property);
+ static QQuickLabsPlatformMenu *menus_at(QQmlListProperty<QQuickLabsPlatformMenu> *property, qsizetype index);
+ static void menus_clear(QQmlListProperty<QQuickLabsPlatformMenu> *property);
+
+private:
+ bool m_complete;
+ QWindow *m_window;
+ QList<QObject *> m_data;
+ QList<QQuickLabsPlatformMenu *> m_menus;
+ QPlatformMenuBar *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMenuBar)
+
+#endif // QQUICKLABSPLATFORMMENUBAR_P_H
diff --git a/src/labs/platform/qquicklabsplatformmenuitem.cpp b/src/labs/platform/qquicklabsplatformmenuitem.cpp
new file mode 100644
index 0000000000..59b9c04d6b
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuitem.cpp
@@ -0,0 +1,650 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenuitem_p.h"
+#include "qquicklabsplatformmenu_p.h"
+#include "qquicklabsplatformmenuitemgroup_p.h"
+#include "qquicklabsplatformiconloader_p.h"
+
+#include <QtGui/qicon.h>
+#if QT_CONFIG(shortcut)
+#include <QtGui/qkeysequence.h>
+#endif
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+
+#include "widgets/qwidgetplatform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuItem
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformMenuItem
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu item.
+
+ The MenuItem type provides a QML API for native platform menu items.
+
+ \image qtlabsplatform-menu.png
+
+ A menu item consists of an \l icon, \l text, and \l shortcut.
+
+ \code
+ Menu {
+ id: zoomMenu
+
+ MenuItem {
+ text: qsTr("Zoom In")
+ shortcut: StandardKey.ZoomIn
+ onTriggered: zoomIn()
+ }
+
+ MenuItem {
+ text: qsTr("Zoom Out")
+ shortcut: StandardKey.ZoomOut
+ onTriggered: zoomOut()
+ }
+ }
+ \endcode
+
+ \labs
+
+ \sa Menu, MenuItemGroup
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItem::triggered()
+
+ This signal is emitted when the menu item is triggered by the user.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItem::hovered()
+
+ This signal is emitted when the menu item is hovered by the user.
+*/
+
+QQuickLabsPlatformMenuItem::QQuickLabsPlatformMenuItem(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_enabled(true),
+ m_visible(true),
+ m_separator(false),
+ m_checkable(false),
+ m_checked(false),
+ m_role(QPlatformMenuItem::TextHeuristicRole),
+ m_menu(nullptr),
+ m_subMenu(nullptr),
+ m_group(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+}
+
+QQuickLabsPlatformMenuItem::~QQuickLabsPlatformMenuItem()
+{
+ if (m_menu)
+ m_menu->removeItem(this);
+ if (m_group)
+ m_group->removeItem(this);
+ removeShortcut();
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformMenuItem *QQuickLabsPlatformMenuItem::handle() const
+{
+ return m_handle;
+}
+
+QPlatformMenuItem *QQuickLabsPlatformMenuItem::create()
+{
+ if (!m_handle && m_menu && m_menu->handle()) {
+ m_handle = m_menu->handle()->createMenuItem();
+
+ // TODO: implement QCocoaMenu::createMenuItem()
+ if (!m_handle)
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem();
+
+ if (!m_handle)
+ m_handle = QWidgetPlatform::createMenuItem();
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformMenuItem::activated, this, &QQuickLabsPlatformMenuItem::activate);
+ connect(m_handle, &QPlatformMenuItem::hovered, this, &QQuickLabsPlatformMenuItem::hovered);
+ }
+ }
+ return m_handle;
+}
+
+void QQuickLabsPlatformMenuItem::sync()
+{
+ if (!m_complete || !create())
+ return;
+
+ m_handle->setEnabled(isEnabled());
+ m_handle->setVisible(isVisible());
+ m_handle->setIsSeparator(m_separator);
+ m_handle->setCheckable(m_checkable);
+ m_handle->setChecked(m_checked);
+ m_handle->setRole(m_role);
+ m_handle->setText(m_text);
+ m_handle->setFont(m_font);
+ m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive());
+
+ if (m_iconLoader)
+ m_handle->setIcon(m_iconLoader->toQIcon());
+
+ if (m_subMenu) {
+ // Sync first as dynamically created menus may need to get the
+ // handle recreated
+ m_subMenu->sync();
+ if (m_subMenu->handle())
+ m_handle->setMenu(m_subMenu->handle());
+ }
+
+#if QT_CONFIG(shortcut)
+ QKeySequence sequence;
+ if (m_shortcut.metaType().id() == QMetaType::Int)
+ sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt()));
+ else
+ sequence = QKeySequence::fromString(m_shortcut.toString());
+ m_handle->setShortcut(sequence.toString());
+#endif
+
+ if (m_menu && m_menu->handle())
+ m_menu->handle()->syncMenuItem(m_handle);
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::MenuItem::menu
+
+ This property holds the menu that the item belongs to, or \c null if the
+ item is not in a menu.
+*/
+QQuickLabsPlatformMenu *QQuickLabsPlatformMenuItem::menu() const
+{
+ return m_menu;
+}
+
+void QQuickLabsPlatformMenuItem::setMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (m_menu == menu)
+ return;
+
+ m_menu = menu;
+ emit menuChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty Menu Qt.labs.platform::MenuItem::subMenu
+
+ This property holds the sub-menu that the item contains, or \c null if
+ the item is not a sub-menu item.
+*/
+QQuickLabsPlatformMenu *QQuickLabsPlatformMenuItem::subMenu() const
+{
+ return m_subMenu;
+}
+
+void QQuickLabsPlatformMenuItem::setSubMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (m_subMenu == menu)
+ return;
+
+ m_subMenu = menu;
+ sync();
+ emit subMenuChanged();
+}
+
+/*!
+ \qmlproperty MenuItemGroup Qt.labs.platform::MenuItem::group
+
+ This property holds the group that the item belongs to, or \c null if the
+ item is not in a group.
+*/
+QQuickLabsPlatformMenuItemGroup *QQuickLabsPlatformMenuItem::group() const
+{
+ return m_group;
+}
+
+void QQuickLabsPlatformMenuItem::setGroup(QQuickLabsPlatformMenuItemGroup *group)
+{
+ if (m_group == group)
+ return;
+
+ bool wasEnabled = isEnabled();
+ bool wasVisible = isVisible();
+
+ if (group)
+ group->addItem(this);
+
+ m_group = group;
+ sync();
+ emit groupChanged();
+
+ if (isEnabled() != wasEnabled)
+ emit enabledChanged();
+ if (isVisible() != wasVisible)
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::enabled
+
+ This property holds whether the item is enabled. The default value is \c true.
+
+ Disabled items cannot be triggered by the user. They do not disappear from menus,
+ but they are displayed in a way which indicates that they are unavailable. For
+ example, they might be displayed using only shades of gray.
+
+ When an item is disabled, it is not possible to trigger it through its \l shortcut.
+*/
+bool QQuickLabsPlatformMenuItem::isEnabled() const
+{
+ return m_enabled && (!m_group || m_group->isEnabled());
+}
+
+void QQuickLabsPlatformMenuItem::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ if (!enabled)
+ removeShortcut();
+
+ bool wasEnabled = isEnabled();
+ m_enabled = enabled;
+
+ if (enabled)
+ addShortcut();
+
+ sync();
+ if (isEnabled() != wasEnabled)
+ emit enabledChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::visible
+
+ This property holds whether the item is visible. The default value is \c true.
+*/
+bool QQuickLabsPlatformMenuItem::isVisible() const
+{
+ return m_visible && (!m_group || m_group->isVisible());
+}
+
+void QQuickLabsPlatformMenuItem::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ bool wasVisible = isVisible();
+ m_visible = visible;
+ sync();
+ if (isVisible() != wasVisible)
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::separator
+
+ This property holds whether the item is a separator line. The default value
+ is \c false.
+
+ \sa MenuSeparator
+*/
+bool QQuickLabsPlatformMenuItem::isSeparator() const
+{
+ return m_separator;
+}
+
+void QQuickLabsPlatformMenuItem::setSeparator(bool separator)
+{
+ if (m_separator == separator)
+ return;
+
+ m_separator = separator;
+ sync();
+ emit separatorChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::checkable
+
+ This property holds whether the item is checkable.
+
+ A checkable menu item has an on/off state. For example, in a word processor,
+ a "Bold" menu item may be either on or off. A menu item that is not checkable
+ is a command item that is simply executed, e.g. file save.
+
+ The default value is \c false.
+
+ \sa checked, MenuItemGroup
+*/
+bool QQuickLabsPlatformMenuItem::isCheckable() const
+{
+ return m_checkable;
+}
+
+void QQuickLabsPlatformMenuItem::setCheckable(bool checkable)
+{
+ if (m_checkable == checkable)
+ return;
+
+ m_checkable = checkable;
+ sync();
+ emit checkableChanged();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItem::checked
+
+ This property holds whether the item is checked (on) or unchecked (off).
+ The default value is \c false.
+
+ \sa checkable, MenuItemGroup
+*/
+bool QQuickLabsPlatformMenuItem::isChecked() const
+{
+ return m_checked;
+}
+
+void QQuickLabsPlatformMenuItem::setChecked(bool checked)
+{
+ if (m_checked == checked)
+ return;
+
+ if (checked && !m_checkable)
+ setCheckable(true);
+
+ m_checked = checked;
+ sync();
+ emit checkedChanged();
+}
+
+/*!
+ \qmlproperty enumeration Qt.labs.platform::MenuItem::role
+
+ This property holds the role of the item. The role determines whether
+ the item should be placed into the application menu on macOS.
+
+ Available values:
+ \value MenuItem.NoRole The item should not be put into the application menu
+ \value MenuItem.TextHeuristicRole The item should be put in the application menu based on the action's text (default)
+ \value MenuItem.ApplicationSpecificRole The item should be put in the application menu with an application-specific role
+ \value MenuItem.AboutQtRole The item handles the "About Qt" menu item.
+ \value MenuItem.AboutRole The item should be placed where the "About" menu item is in the application menu. The text of
+ the menu item will be set to "About <application name>". The application name is fetched from the
+ \c{Info.plist} file in the application's bundle (See \l{Qt for macOS - Deployment}).
+ \value MenuItem.PreferencesRole The item should be placed where the "Preferences..." menu item is in the application menu.
+ \value MenuItem.QuitRole The item should be placed where the Quit menu item is in the application menu.
+
+ Specifying the role only has effect on items that are in the immediate
+ menus of a menubar, not in the submenus of those menus. For example, if
+ you have a "File" menu in your menubar and the "File" menu has a submenu,
+ specifying a role for the items in that submenu has no effect. They will
+ never be moved to the application menu.
+*/
+QPlatformMenuItem::MenuRole QQuickLabsPlatformMenuItem::role() const
+{
+ return m_role;
+}
+
+void QQuickLabsPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
+{
+ if (m_role == role)
+ return;
+
+ m_role = role;
+ sync();
+ emit roleChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MenuItem::text
+
+ This property holds the menu item's text.
+*/
+QString QQuickLabsPlatformMenuItem::text() const
+{
+ return m_text;
+}
+
+void QQuickLabsPlatformMenuItem::setText(const QString &text)
+{
+ if (m_text == text)
+ return;
+
+ m_text = text;
+ sync();
+ emit textChanged();
+}
+
+/*!
+ \qmlproperty keysequence Qt.labs.platform::MenuItem::shortcut
+
+ This property holds the menu item's shortcut.
+
+ The shortcut key sequence can be set to one of the
+ \l{QKeySequence::StandardKey}{standard keyboard shortcuts}, or it can be
+ specified by a string containing a sequence of up to four key presses
+ that are needed to \l{triggered}{trigger} the shortcut.
+
+ The default value is an empty key sequence.
+
+ \code
+ MenuItem {
+ shortcut: "Ctrl+E,Ctrl+W"
+ onTriggered: edit.wrapMode = TextEdit.Wrap
+ }
+ \endcode
+*/
+QVariant QQuickLabsPlatformMenuItem::shortcut() const
+{
+ return m_shortcut;
+}
+
+bool QQuickLabsPlatformMenuItem::event(QEvent *e)
+{
+#if QT_CONFIG(shortcut)
+ if (e->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
+ if (se->shortcutId() == m_shortcutId) {
+ activate();
+ return true;
+ }
+ }
+#endif
+ return QObject::event(e);
+}
+
+void QQuickLabsPlatformMenuItem::setShortcut(const QVariant& shortcut)
+{
+ if (m_shortcut == shortcut)
+ return;
+
+ removeShortcut();
+ m_shortcut = shortcut;
+ sync();
+ addShortcut();
+ emit shortcutChanged();
+}
+
+/*!
+ \qmlproperty font Qt.labs.platform::MenuItem::font
+
+ This property holds the menu item's font.
+
+ \sa text
+*/
+QFont QQuickLabsPlatformMenuItem::font() const
+{
+ return m_font;
+}
+
+void QQuickLabsPlatformMenuItem::setFont(const QFont& font)
+{
+ if (m_font == font)
+ return;
+
+ m_font = font;
+ sync();
+ emit fontChanged();
+}
+
+/*!
+ \since Qt.labs.platform 1.1 (Qt 5.12)
+ \qmlproperty url Qt.labs.platform::MenuItem::icon.source
+ \qmlproperty string Qt.labs.platform::MenuItem::icon.name
+ \qmlproperty bool Qt.labs.platform::MenuItem::icon.mask
+
+ This property holds the menu item's icon.
+
+ \code
+ MenuItem {
+ icon.mask: true
+ icon.name: "edit-undo"
+ icon.source: "qrc:/images/undo.png"
+ }
+ \endcode
+
+ \sa QIcon::fromTheme()
+*/
+QQuickLabsPlatformIcon QQuickLabsPlatformMenuItem::icon() const
+{
+ if (!m_iconLoader)
+ return QQuickLabsPlatformIcon();
+
+ return m_iconLoader->icon();
+}
+
+void QQuickLabsPlatformMenuItem::setIcon(const QQuickLabsPlatformIcon &icon)
+{
+ if (iconLoader()->icon() == icon)
+ return;
+
+ iconLoader()->setIcon(icon);
+ emit iconChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItem::toggle()
+
+ Toggles the \l checked state to its opposite state.
+*/
+void QQuickLabsPlatformMenuItem::toggle()
+{
+ if (m_checkable)
+ setChecked(!m_checked);
+}
+
+void QQuickLabsPlatformMenuItem::classBegin()
+{
+}
+
+void QQuickLabsPlatformMenuItem::componentComplete()
+{
+ if (m_iconLoader)
+ m_iconLoader->setEnabled(true);
+ m_complete = true;
+ sync();
+}
+
+QQuickLabsPlatformIconLoader *QQuickLabsPlatformMenuItem::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickLabsPlatformMenuItem *that = const_cast<QQuickLabsPlatformMenuItem *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+void QQuickLabsPlatformMenuItem::activate()
+{
+ toggle();
+ emit triggered();
+}
+
+void QQuickLabsPlatformMenuItem::updateIcon()
+{
+ sync();
+}
+
+void QQuickLabsPlatformMenuItem::addShortcut()
+{
+#if QT_CONFIG(shortcut)
+ QKeySequence sequence;
+ if (m_shortcut.metaType().id() == QMetaType::Int)
+ sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt()));
+ else
+ sequence = QKeySequence::fromString(m_shortcut.toString());
+ if (!sequence.isEmpty() && m_enabled) {
+ m_shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence,
+ Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ } else {
+ m_shortcutId = -1;
+ }
+#endif
+}
+
+void QQuickLabsPlatformMenuItem::removeShortcut()
+{
+#if QT_CONFIG(shortcut)
+ if (m_shortcutId == -1)
+ return;
+
+ QKeySequence sequence;
+ if (m_shortcut.metaType().id() == QMetaType::Int)
+ sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt()));
+ else
+ sequence = QKeySequence::fromString(m_shortcut.toString());
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, this, sequence);
+#endif
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenuitem_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmenuitem_p.h b/src/labs/platform/qquicklabsplatformmenuitem_p.h
new file mode 100644
index 0000000000..ab7403e0da
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuitem_p.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMENUITEM_P_H
+#define QQUICKLABSPLATFORMMENUITEM_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/qurl.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpa/qplatformmenu.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformMenuItem;
+class QQuickLabsPlatformMenu;
+class QQuickLabsPlatformIconLoader;
+class QQuickLabsPlatformMenuItemGroup;
+
+class QQuickLabsPlatformMenuItem : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQuickLabsPlatformMenu *menu READ menu NOTIFY menuChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenu *subMenu READ subMenu NOTIFY subMenuChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenuItemGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(bool separator READ isSeparator WRITE setSeparator NOTIFY separatorChanged FINAL)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL)
+ Q_PROPERTY(QPlatformMenuItem::MenuRole role READ role WRITE setRole NOTIFY roleChanged FINAL)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(QVariant shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformIcon icon READ icon WRITE setIcon NOTIFY iconChanged FINAL REVISION(1, 1))
+ Q_ENUMS(QPlatformMenuItem::MenuRole)
+
+public:
+ explicit QQuickLabsPlatformMenuItem(QObject *parent = nullptr);
+ ~QQuickLabsPlatformMenuItem();
+
+ QPlatformMenuItem *handle() const;
+ QPlatformMenuItem *create();
+ void sync();
+
+ QQuickLabsPlatformMenu *menu() const;
+ void setMenu(QQuickLabsPlatformMenu* menu);
+
+ QQuickLabsPlatformMenu *subMenu() const;
+ void setSubMenu(QQuickLabsPlatformMenu *menu);
+
+ QQuickLabsPlatformMenuItemGroup *group() const;
+ void setGroup(QQuickLabsPlatformMenuItemGroup *group);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ bool isSeparator() const;
+ void setSeparator(bool separator);
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+
+ bool isChecked() const;
+ void setChecked(bool checked);
+
+ QPlatformMenuItem::MenuRole role() const;
+ void setRole(QPlatformMenuItem::MenuRole role);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ QVariant shortcut() const;
+ void setShortcut(const QVariant& shortcut);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QQuickLabsPlatformIcon icon() const;
+ void setIcon(const QQuickLabsPlatformIcon &icon);
+
+public Q_SLOTS:
+ void toggle();
+
+Q_SIGNALS:
+ void triggered();
+ void hovered();
+
+ void menuChanged();
+ void subMenuChanged();
+ void groupChanged();
+ void enabledChanged();
+ void visibleChanged();
+ void separatorChanged();
+ void checkableChanged();
+ void checkedChanged();
+ void roleChanged();
+ void textChanged();
+ void shortcutChanged();
+ void fontChanged();
+ Q_REVISION(2, 1) void iconChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ QQuickLabsPlatformIconLoader *iconLoader() const;
+
+ bool event(QEvent *e) override;
+private Q_SLOTS:
+ void activate();
+ void updateIcon();
+
+private:
+ void addShortcut();
+ void removeShortcut();
+
+ bool m_complete;
+ bool m_enabled;
+ bool m_visible;
+ bool m_separator;
+ bool m_checkable;
+ bool m_checked;
+ QPlatformMenuItem::MenuRole m_role;
+ QString m_text;
+ QVariant m_shortcut;
+ QFont m_font;
+ QQuickLabsPlatformMenu *m_menu;
+ QQuickLabsPlatformMenu *m_subMenu;
+ QQuickLabsPlatformMenuItemGroup *m_group;
+ mutable QQuickLabsPlatformIconLoader *m_iconLoader;
+ QPlatformMenuItem *m_handle;
+ int m_shortcutId = -1;
+
+ friend class QQuickLabsPlatformMenu;
+ friend class QQuickLabsPlatformMenuItemGroup;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMenuItem)
+
+#endif // QQUICKLABSPLATFORMMENUITEM_P_H
diff --git a/src/labs/platform/qquicklabsplatformmenuitemgroup.cpp b/src/labs/platform/qquicklabsplatformmenuitemgroup.cpp
new file mode 100644
index 0000000000..bb2d116e23
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuitemgroup.cpp
@@ -0,0 +1,392 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenuitemgroup_p.h"
+#include "qquicklabsplatformmenuitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuItemGroup
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformMenuItemGroup
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A group for managing native menu items.
+
+ The MenuItemGroup groups native menu items together.
+
+ MenuItemGroup is exclusive by default. In an exclusive menu item
+ group, only one item can be checked at any time; checking another
+ item automatically unchecks the previously checked one. MenuItemGroup
+ can be configured as non-exclusive, which is particularly useful for
+ showing, hiding, enabling and disabling items together as a group.
+
+ The most straight-forward way to use MenuItemGroup is to assign
+ a list of items.
+
+ \code
+ Menu {
+ id: verticalMenu
+ title: qsTr("Vertical")
+
+ MenuItemGroup {
+ id: verticalGroup
+ items: verticalMenu.items
+ }
+
+ MenuItem { text: qsTr("Top"); checkable: true }
+ MenuItem { text: qsTr("Center"); checked: true }
+ MenuItem { text: qsTr("Bottom"); checkable: true }
+ }
+ \endcode
+
+ The same menu may sometimes contain items that should not be included
+ in the same exclusive group. Such cases are best handled using the
+ \l {MenuItem::group}{group} property.
+
+ \code
+ Menu {
+ id: horizontalMenu
+ title: qsTr("Horizontal")
+
+ MenuItemGroup {
+ id: horizontalGroup
+ }
+
+ MenuItem {
+ checked: true
+ text: qsTr("Left")
+ group: horizontalGroup
+ }
+ MenuItem {
+ checkable: true
+ text: qsTr("Center")
+ group: horizontalGroup
+ }
+ MenuItem {
+ text: qsTr("Right")
+ checkable: true
+ group: horizontalGroup
+ }
+
+ MenuItem { separator: true }
+ MenuItem { text: qsTr("Justify"); checkable: true }
+ MenuItem { text: qsTr("Absolute"); checkable: true }
+ }
+ \endcode
+
+ More advanced use cases can be handled using the addItem() and
+ removeItem() methods.
+
+ \labs
+
+ \sa MenuItem
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItemGroup::triggered(MenuItem item)
+
+ This signal is emitted when an \a item in the group is triggered by the user.
+
+ \sa MenuItem::triggered()
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MenuItemGroup::hovered(MenuItem item)
+
+ This signal is emitted when an \a item in the group is hovered by the user.
+
+ \sa MenuItem::hovered()
+*/
+
+QQuickLabsPlatformMenuItemGroup::QQuickLabsPlatformMenuItemGroup(QObject *parent)
+ : QObject(parent), m_enabled(true), m_visible(true), m_exclusive(true), m_checkedItem(nullptr)
+{
+}
+
+QQuickLabsPlatformMenuItemGroup::~QQuickLabsPlatformMenuItemGroup()
+{
+ clear();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::enabled
+
+ This property holds whether the group is enabled. The default value is \c true.
+
+ The enabled state of the group affects the enabled state of each item in the group,
+ except that explicitly disabled items are not enabled even if the group is enabled.
+*/
+bool QQuickLabsPlatformMenuItemGroup::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QQuickLabsPlatformMenuItemGroup::setEnabled(bool enabled)
+{
+ if (m_enabled == enabled)
+ return;
+
+ m_enabled = enabled;
+ emit enabledChanged();
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ if (item->m_enabled) {
+ item->sync();
+ emit item->enabledChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::visible
+
+ This property holds whether the group is visible. The default value is \c true.
+
+ The visibility of the group affects the visibility of each item in the group,
+ except that explicitly hidden items are not visible even if the group is visible.
+*/
+bool QQuickLabsPlatformMenuItemGroup::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickLabsPlatformMenuItemGroup::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ m_visible = visible;
+ emit visibleChanged();
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ if (item->m_visible) {
+ item->sync();
+ emit item->visibleChanged();
+ }
+ }
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::MenuItemGroup::exclusive
+
+ This property holds whether the group is exclusive. The default value is \c true.
+
+ In an exclusive menu item group, only one item can be checked at any time;
+ checking another item automatically unchecks the previously checked one.
+*/
+bool QQuickLabsPlatformMenuItemGroup::isExclusive() const
+{
+ return m_exclusive;
+}
+
+void QQuickLabsPlatformMenuItemGroup::setExclusive(bool exclusive)
+{
+ if (m_exclusive == exclusive)
+ return;
+
+ m_exclusive = exclusive;
+ emit exclusiveChanged();
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items))
+ item->sync();
+}
+
+/*!
+ \qmlproperty MenuItem Qt.labs.platform::MenuItemGroup::checkedItem
+
+ This property holds the currently checked item in the group, or \c null if no item is checked.
+*/
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::checkedItem() const
+{
+ return m_checkedItem;
+}
+
+void QQuickLabsPlatformMenuItemGroup::setCheckedItem(QQuickLabsPlatformMenuItem *item)
+{
+ if (m_checkedItem == item)
+ return;
+
+ if (m_checkedItem)
+ m_checkedItem->setChecked(false);
+
+ m_checkedItem = item;
+ emit checkedItemChanged();
+
+ if (item)
+ item->setChecked(true);
+}
+
+/*!
+ \qmlproperty list<MenuItem> Qt.labs.platform::MenuItemGroup::items
+
+ This property holds the list of items in the group.
+*/
+QQmlListProperty<QQuickLabsPlatformMenuItem> QQuickLabsPlatformMenuItemGroup::items()
+{
+ return QQmlListProperty<QQuickLabsPlatformMenuItem>(this, nullptr, items_append, items_count, items_at, items_clear);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::addItem(MenuItem item)
+
+ Adds an \a item to the group.
+*/
+void QQuickLabsPlatformMenuItemGroup::addItem(QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || m_items.contains(item))
+ return;
+
+ m_items.append(item);
+ item->setGroup(this);
+
+ connect(item, &QQuickLabsPlatformMenuItem::checkedChanged, this, &QQuickLabsPlatformMenuItemGroup::updateCurrent);
+ connect(item, &QQuickLabsPlatformMenuItem::triggered, this, &QQuickLabsPlatformMenuItemGroup::activateItem);
+ connect(item, &QQuickLabsPlatformMenuItem::hovered, this, &QQuickLabsPlatformMenuItemGroup::hoverItem);
+
+ if (m_exclusive && item->isChecked())
+ setCheckedItem(item);
+
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::removeItem(MenuItem item)
+
+ Removes an \a item from the group.
+*/
+void QQuickLabsPlatformMenuItemGroup::removeItem(QQuickLabsPlatformMenuItem *item)
+{
+ if (!item || !m_items.contains(item))
+ return;
+
+ m_items.removeOne(item);
+ item->setGroup(nullptr);
+
+ disconnect(item, &QQuickLabsPlatformMenuItem::checkedChanged, this, &QQuickLabsPlatformMenuItemGroup::updateCurrent);
+ disconnect(item, &QQuickLabsPlatformMenuItem::triggered, this, &QQuickLabsPlatformMenuItemGroup::activateItem);
+ disconnect(item, &QQuickLabsPlatformMenuItem::hovered, this, &QQuickLabsPlatformMenuItemGroup::hoverItem);
+
+ if (m_checkedItem == item)
+ setCheckedItem(nullptr);
+
+ emit itemsChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::MenuItemGroup::clear()
+
+ Removes all items from the group.
+*/
+void QQuickLabsPlatformMenuItemGroup::clear()
+{
+ if (m_items.isEmpty())
+ return;
+
+ for (QQuickLabsPlatformMenuItem *item : qAsConst(m_items)) {
+ item->setGroup(nullptr);
+ disconnect(item, &QQuickLabsPlatformMenuItem::checkedChanged, this, &QQuickLabsPlatformMenuItemGroup::updateCurrent);
+ disconnect(item, &QQuickLabsPlatformMenuItem::triggered, this, &QQuickLabsPlatformMenuItemGroup::activateItem);
+ disconnect(item, &QQuickLabsPlatformMenuItem::hovered, this, &QQuickLabsPlatformMenuItemGroup::hoverItem);
+ }
+
+ setCheckedItem(nullptr);
+
+ m_items.clear();
+ emit itemsChanged();
+}
+
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::findCurrent() const
+{
+ for (QQuickLabsPlatformMenuItem *item : m_items) {
+ if (item->isChecked())
+ return item;
+ }
+ return nullptr;
+}
+
+void QQuickLabsPlatformMenuItemGroup::updateCurrent()
+{
+ if (!m_exclusive)
+ return;
+
+ QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(sender());
+ if (item && item->isChecked())
+ setCheckedItem(item);
+}
+
+void QQuickLabsPlatformMenuItemGroup::activateItem()
+{
+ QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(sender());
+ if (item)
+ emit triggered(item);
+}
+
+void QQuickLabsPlatformMenuItemGroup::hoverItem()
+{
+ QQuickLabsPlatformMenuItem *item = qobject_cast<QQuickLabsPlatformMenuItem*>(sender());
+ if (item)
+ emit hovered(item);
+}
+
+void QQuickLabsPlatformMenuItemGroup::items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, QQuickLabsPlatformMenuItem *item)
+{
+ QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
+ group->addItem(item);
+}
+
+qsizetype QQuickLabsPlatformMenuItemGroup::items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop)
+{
+ QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
+ return group->m_items.count();
+}
+
+QQuickLabsPlatformMenuItem *QQuickLabsPlatformMenuItemGroup::items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, qsizetype index)
+{
+ QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
+ return group->m_items.value(index);
+}
+
+void QQuickLabsPlatformMenuItemGroup::items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop)
+{
+ QQuickLabsPlatformMenuItemGroup *group = static_cast<QQuickLabsPlatformMenuItemGroup *>(prop->object);
+ group->clear();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenuitemgroup_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmenuitemgroup_p.h b/src/labs/platform/qquicklabsplatformmenuitemgroup_p.h
new file mode 100644
index 0000000000..2dc60a70d2
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuitemgroup_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMENUITEMGROUP_P_H
+#define QQUICKLABSPLATFORMMENUITEMGROUP_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/qlist.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformMenuItem;
+class QQuickLabsPlatformMenuItemGroupPrivate;
+
+class QQuickLabsPlatformMenuItemGroup : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive NOTIFY exclusiveChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenuItem *checkedItem READ checkedItem WRITE setCheckedItem NOTIFY checkedItemChanged FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickLabsPlatformMenuItem> items READ items NOTIFY itemsChanged FINAL)
+
+public:
+ explicit QQuickLabsPlatformMenuItemGroup(QObject *parent = nullptr);
+ ~QQuickLabsPlatformMenuItemGroup();
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ bool isExclusive() const;
+ void setExclusive(bool exclusive);
+
+ QQuickLabsPlatformMenuItem *checkedItem() const;
+ void setCheckedItem(QQuickLabsPlatformMenuItem *item);
+
+ QQmlListProperty<QQuickLabsPlatformMenuItem> items();
+
+ Q_INVOKABLE void addItem(QQuickLabsPlatformMenuItem *item);
+ Q_INVOKABLE void removeItem(QQuickLabsPlatformMenuItem *item);
+ Q_INVOKABLE void clear();
+
+Q_SIGNALS:
+ void triggered(QQuickLabsPlatformMenuItem *item);
+ void hovered(QQuickLabsPlatformMenuItem *item);
+
+ void enabledChanged();
+ void visibleChanged();
+ void exclusiveChanged();
+ void checkedItemChanged();
+ void itemsChanged();
+
+private:
+ QQuickLabsPlatformMenuItem *findCurrent() const;
+ void updateCurrent();
+ void activateItem();
+ void hoverItem();
+
+ static void items_append(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, QQuickLabsPlatformMenuItem *obj);
+ static qsizetype items_count(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop);
+ static QQuickLabsPlatformMenuItem *items_at(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop, qsizetype index);
+ static void items_clear(QQmlListProperty<QQuickLabsPlatformMenuItem> *prop);
+
+ bool m_enabled;
+ bool m_visible;
+ bool m_exclusive;
+ QQuickLabsPlatformMenuItem *m_checkedItem;
+ QList<QQuickLabsPlatformMenuItem*> m_items;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMenuItemGroup)
+
+#endif // QQUICKLABSPLATFORMMENUITEMGROUP_P_H
diff --git a/src/labs/platform/qquicklabsplatformmenuseparator.cpp b/src/labs/platform/qquicklabsplatformmenuseparator.cpp
new file mode 100644
index 0000000000..c3c2dd80df
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuseparator.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmenuseparator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuSeparator
+ \inherits MenuItem
+//! \instantiates QQuickLabsPlatformMenuSeparator
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native menu separator.
+
+ The MenuSeparator type is provided for convenience. It is a MenuItem
+ that has the \l {MenuItem::}{separator} property set to \c true by default.
+
+ \image qtlabsplatform-menubar.png
+
+ \labs
+
+ \sa Menu, MenuItem
+*/
+
+QQuickLabsPlatformMenuSeparator::QQuickLabsPlatformMenuSeparator(QObject *parent)
+ : QQuickLabsPlatformMenuItem(parent)
+{
+ setSeparator(true);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmenuseparator_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmenuseparator_p.h b/src/labs/platform/qquicklabsplatformmenuseparator_p.h
new file mode 100644
index 0000000000..d77903dda8
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmenuseparator_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMENUSEPARATOR_P_H
+#define QQUICKLABSPLATFORMMENUSEPARATOR_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 "qquicklabsplatformmenuitem_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformMenuSeparator : public QQuickLabsPlatformMenuItem
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickLabsPlatformMenuSeparator(QObject *parent = nullptr);
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMenuSeparator)
+
+#endif // QQUICKLABSPLATFORMMENUSEPARATOR_P_H
diff --git a/src/labs/platform/qquicklabsplatformmessagedialog.cpp b/src/labs/platform/qquicklabsplatformmessagedialog.cpp
new file mode 100644
index 0000000000..83ec2d9fd1
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmessagedialog.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformmessagedialog_p.h"
+
+#include <QtQml/qqmlinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MessageDialog
+ \inherits Dialog
+//! \instantiates QQuickLabsPlatformMessageDialog
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A native message dialog.
+
+ The MessageDialog type provides a QML API for native platform message dialogs.
+
+ \image qtlabsplatform-messagedialog-android.png
+
+ A message dialog is used to inform the user, or ask the user a question.
+ A message dialog displays a primary \l text to alert the user to a situation,
+ an \l {informativeText}{informative text} to further explain the alert or to
+ ask the user a question, and an optional \l {detailedText}{detailed text} to
+ provide even more data if the user requests it. A message box can also display
+ a configurable set of \l buttons for accepting a user response.
+
+ To show a message dialog, construct an instance of MessageDialog, set the
+ desired properties, and call \l {Dialog::}{open()}.
+
+ \code
+ MessageDialog {
+ buttons: MessageDialog.Ok
+ text: "The document has been modified."
+ }
+ \endcode
+
+ The user must click the \uicontrol OK button to dismiss the message dialog.
+ A modal message dialog blocks the rest of the GUI until the message is
+ dismissed.
+
+ A more elaborate approach than just alerting the user to an event is to
+ also ask the user what to do about it. Store the question in the
+ \l {informativeText}{informative text} property, and specify the \l buttons
+ property to the set of buttons you want as the set of user responses. The
+ buttons are specified by combining values using the bitwise OR operator. The
+ display order for the buttons is platform dependent.
+
+ \code
+ MessageDialog {
+ text: "The document has been modified."
+ informativeText: "Do you want to save your changes?"
+ buttons: MessageDialog.Ok | MessageDialog.Cancel
+
+ onAccepted: document.save()
+ }
+ \endcode
+
+ \image qtlabsplatform-messagedialog-informative-android.png
+
+ The \l clicked() signal passes the information of which button was clicked.
+
+ A native platform message dialog is currently available on the following platforms:
+
+ \list
+ \li iOS
+ \li Android
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::clicked(button)
+
+ This signal is emitted when a dialog \a button is clicked.
+
+ \sa buttons
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::okClicked()
+
+ This signal is emitted when \uicontrol Ok is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::saveClicked()
+
+ This signal is emitted when \uicontrol Save is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::saveAllClicked()
+
+ This signal is emitted when \uicontrol {Save All} is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::openClicked()
+
+ This signal is emitted when \uicontrol Open is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::yesClicked()
+
+ This signal is emitted when \uicontrol Yes is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::yesToAllClicked()
+
+ This signal is emitted when \uicontrol {Yes To All} is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::noClicked()
+
+ This signal is emitted when \uicontrol No is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::noToAllClicked()
+
+ This signal is emitted when \uicontrol {No To All} is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::abortClicked()
+
+ This signal is emitted when \uicontrol Abort is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::retryClicked()
+
+ This signal is emitted when \uicontrol Retry is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::ignoreClicked()
+
+ This signal is emitted when \uicontrol Ignore is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::closeClicked()
+
+ This signal is emitted when \uicontrol Close is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::cancelClicked()
+
+ This signal is emitted when \uicontrol Cancel is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::discardClicked()
+
+ This signal is emitted when \uicontrol Discard is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::helpClicked()
+
+ This signal is emitted when \uicontrol Help is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::applyClicked()
+
+ This signal is emitted when \uicontrol Apply is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::resetClicked()
+
+ This signal is emitted when \uicontrol Reset is clicked.
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::MessageDialog::restoreDefaultsClicked()
+
+ This signal is emitted when \uicontrol {Restore Defaults} is clicked.
+*/
+
+QQuickLabsPlatformMessageDialog::QQuickLabsPlatformMessageDialog(QObject *parent)
+ : QQuickLabsPlatformDialog(QPlatformTheme::MessageDialog, parent),
+ m_options(QMessageDialogOptions::create())
+{
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MessageDialog::text
+
+ This property holds the text to be displayed on the message dialog.
+
+ \sa informativeText, detailedText
+*/
+QString QQuickLabsPlatformMessageDialog::text() const
+{
+ return m_options->text();
+}
+
+void QQuickLabsPlatformMessageDialog::setText(const QString &text)
+{
+ if (m_options->text() == text)
+ return;
+
+ m_options->setText(text);
+ emit textChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MessageDialog::informativeText
+
+ This property holds the informative text that provides a fuller description for the message.
+
+ Informative text can be used to expand upon the \l text to give more information to the user.
+
+ \sa text, detailedText
+*/
+QString QQuickLabsPlatformMessageDialog::informativeText() const
+{
+ return m_options->informativeText();
+}
+
+void QQuickLabsPlatformMessageDialog::setInformativeText(const QString &text)
+{
+ if (m_options->informativeText() == text)
+ return;
+
+ m_options->setInformativeText(text);
+ emit informativeTextChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::MessageDialog::detailedText
+
+ This property holds the text to be displayed in the details area.
+
+ \sa text, informativeText
+*/
+QString QQuickLabsPlatformMessageDialog::detailedText() const
+{
+ return m_options->detailedText();
+}
+
+void QQuickLabsPlatformMessageDialog::setDetailedText(const QString &text)
+{
+ if (m_options->detailedText() == text)
+ return;
+
+ m_options->setDetailedText(text);
+ emit detailedTextChanged();
+}
+
+/*!
+ \qmlproperty flags Qt.labs.platform::MessageDialog::buttons
+
+ This property holds a combination of buttons that are used by the message dialog.
+ The default value is \c MessageDialog.NoButton.
+
+ Possible flags:
+ \value MessageDialog.Ok An "OK" button defined with the \c AcceptRole.
+ \value MessageDialog.Open An "Open" button defined with the \c AcceptRole.
+ \value MessageDialog.Save A "Save" button defined with the \c AcceptRole.
+ \value MessageDialog.Cancel A "Cancel" button defined with the \c RejectRole.
+ \value MessageDialog.Close A "Close" button defined with the \c RejectRole.
+ \value MessageDialog.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
+ \value MessageDialog.Apply An "Apply" button defined with the \c ApplyRole.
+ \value MessageDialog.Reset A "Reset" button defined with the \c ResetRole.
+ \value MessageDialog.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
+ \value MessageDialog.Help A "Help" button defined with the \c HelpRole.
+ \value MessageDialog.SaveAll A "Save All" button defined with the \c AcceptRole.
+ \value MessageDialog.Yes A "Yes" button defined with the \c YesRole.
+ \value MessageDialog.YesToAll A "Yes to All" button defined with the \c YesRole.
+ \value MessageDialog.No A "No" button defined with the \c NoRole.
+ \value MessageDialog.NoToAll A "No to All" button defined with the \c NoRole.
+ \value MessageDialog.Abort An "Abort" button defined with the \c RejectRole.
+ \value MessageDialog.Retry A "Retry" button defined with the \c AcceptRole.
+ \value MessageDialog.Ignore An "Ignore" button defined with the \c AcceptRole.
+ \value MessageDialog.NoButton The dialog has no buttons.
+
+ \sa clicked()
+*/
+QPlatformDialogHelper::StandardButtons QQuickLabsPlatformMessageDialog::buttons() const
+{
+ return m_options->standardButtons();
+}
+
+void QQuickLabsPlatformMessageDialog::setButtons(QPlatformDialogHelper::StandardButtons buttons)
+{
+ if (m_options->standardButtons() == buttons)
+ return;
+
+ m_options->setStandardButtons(buttons);
+ emit buttonsChanged();
+}
+
+void QQuickLabsPlatformMessageDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformMessageDialogHelper *messageDialog = qobject_cast<QPlatformMessageDialogHelper *>(dialog)) {
+ connect(messageDialog, &QPlatformMessageDialogHelper::clicked, this, &QQuickLabsPlatformMessageDialog::handleClick);
+ messageDialog->setOptions(m_options);
+ }
+}
+
+void QQuickLabsPlatformMessageDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformMessageDialogHelper *messageDialog = qobject_cast<QPlatformMessageDialogHelper *>(dialog))
+ messageDialog->setOptions(m_options);
+}
+
+void QQuickLabsPlatformMessageDialog::handleClick(QPlatformDialogHelper::StandardButton button)
+{
+ done(button);
+ emit clicked(button);
+
+ switch (button) {
+ case QPlatformDialogHelper::Ok: emit okClicked(); break;
+ case QPlatformDialogHelper::Save: emit saveClicked(); break;
+ case QPlatformDialogHelper::SaveAll: emit saveAllClicked(); break;
+ case QPlatformDialogHelper::Open: emit openClicked(); break;
+ case QPlatformDialogHelper::Yes: emit yesClicked(); break;
+ case QPlatformDialogHelper::YesToAll: emit yesToAllClicked(); break;
+ case QPlatformDialogHelper::No: emit noClicked(); break;
+ case QPlatformDialogHelper::NoToAll: emit noToAllClicked(); break;
+ case QPlatformDialogHelper::Abort: emit abortClicked(); break;
+ case QPlatformDialogHelper::Retry: emit retryClicked(); break;
+ case QPlatformDialogHelper::Ignore: emit ignoreClicked(); break;
+ case QPlatformDialogHelper::Close: emit closeClicked(); break;
+ case QPlatformDialogHelper::Cancel: emit cancelClicked(); break;
+ case QPlatformDialogHelper::Discard: emit discardClicked(); break;
+ case QPlatformDialogHelper::Help: emit helpClicked(); break;
+ case QPlatformDialogHelper::Apply: emit applyClicked(); break;
+ case QPlatformDialogHelper::Reset: emit resetClicked(); break;
+ case QPlatformDialogHelper::RestoreDefaults: emit restoreDefaultsClicked(); break;
+ default: qmlWarning(this) << "unknown button" << int(button); break;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformmessagedialog_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformmessagedialog_p.h b/src/labs/platform/qquicklabsplatformmessagedialog_p.h
new file mode 100644
index 0000000000..af5ee25241
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformmessagedialog_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMMESSAGEDIALOG_P_H
+#define QQUICKLABSPLATFORMMESSAGEDIALOG_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 "qquicklabsplatformdialog_p.h"
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformMessageDialog : public QQuickLabsPlatformDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged FINAL)
+ Q_PROPERTY(QString detailedText READ detailedText WRITE setDetailedText NOTIFY detailedTextChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::StandardButtons buttons READ buttons WRITE setButtons NOTIFY buttonsChanged FINAL)
+ Q_FLAGS(QPlatformDialogHelper::StandardButtons)
+
+public:
+ explicit QQuickLabsPlatformMessageDialog(QObject *parent = nullptr);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ QString informativeText() const;
+ void setInformativeText(const QString &text);
+
+ QString detailedText() const;
+ void setDetailedText(const QString &text);
+
+ QPlatformDialogHelper::StandardButtons buttons() const;
+ void setButtons(QPlatformDialogHelper::StandardButtons buttons);
+
+Q_SIGNALS:
+ void textChanged();
+ void informativeTextChanged();
+ void detailedTextChanged();
+ void buttonsChanged();
+ void clicked(QPlatformDialogHelper::StandardButton button);
+
+ void okClicked();
+ void saveClicked();
+ void saveAllClicked();
+ void openClicked();
+ void yesClicked();
+ void yesToAllClicked();
+ void noClicked();
+ void noToAllClicked();
+ void abortClicked();
+ void retryClicked();
+ void ignoreClicked();
+ void closeClicked();
+ void cancelClicked();
+ void discardClicked();
+ void helpClicked();
+ void applyClicked();
+ void resetClicked();
+ void restoreDefaultsClicked();
+
+protected:
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+
+private Q_SLOTS:
+ void handleClick(QPlatformDialogHelper::StandardButton button);
+
+private:
+ QSharedPointer<QMessageDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformMessageDialog)
+
+#endif // QQUICKLABSPLATFORMMESSAGEDIALOG_P_H
diff --git a/src/labs/platform/qquicklabsplatformstandardpaths.cpp b/src/labs/platform/qquicklabsplatformstandardpaths.cpp
new file mode 100644
index 0000000000..33e40b8517
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformstandardpaths.cpp
@@ -0,0 +1,175 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformstandardpaths_p.h"
+
+#include <QtQml/qqmlengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype StandardPaths
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformStandardPaths
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief Provides access to the standard system paths.
+
+ The StandardPaths singleton type provides methods for querying the standard
+ system paths. The standard paths are mostly useful in conjunction with the
+ FileDialog and FolderDialog types.
+
+ \qml
+ FileDialog {
+ folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
+ }
+ \endqml
+
+ \labs
+
+ \sa FileDialog, FolderDialog, QStandardPaths
+*/
+
+static QList<QUrl> toUrlList(const QStringList &paths)
+{
+ QList<QUrl> urls;
+ urls.reserve(paths.size());
+ for (const QString &path : paths)
+ urls += QUrl::fromLocalFile(path);
+ return urls;
+}
+
+QQuickLabsPlatformStandardPaths::QQuickLabsPlatformStandardPaths(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QObject *QQuickLabsPlatformStandardPaths::create(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+ Q_UNUSED(scriptEngine);
+ return new QQuickLabsPlatformStandardPaths(engine);
+}
+
+/*!
+ \qmlmethod string Qt.labs.platform::StandardPaths::displayName(StandardLocation type)
+
+ \include standardpath/functiondocs.qdocinc displayName
+
+ \sa QStandardPaths::displayName()
+*/
+QString QQuickLabsPlatformStandardPaths::displayName(QStandardPaths::StandardLocation type)
+{
+ return QStandardPaths::displayName(type);
+}
+
+/*!
+ \qmlmethod url Qt.labs.platform::StandardPaths::findExecutable(string executableName, list<string> paths)
+
+ \include standardpath/functiondocs.qdocinc findExecutable
+
+ \sa QStandardPaths::findExecutable()
+*/
+QUrl QQuickLabsPlatformStandardPaths::findExecutable(const QString &executableName, const QStringList &paths)
+{
+ return QUrl::fromLocalFile(QStandardPaths::findExecutable(executableName, paths));
+}
+
+/*!
+ \qmlmethod url Qt.labs.platform::StandardPaths::locate(StandardLocation type, string fileName, LocateOptions options)
+
+ \include standardpath/functiondocs.qdocinc locate
+
+ \sa QStandardPaths::locate()
+*/
+QUrl QQuickLabsPlatformStandardPaths::locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
+{
+ return QUrl::fromLocalFile(QStandardPaths::locate(type, fileName, options));
+}
+
+/*!
+ \qmlmethod list<url> Qt.labs.platform::StandardPaths::locateAll(StandardLocation type, string fileName, LocateOptions options)
+
+ \include standardpath/functiondocs.qdocinc locateAll
+
+ \sa QStandardPaths::locateAll()
+*/
+QList<QUrl> QQuickLabsPlatformStandardPaths::locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
+{
+ return toUrlList(QStandardPaths::locateAll(type, fileName, options));
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::StandardPaths::setTestModeEnabled(bool testMode)
+
+ \include standardpath/functiondocs.qdocinc setTestModeEnabled
+
+ \sa QStandardPaths::setTestModeEnabled()
+*/
+void QQuickLabsPlatformStandardPaths::setTestModeEnabled(bool testMode)
+{
+ QStandardPaths::setTestModeEnabled(testMode);
+}
+
+/*!
+ \qmlmethod list<url> Qt.labs.platform::StandardPaths::standardLocations(StandardLocation type)
+
+ \include standardpath/functiondocs.qdocinc standardLocations
+
+ \sa QStandardPaths::standardLocations()
+*/
+QList<QUrl> QQuickLabsPlatformStandardPaths::standardLocations(QStandardPaths::StandardLocation type)
+{
+ return toUrlList(QStandardPaths::standardLocations(type));
+}
+
+/*!
+ \qmlmethod url Qt.labs.platform::StandardPaths::writableLocation(StandardLocation type)
+
+ \include standardpath/functiondocs.qdocinc writableLocation
+
+ \sa QStandardPaths::writableLocation()
+*/
+QUrl QQuickLabsPlatformStandardPaths::writableLocation(QStandardPaths::StandardLocation type)
+{
+ return QUrl::fromLocalFile(QStandardPaths::writableLocation(type));
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformstandardpaths_p.cpp"
diff --git a/src/quick/designer/qquickdesignerwindowmanager_p.h b/src/labs/platform/qquicklabsplatformstandardpaths_p.h
index ac9695953f..2dd3247e72 100644
--- a/src/quick/designer/qquickdesignerwindowmanager_p.h
+++ b/src/labs/platform/qquicklabsplatformstandardpaths_p.h
@@ -1,9 +1,9 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
-** This file is part of the QtQuick module of the Qt Toolkit.
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -37,8 +37,8 @@
**
****************************************************************************/
-#ifndef DESIGNERWINDOWMANAGER_P_H
-#define DESIGNERWINDOWMANAGER_P_H
+#ifndef QQUICKLABSPLATFORMSTANDARDPATHS_P_H
+#define QQUICKLABSPLATFORMSTANDARDPATHS_P_H
//
// W A R N I N G
@@ -51,58 +51,42 @@
// We mean it.
//
-#include <QtCore/QScopedPointer>
-
-#include <private/qsgrenderloop_p.h>
-#include <private/qtquickglobal_p.h>
-#include <private/qsgcontext_p.h>
-
-#if QT_CONFIG(opengl)
-# include <QOpenGLContext>
-#endif
+#include <QtCore/qobject.h>
+#include <QtCore/qstandardpaths.h>
+#include <QtCore/qurl.h>
+#include <QtQml/qqml.h>
QT_BEGIN_NAMESPACE
-class QQuickWindow;
-class QSGContext;
-class QSGDefaultRenderContext;
-class QAnimationDriver;
+class QQmlEngine;
+class QJSEngine;
-class QQuickDesignerWindowManager : public QSGRenderLoop
+class QQuickLabsPlatformStandardPaths : public QObject
{
Q_OBJECT
-public:
- QQuickDesignerWindowManager();
-
- void show(QQuickWindow *window) override;
- void hide(QQuickWindow *window) override;
-
- void windowDestroyed(QQuickWindow *window) override;
+ Q_ENUMS(QStandardPaths::StandardLocation QStandardPaths::LocateOptions)
- void makeOpenGLContext(QQuickWindow *window);
- void exposureChanged(QQuickWindow *window) override;
- QImage grab(QQuickWindow *window) override;
-
- void maybeUpdate(QQuickWindow *window) override;
- void update(QQuickWindow *window) override; // identical for this implementation.
-
- void releaseResources(QQuickWindow *) override { }
-
- QAnimationDriver *animationDriver() const override { return nullptr; }
+public:
+ explicit QQuickLabsPlatformStandardPaths(QObject *parent = nullptr);
- QSGContext *sceneGraphContext() const override;
- QSGRenderContext *createRenderContext(QSGContext *) const override { return m_renderContext.data(); }
+ static QObject *create(QQmlEngine *engine, QJSEngine *scriptEngine);
- static void createOpenGLContext(QQuickWindow *window);
+ Q_INVOKABLE static QString displayName(QStandardPaths::StandardLocation type);
+ Q_INVOKABLE static QUrl findExecutable(const QString &executableName, const QStringList &paths = QStringList());
+ Q_INVOKABLE static QUrl locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile);
+ Q_INVOKABLE static QList<QUrl> locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile);
+ Q_INVOKABLE static void setTestModeEnabled(bool testMode);
+ Q_INVOKABLE static QList<QUrl> standardLocations(QStandardPaths::StandardLocation type);
+ Q_INVOKABLE static QUrl writableLocation(QStandardPaths::StandardLocation type);
private:
-#if QT_CONFIG(opengl)
- QScopedPointer<QOpenGLContext> m_openGlContext;
-#endif
- QScopedPointer<QSGContext> m_sgContext;
- QScopedPointer<QSGRenderContext> m_renderContext;
+ Q_DISABLE_COPY(QQuickLabsPlatformStandardPaths)
};
QT_END_NAMESPACE
-#endif // DESIGNERWINDOWMANAGER_P_H
+QML_DECLARE_TYPE(QQuickLabsPlatformStandardPaths)
+Q_DECLARE_METATYPE(QStandardPaths::StandardLocation)
+Q_DECLARE_METATYPE(QStandardPaths::LocateOptions)
+
+#endif // QQUICKLABSPLATFORMSTANDARDPATHS_P_H
diff --git a/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp b/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp
new file mode 100644
index 0000000000..d3bb83aeed
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformsystemtrayicon.cpp
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabsplatformsystemtrayicon_p.h"
+#include "qquicklabsplatformmenu_p.h"
+#include "qquicklabsplatformiconloader_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include "widgets/qwidgetplatform_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SystemTrayIcon
+ \inherits QtObject
+//! \instantiates QQuickLabsPlatformSystemTrayIcon
+ \inqmlmodule Qt.labs.platform
+ \since 5.8
+ \brief A system tray icon.
+
+ The SystemTrayIcon type provides an icon for an application in the system tray.
+
+ Many desktop platforms provide a special system tray or notification area,
+ where applications can display icons and notification messages.
+
+ \image qtlabsplatform-systemtrayicon.png
+
+ The following example shows how to create a system tray icon, and how to make
+ use of the \l activated() signal:
+
+ \code
+ SystemTrayIcon {
+ visible: true
+ icon.source: "qrc:/images/tray-icon.png"
+
+ onActivated: {
+ window.show()
+ window.raise()
+ window.requestActivate()
+ }
+ }
+ \endcode
+
+ \section2 Tray menu
+
+ SystemTrayIcon can have a menu that opens when the icon is activated.
+
+ \image qtlabsplatform-systemtrayicon-menu.png
+
+ The following example illustrates how to assign a \l Menu to a system tray icon:
+
+ \code
+ SystemTrayIcon {
+ visible: true
+ icon.source: "qrc:/images/tray-icon.png"
+
+ menu: Menu {
+ MenuItem {
+ text: qsTr("Quit")
+ onTriggered: Qt.quit()
+ }
+ }
+ }
+ \endcode
+
+ \section2 Notification messages
+
+ SystemTrayIcon can display notification messages.
+
+ \image qtlabsplatform-systemtrayicon-message.png
+
+ The following example presents how to show a notification message using
+ \l showMessage(), and how to make use of the \l messageClicked() signal:
+
+ \code
+ SystemTrayIcon {
+ visible: true
+ icon.source: "qrc:/images/tray-icon.png"
+
+ onMessageClicked: console.log("Message clicked")
+ Component.onCompleted: showMessage("Message title", "Something important came up. Click this to know more.")
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native system tray icon is currently \l available on the following platforms:
+
+ \list
+ \li All window managers and independent tray implementations for X11 that implement the
+ \l{http://standards.freedesktop.org/systemtray-spec/systemtray-spec-0.2.html}
+ {freedesktop.org XEmbed system tray specification}.
+ \li All desktop environments that implement the
+ \l{http://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem}
+ {freedesktop.org D-Bus StatusNotifierItem specification}, including recent versions of KDE and Unity.
+ \li All supported versions of macOS. Note that the Growl notification system must be installed
+ for showMessage() to display messages on OS X prior to 10.8 (Mountain Lion).
+ \endlist
+
+ \input includes/widgets.qdocinc 1
+
+ \labs
+
+ \sa Menu
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::SystemTrayIcon::activated(ActivationReason reason)
+
+ This signal is emitted when the system tray icon is activated by the user. The
+ \a reason argument specifies how the system tray icon was activated.
+
+ Available reasons:
+
+ \value SystemTrayIcon.Unknown Unknown reason
+ \value SystemTrayIcon.Context The context menu for the system tray icon was requested
+ \value SystemTrayIcon.DoubleClick The system tray icon was double clicked
+ \value SystemTrayIcon.Trigger The system tray icon was clicked
+ \value SystemTrayIcon.MiddleClick The system tray icon was clicked with the middle mouse button
+*/
+
+/*!
+ \qmlsignal Qt.labs.platform::SystemTrayIcon::messageClicked()
+
+ This signal is emitted when a notification message is clicked by the user.
+
+ \sa showMessage()
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(qtLabsPlatformTray)
+
+QQuickLabsPlatformSystemTrayIcon::QQuickLabsPlatformSystemTrayIcon(QObject *parent)
+ : QObject(parent),
+ m_complete(false),
+ m_visible(false),
+ m_menu(nullptr),
+ m_iconLoader(nullptr),
+ m_handle(nullptr)
+{
+ m_handle = QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon();
+ if (!m_handle)
+ m_handle = QWidgetPlatform::createSystemTrayIcon(this);
+ qCDebug(qtLabsPlatformTray) << "SystemTrayIcon ->" << m_handle;
+
+ if (m_handle) {
+ connect(m_handle, &QPlatformSystemTrayIcon::activated, this, &QQuickLabsPlatformSystemTrayIcon::activated);
+ connect(m_handle, &QPlatformSystemTrayIcon::messageClicked, this, &QQuickLabsPlatformSystemTrayIcon::messageClicked);
+ }
+}
+
+QQuickLabsPlatformSystemTrayIcon::~QQuickLabsPlatformSystemTrayIcon()
+{
+ if (m_menu)
+ m_menu->setSystemTrayIcon(nullptr);
+ cleanup();
+ delete m_iconLoader;
+ m_iconLoader = nullptr;
+ delete m_handle;
+ m_handle = nullptr;
+}
+
+QPlatformSystemTrayIcon *QQuickLabsPlatformSystemTrayIcon::handle() const
+{
+ return m_handle;
+}
+
+/*!
+ \readonly
+ \qmlproperty bool Qt.labs.platform::SystemTrayIcon::available
+
+ This property holds whether the system tray is available.
+*/
+bool QQuickLabsPlatformSystemTrayIcon::isAvailable() const
+{
+ return m_handle && m_handle->isSystemTrayAvailable();
+}
+
+/*!
+ \readonly
+ \qmlproperty bool Qt.labs.platform::SystemTrayIcon::supportsMessages
+
+ This property holds whether the system tray icon supports notification messages.
+
+ \sa showMessage()
+*/
+bool QQuickLabsPlatformSystemTrayIcon::supportsMessages() const
+{
+ return m_handle && m_handle->supportsMessages();
+}
+
+/*!
+ \qmlproperty bool Qt.labs.platform::SystemTrayIcon::visible
+
+ This property holds whether the system tray icon is visible.
+
+ The default value is \c false.
+*/
+bool QQuickLabsPlatformSystemTrayIcon::isVisible() const
+{
+ return m_visible;
+}
+
+void QQuickLabsPlatformSystemTrayIcon::setVisible(bool visible)
+{
+ if (m_visible == visible)
+ return;
+
+ if (m_handle && m_complete) {
+ if (visible)
+ init();
+ else
+ cleanup();
+ }
+
+ m_visible = visible;
+ emit visibleChanged();
+}
+
+/*!
+ \qmlproperty string Qt.labs.platform::SystemTrayIcon::tooltip
+
+ This property holds the tooltip of the system tray icon.
+*/
+QString QQuickLabsPlatformSystemTrayIcon::tooltip() const
+{
+ return m_tooltip;
+}
+
+void QQuickLabsPlatformSystemTrayIcon::setTooltip(const QString &tooltip)
+{
+ if (m_tooltip == tooltip)
+ return;
+
+ if (m_handle && m_complete)
+ m_handle->updateToolTip(tooltip);
+
+ m_tooltip = tooltip;
+ emit tooltipChanged();
+}
+
+/*!
+ \qmlproperty Menu Qt.labs.platform::SystemTrayIcon::menu
+
+ This property holds a menu for the system tray icon.
+*/
+QQuickLabsPlatformMenu *QQuickLabsPlatformSystemTrayIcon::menu() const
+{
+ return m_menu;
+}
+
+void QQuickLabsPlatformSystemTrayIcon::setMenu(QQuickLabsPlatformMenu *menu)
+{
+ if (m_menu == menu)
+ return;
+
+ if (m_menu)
+ m_menu->setSystemTrayIcon(nullptr);
+ if (menu) {
+ menu->setSystemTrayIcon(this);
+ if (m_handle && m_complete && menu->create())
+ m_handle->updateMenu(menu->handle());
+ }
+
+ m_menu = menu;
+ emit menuChanged();
+}
+
+/*!
+ \since Qt.labs.platform 1.1 (Qt 5.12)
+ \qmlproperty rect Qt.labs.platform::SystemTrayIcon::geometry
+
+ This property holds the geometry of the system tray icon.
+*/
+QRect QQuickLabsPlatformSystemTrayIcon::geometry() const
+{
+ return m_handle ? m_handle->geometry() : QRect();
+}
+
+/*!
+ \since Qt.labs.platform 1.1 (Qt 5.12)
+ \qmlproperty url Qt.labs.platform::SystemTrayIcon::icon.source
+ \qmlproperty string Qt.labs.platform::SystemTrayIcon::icon.name
+ \qmlproperty bool Qt.labs.platform::SystemTrayIcon::icon.mask
+
+ This property holds the system tray icon.
+
+ \code
+ SystemTrayIcon {
+ icon.mask: true
+ icon.source: "qrc:/images/tray-icon.png"
+ }
+ \endcode
+*/
+QQuickLabsPlatformIcon QQuickLabsPlatformSystemTrayIcon::icon() const
+{
+ if (!m_iconLoader)
+ return QQuickLabsPlatformIcon();
+
+ return m_iconLoader->icon();
+}
+
+void QQuickLabsPlatformSystemTrayIcon::setIcon(const QQuickLabsPlatformIcon &icon)
+{
+ if (iconLoader()->icon() == icon)
+ return;
+
+ iconLoader()->setIcon(icon);
+ emit iconChanged();
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::SystemTrayIcon::show()
+
+ Shows the system tray icon.
+*/
+void QQuickLabsPlatformSystemTrayIcon::show()
+{
+ setVisible(true);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::SystemTrayIcon::hide()
+
+ Hides the system tray icon.
+*/
+void QQuickLabsPlatformSystemTrayIcon::hide()
+{
+ setVisible(false);
+}
+
+/*!
+ \qmlmethod void Qt.labs.platform::SystemTrayIcon::showMessage(string title, string message, MessageIcon icon, int msecs)
+
+ Shows a system tray message with the given \a title, \a message and \a icon
+ for the time specified in \a msecs.
+
+ \note System tray messages are dependent on the system configuration and user preferences,
+ and may not appear at all. Therefore, it should not be relied upon as the sole means for providing
+ critical information.
+
+ \sa supportsMessages, messageClicked()
+*/
+void QQuickLabsPlatformSystemTrayIcon::showMessage(const QString &title, const QString &msg, QPlatformSystemTrayIcon::MessageIcon icon, int msecs)
+{
+ if (m_handle)
+ m_handle->showMessage(title, msg, QIcon(), icon, msecs);
+}
+
+void QQuickLabsPlatformSystemTrayIcon::init()
+{
+ if (!m_handle)
+ return;
+
+ m_handle->init();
+ if (m_menu && m_menu->create())
+ m_handle->updateMenu(m_menu->handle());
+ m_handle->updateToolTip(m_tooltip);
+ if (m_iconLoader)
+ m_iconLoader->setEnabled(true);
+}
+
+void QQuickLabsPlatformSystemTrayIcon::cleanup()
+{
+ if (m_handle)
+ m_handle->cleanup();
+ if (m_iconLoader)
+ m_iconLoader->setEnabled(false);
+}
+
+void QQuickLabsPlatformSystemTrayIcon::classBegin()
+{
+}
+
+void QQuickLabsPlatformSystemTrayIcon::componentComplete()
+{
+ m_complete = true;
+ if (m_visible)
+ init();
+}
+
+QQuickLabsPlatformIconLoader *QQuickLabsPlatformSystemTrayIcon::iconLoader() const
+{
+ if (!m_iconLoader) {
+ QQuickLabsPlatformSystemTrayIcon *that = const_cast<QQuickLabsPlatformSystemTrayIcon *>(this);
+ static int slot = staticMetaObject.indexOfSlot("updateIcon()");
+ m_iconLoader = new QQuickLabsPlatformIconLoader(slot, that);
+ m_iconLoader->setEnabled(m_complete);
+ }
+ return m_iconLoader;
+}
+
+void QQuickLabsPlatformSystemTrayIcon::updateIcon()
+{
+ if (!m_handle || !m_iconLoader)
+ return;
+
+ const QRect oldGeometry = m_handle->geometry();
+
+ m_handle->updateIcon(m_iconLoader->toQIcon());
+
+ if (oldGeometry != m_handle->geometry())
+ emit geometryChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabsplatformsystemtrayicon_p.cpp"
diff --git a/src/labs/platform/qquicklabsplatformsystemtrayicon_p.h b/src/labs/platform/qquicklabsplatformsystemtrayicon_p.h
new file mode 100644
index 0000000000..f59fc55094
--- /dev/null
+++ b/src/labs/platform/qquicklabsplatformsystemtrayicon_p.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABSPLATFORMSYSTEMTRAYICON_P_H
+#define QQUICKLABSPLATFORMSYSTEMTRAYICON_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/qrect.h>
+#include <QtGui/qpa/qplatformsystemtrayicon.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqml.h>
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_REQUIRE_CONFIG(systemtrayicon);
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabsPlatformMenu;
+class QQuickLabsPlatformIconLoader;
+
+class QQuickLabsPlatformSystemTrayIcon : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(bool available READ isAvailable CONSTANT FINAL)
+ Q_PROPERTY(bool supportsMessages READ supportsMessages CONSTANT FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(QString tooltip READ tooltip WRITE setTooltip NOTIFY tooltipChanged FINAL)
+ Q_PROPERTY(QQuickLabsPlatformMenu *menu READ menu WRITE setMenu NOTIFY menuChanged FINAL)
+ Q_PROPERTY(QRect geometry READ geometry NOTIFY geometryChanged FINAL REVISION(1, 1))
+ Q_PROPERTY(QQuickLabsPlatformIcon icon READ icon WRITE setIcon NOTIFY iconChanged FINAL REVISION(1, 1))
+ Q_ENUMS(QPlatformSystemTrayIcon::ActivationReason QPlatformSystemTrayIcon::MessageIcon)
+
+public:
+ explicit QQuickLabsPlatformSystemTrayIcon(QObject *parent = nullptr);
+ ~QQuickLabsPlatformSystemTrayIcon();
+
+ QPlatformSystemTrayIcon *handle() const;
+
+ bool isAvailable() const;
+ bool supportsMessages() const;
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QString tooltip() const;
+ void setTooltip(const QString &tooltip);
+
+ QQuickLabsPlatformMenu *menu() const;
+ void setMenu(QQuickLabsPlatformMenu *menu);
+
+ QRect geometry() const;
+
+ QQuickLabsPlatformIcon icon() const;
+ void setIcon(const QQuickLabsPlatformIcon &icon);
+
+public Q_SLOTS:
+ void show();
+ void hide();
+
+ void showMessage(const QString &title, const QString &message,
+ QPlatformSystemTrayIcon::MessageIcon iconType = QPlatformSystemTrayIcon::Information, int msecs = 10000);
+
+Q_SIGNALS:
+ void activated(QPlatformSystemTrayIcon::ActivationReason reason);
+ void messageClicked();
+ void visibleChanged();
+ void tooltipChanged();
+ void menuChanged();
+ Q_REVISION(2, 1) void geometryChanged();
+ Q_REVISION(2, 1) void iconChanged();
+
+protected:
+ void init();
+ void cleanup();
+
+ void classBegin() override;
+ void componentComplete() override;
+
+ QQuickLabsPlatformIconLoader *iconLoader() const;
+
+private Q_SLOTS:
+ void updateIcon();
+
+private:
+ bool m_complete;
+ bool m_visible;
+ QString m_tooltip;
+ QQuickLabsPlatformMenu *m_menu;
+ mutable QQuickLabsPlatformIconLoader *m_iconLoader;
+ QPlatformSystemTrayIcon *m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabsPlatformSystemTrayIcon)
+Q_DECLARE_METATYPE(QPlatformSystemTrayIcon::ActivationReason)
+Q_DECLARE_METATYPE(QPlatformSystemTrayIcon::MessageIcon)
+
+#endif // QQUICKLABSPLATFORMSYSTEMTRAYICON_P_H
diff --git a/src/labs/platform/qtlabsplatformplugin.cpp b/src/labs/platform/qtlabsplatformplugin.cpp
new file mode 100644
index 0000000000..90b166f6e9
--- /dev/null
+++ b/src/labs/platform/qtlabsplatformplugin.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Templates module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/qqml.h>
+#include <QtCore/qloggingcategory.h>
+
+#include "qquicklabsplatformdialog_p.h"
+#include "qquicklabsplatformcolordialog_p.h"
+#include "qquicklabsplatformfiledialog_p.h"
+#include "qquicklabsplatformfolderdialog_p.h"
+#include "qquicklabsplatformfontdialog_p.h"
+#include "qquicklabsplatformmessagedialog_p.h"
+
+#include "qquicklabsplatformmenu_p.h"
+#include "qquicklabsplatformmenubar_p.h"
+#include "qquicklabsplatformmenuitem_p.h"
+#include "qquicklabsplatformmenuitemgroup_p.h"
+#include "qquicklabsplatformmenuseparator_p.h"
+
+#include "qquicklabsplatformstandardpaths_p.h"
+#if QT_CONFIG(systemtrayicon)
+# include "qquicklabsplatformsystemtrayicon_p.h"
+#endif
+
+#include "qquicklabsplatformicon_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qtLabsPlatformDialogs, "qt.labs.platform.dialogs")
+Q_LOGGING_CATEGORY(qtLabsPlatformMenus, "qt.labs.platform.menus")
+Q_LOGGING_CATEGORY(qtLabsPlatformTray, "qt.labs.platform.tray")
+
+class QtLabsPlatformPlugin: public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtLabsPlatformPlugin(QObject *parent = nullptr);
+ void registerTypes(const char *uri) override;
+};
+
+QtLabsPlatformPlugin::QtLabsPlatformPlugin(QObject *parent) : QQmlExtensionPlugin(parent)
+{
+}
+
+void QtLabsPlatformPlugin::registerTypes(const char *uri)
+{
+ qmlRegisterUncreatableType<QQuickLabsPlatformDialog>(uri, 1, 0, "Dialog", QQuickLabsPlatformDialog::tr("Dialog is an abstract base class"));
+ qmlRegisterType<QQuickLabsPlatformColorDialog>(uri, 1, 0, "ColorDialog");
+ qmlRegisterType<QQuickLabsPlatformFileDialog>(uri, 1, 0, "FileDialog");
+ qmlRegisterAnonymousType<QQuickLabsPlatformFileNameFilter>(uri, 1);
+ qmlRegisterType<QQuickLabsPlatformFolderDialog>(uri, 1, 0, "FolderDialog");
+ qmlRegisterType<QQuickLabsPlatformFontDialog>(uri, 1, 0, "FontDialog");
+ qmlRegisterType<QQuickLabsPlatformMessageDialog>(uri, 1, 0, "MessageDialog");
+
+ qmlRegisterType<QQuickLabsPlatformMenu>(uri, 1, 0, "Menu");
+ qmlRegisterType<QQuickLabsPlatformMenuBar>(uri, 1, 0, "MenuBar");
+ qmlRegisterType<QQuickLabsPlatformMenuItem>(uri, 1, 0, "MenuItem");
+ qmlRegisterType<QQuickLabsPlatformMenuItem, 1>(uri, 1, 1, "MenuItem");
+ qmlRegisterType<QQuickLabsPlatformMenuItemGroup>(uri, 1, 0, "MenuItemGroup");
+ qmlRegisterType<QQuickLabsPlatformMenuSeparator>(uri, 1, 0, "MenuSeparator");
+ qRegisterMetaType<QPlatformMenu::MenuType>();
+
+ qmlRegisterUncreatableType<QPlatformDialogHelper>(uri, 1, 0, "StandardButton", QQuickLabsPlatformDialog::tr("Cannot create an instance of StandardButton"));
+ qmlRegisterSingletonType<QQuickLabsPlatformStandardPaths>(uri, 1, 0, "StandardPaths", QQuickLabsPlatformStandardPaths::create);
+ qRegisterMetaType<QStandardPaths::StandardLocation>();
+ qRegisterMetaType<QStandardPaths::LocateOptions>();
+
+#if QT_CONFIG(systemtrayicon)
+ qmlRegisterType<QQuickLabsPlatformSystemTrayIcon>(uri, 1, 0, "SystemTrayIcon");
+ qmlRegisterType<QQuickLabsPlatformSystemTrayIcon, 1>(uri, 1, 1, "SystemTrayIcon");
+ qRegisterMetaType<QPlatformSystemTrayIcon::ActivationReason>();
+ qRegisterMetaType<QPlatformSystemTrayIcon::MessageIcon>();
+#endif
+
+ qmlRegisterAnonymousType<QQuickLabsPlatformIcon>(uri, 1);
+ qRegisterMetaType<QQuickLabsPlatformIcon>();
+}
+
+QT_END_NAMESPACE
+
+#include "qtlabsplatformplugin.moc"
diff --git a/src/labs/platform/widgets/qwidgetplatform_p.h b/src/labs/platform/widgets/qwidgetplatform_p.h
new file mode 100644
index 0000000000..cbdaa24a1e
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatform_p.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORM_P_H
+#define QWIDGETPLATFORM_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/qdebug.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtGui/qpa/qplatformsystemtrayicon.h>
+#include <QtGui/qpa/qplatformmenu.h>
+
+#ifdef QT_WIDGETS_LIB
+#include <QtWidgets/qtwidgetsglobal.h>
+#if QT_CONFIG(colordialog)
+#include "qwidgetplatformcolordialog_p.h"
+#endif
+#if QT_CONFIG(filedialog)
+#include "qwidgetplatformfiledialog_p.h"
+#endif
+#if QT_CONFIG(fontdialog)
+#include "qwidgetplatformfontdialog_p.h"
+#endif
+#if QT_CONFIG(messagebox)
+#include "qwidgetplatformmessagedialog_p.h"
+#endif
+#if QT_CONFIG(menu)
+#include "qwidgetplatformmenu_p.h"
+#include "qwidgetplatformmenuitem_p.h"
+#endif
+#ifndef QT_NO_SYSTEMTRAYICON
+#include "qwidgetplatformsystemtrayicon_p.h"
+#endif
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_WIDGETS_LIB
+typedef QPlatformMenu QWidgetPlatformMenu;
+typedef QPlatformMenuItem QWidgetPlatformMenuItem;
+typedef QPlatformColorDialogHelper QWidgetPlatformColorDialog;
+typedef QPlatformFileDialogHelper QWidgetPlatformFileDialog;
+typedef QPlatformFontDialogHelper QWidgetPlatformFontDialog;
+typedef QPlatformMessageDialogHelper QWidgetPlatformMessageDialog;
+typedef QPlatformSystemTrayIcon QWidgetPlatformSystemTrayIcon;
+#endif
+
+namespace QWidgetPlatform
+{
+ static inline bool isAvailable(const char *type)
+ {
+ if (!qApp->inherits("QApplication")) {
+ qCritical("\nERROR: No native %s implementation available."
+ "\nQt Labs Platform requires Qt Widgets on this setup."
+ "\nAdd 'QT += widgets' to .pro and create QApplication in main().\n", type);
+ return false;
+ }
+ return true;
+ }
+
+ template<typename T>
+ static inline T *createWidget(const char *name, QObject *parent)
+ {
+ static bool available = isAvailable(name);
+#ifdef QT_WIDGETS_LIB
+ if (available)
+ return new T(parent);
+#else
+ Q_UNUSED(parent);
+ Q_UNUSED(available);
+#endif
+ return nullptr;
+ }
+
+ static inline QPlatformMenu *createMenu(QObject *parent = nullptr) {
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(menu)
+ return createWidget<QWidgetPlatformMenu>("Menu", parent);
+#else
+ Q_UNUSED(parent);
+ return nullptr;
+#endif
+ }
+ static inline QPlatformMenuItem *createMenuItem(QObject *parent = nullptr) {
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(menu)
+ return createWidget<QWidgetPlatformMenuItem>("MenuItem", parent);
+#else
+ Q_UNUSED(parent);
+ return nullptr;
+#endif
+ }
+ static inline QPlatformSystemTrayIcon *createSystemTrayIcon(QObject *parent = nullptr) {
+#ifndef QT_NO_SYSTEMTRAYICON
+ return createWidget<QWidgetPlatformSystemTrayIcon>("SystemTrayIcon", parent);
+#else
+ Q_UNUSED(parent);
+ return nullptr;
+#endif
+ }
+ static inline QPlatformDialogHelper *createDialog(QPlatformTheme::DialogType type, QObject *parent = nullptr)
+ {
+#if !defined(QT_WIDGETS_LIB) || !(QT_CONFIG(colordialog) || QT_CONFIG(filedialog) || QT_CONFIG(fontdialog) || QT_CONFIG(messagebox))
+ Q_UNUSED(parent);
+#endif
+ switch (type) {
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(colordialog)
+ case QPlatformTheme::ColorDialog: return createWidget<QWidgetPlatformColorDialog>("ColorDialog", parent);
+#endif
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(filedialog)
+ case QPlatformTheme::FileDialog: return createWidget<QWidgetPlatformFileDialog>("FileDialog", parent);
+#endif
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(fontdialog)
+ case QPlatformTheme::FontDialog: return createWidget<QWidgetPlatformFontDialog>("FontDialog", parent);
+#endif
+#if defined(QT_WIDGETS_LIB) && QT_CONFIG(messagebox)
+ case QPlatformTheme::MessageDialog: return createWidget<QWidgetPlatformMessageDialog>("MessageDialog", parent);
+#endif
+ default: break;
+ }
+ return nullptr;
+ }
+}
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORM_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformcolordialog.cpp b/src/labs/platform/widgets/qwidgetplatformcolordialog.cpp
new file mode 100644
index 0000000000..472f584fae
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformcolordialog.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformcolordialog_p.h"
+#include "qwidgetplatformdialog_p.h"
+
+#include <QtWidgets/qcolordialog.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformColorDialog::QWidgetPlatformColorDialog(QObject *parent)
+ : m_dialog(new QColorDialog)
+{
+ setParent(parent);
+
+ connect(m_dialog.data(), &QColorDialog::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog.data(), &QColorDialog::rejected, this, &QPlatformDialogHelper::reject);
+ connect(m_dialog.data(), &QColorDialog::currentColorChanged, this, &QPlatformColorDialogHelper::currentColorChanged);
+}
+
+QWidgetPlatformColorDialog::~QWidgetPlatformColorDialog()
+{
+}
+
+QColor QWidgetPlatformColorDialog::currentColor() const
+{
+ return m_dialog->currentColor();
+}
+
+void QWidgetPlatformColorDialog::setCurrentColor(const QColor &color)
+{
+ m_dialog->setCurrentColor(color);
+}
+
+void QWidgetPlatformColorDialog::exec()
+{
+ m_dialog->exec();
+}
+
+bool QWidgetPlatformColorDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ QSharedPointer<QColorDialogOptions> options = QPlatformColorDialogHelper::options();
+ m_dialog->setWindowTitle(options->windowTitle());
+ m_dialog->setOptions(static_cast<QColorDialog::ColorDialogOptions>(int(options->options())) | QColorDialog::DontUseNativeDialog);
+
+ return QWidgetPlatformDialog::show(m_dialog.data(), flags, modality, parent);
+}
+
+void QWidgetPlatformColorDialog::hide()
+{
+ m_dialog->hide();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformcolordialog_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformcolordialog_p.h b/src/labs/platform/widgets/qwidgetplatformcolordialog_p.h
new file mode 100644
index 0000000000..09ed5a1e7c
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformcolordialog_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMCOLORDIALOG_P_H
+#define QWIDGETPLATFORMCOLORDIALOG_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/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColorDialog;
+
+class QWidgetPlatformColorDialog : public QPlatformColorDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformColorDialog(QObject *parent = nullptr);
+ ~QWidgetPlatformColorDialog();
+
+ QColor currentColor() const override;
+ void setCurrentColor(const QColor &color) override;
+
+ void exec() override;
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) override;
+ void hide() override;
+
+private:
+ QScopedPointer<QColorDialog> m_dialog;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMCOLORDIALOG_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformdialog.cpp b/src/labs/platform/widgets/qwidgetplatformdialog.cpp
new file mode 100644
index 0000000000..3a206839e2
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformdialog.cpp
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformdialog_p.h"
+
+#include <QtGui/qwindow.h>
+#include <QtWidgets/qdialog.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QWidgetPlatformDialog::show(QDialog *dialog, Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ dialog->setWindowFlags(flags);
+ dialog->setWindowModality(modality);
+
+ dialog->createWinId();
+ QWindow *handle = dialog->windowHandle();
+ Q_ASSERT(handle);
+ handle->setTransientParent(const_cast<QWindow *>(parent));
+
+ dialog->show();
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/labs/platform/widgets/qwidgetplatformdialog_p.h b/src/labs/platform/widgets/qwidgetplatformdialog_p.h
new file mode 100644
index 0000000000..d4f27655ea
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformdialog_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMDIALOG_P_H
+#define QWIDGETPLATFORMDIALOG_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/qnamespace.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDialog;
+class QWindow;
+
+class QWidgetPlatformDialog
+{
+public:
+ static bool show(QDialog *dialog, Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMDIALOG_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformfiledialog.cpp b/src/labs/platform/widgets/qwidgetplatformfiledialog.cpp
new file mode 100644
index 0000000000..5ab27db45f
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformfiledialog.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformfiledialog_p.h"
+#include "qwidgetplatformdialog_p.h"
+
+#include <QtWidgets/qfiledialog.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformFileDialog::QWidgetPlatformFileDialog(QObject *parent)
+ : m_dialog(new QFileDialog)
+{
+ setParent(parent);
+
+ connect(m_dialog.data(), &QDialog::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog.data(), &QDialog::rejected, this, &QPlatformDialogHelper::reject);
+
+ connect(m_dialog.data(), &QFileDialog::fileSelected, [this](const QString &file) {
+ emit fileSelected(QUrl::fromLocalFile(file));
+ });
+ connect(m_dialog.data(), &QFileDialog::filesSelected, [this](const QList<QString> &files) {
+ QList<QUrl> urls;
+ urls.reserve(files.count());
+ for (const QString &file : files)
+ urls += QUrl::fromLocalFile(file);
+ emit filesSelected(urls);
+ });
+ connect(m_dialog.data(), &QFileDialog::currentChanged, [this](const QString &path) {
+ emit currentChanged(QUrl::fromLocalFile(path));
+ });
+ connect(m_dialog.data(), &QFileDialog::directoryEntered, this, &QWidgetPlatformFileDialog::directoryEntered);
+ connect(m_dialog.data(), &QFileDialog::filterSelected, this, &QWidgetPlatformFileDialog::filterSelected);
+}
+
+QWidgetPlatformFileDialog::~QWidgetPlatformFileDialog()
+{
+}
+
+bool QWidgetPlatformFileDialog::defaultNameFilterDisables() const
+{
+ return false; // TODO: ?
+}
+
+void QWidgetPlatformFileDialog::setDirectory(const QUrl &directory)
+{
+ m_dialog->setDirectory(directory.toLocalFile());
+}
+
+QUrl QWidgetPlatformFileDialog::directory() const
+{
+ return m_dialog->directoryUrl();
+}
+
+void QWidgetPlatformFileDialog::selectFile(const QUrl &filename)
+{
+ m_dialog->selectUrl(filename);
+}
+
+QList<QUrl> QWidgetPlatformFileDialog::selectedFiles() const
+{
+ return m_dialog->selectedUrls();
+}
+
+void QWidgetPlatformFileDialog::setFilter()
+{
+ // TODO: ?
+}
+
+void QWidgetPlatformFileDialog::selectNameFilter(const QString &filter)
+{
+ m_dialog->selectNameFilter(filter);
+}
+
+QString QWidgetPlatformFileDialog::selectedNameFilter() const
+{
+ return m_dialog->selectedNameFilter();
+}
+
+void QWidgetPlatformFileDialog::exec()
+{
+ m_dialog->exec();
+}
+
+bool QWidgetPlatformFileDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ QSharedPointer<QFileDialogOptions> options = QPlatformFileDialogHelper::options();
+ m_dialog->setWindowTitle(options->windowTitle());
+ m_dialog->setAcceptMode(static_cast<QFileDialog::AcceptMode>(options->acceptMode()));
+ m_dialog->setFileMode(static_cast<QFileDialog::FileMode>(options->fileMode()));
+ m_dialog->setOptions(static_cast<QFileDialog::Options>(int(options->options())) | QFileDialog::DontUseNativeDialog);
+ m_dialog->setNameFilters(options->nameFilters());
+ m_dialog->setDefaultSuffix(options->defaultSuffix());
+ if (options->isLabelExplicitlySet(QFileDialogOptions::Accept))
+ m_dialog->setLabelText(QFileDialog::Accept, options->labelText(QFileDialogOptions::Accept));
+ if (options->isLabelExplicitlySet(QFileDialogOptions::Reject))
+ m_dialog->setLabelText(QFileDialog::Reject, options->labelText(QFileDialogOptions::Reject));
+
+ return QWidgetPlatformDialog::show(m_dialog.data(), flags, modality, parent);
+}
+
+void QWidgetPlatformFileDialog::hide()
+{
+ m_dialog->hide();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformfiledialog_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformfiledialog_p.h b/src/labs/platform/widgets/qwidgetplatformfiledialog_p.h
new file mode 100644
index 0000000000..3dba603845
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformfiledialog_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMFILEDIALOG_P_H
+#define QWIDGETPLATFORMFILEDIALOG_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/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFileDialog;
+
+class QWidgetPlatformFileDialog : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformFileDialog(QObject *parent = nullptr);
+ ~QWidgetPlatformFileDialog();
+
+ bool defaultNameFilterDisables() const override;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &filename) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override;
+ void selectNameFilter(const QString &filter) override;
+ QString selectedNameFilter() const override;
+
+ void exec() override;
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) override;
+ void hide() override;
+
+private:
+ QScopedPointer<QFileDialog> m_dialog;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMFILEDIALOG_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformfontdialog.cpp b/src/labs/platform/widgets/qwidgetplatformfontdialog.cpp
new file mode 100644
index 0000000000..ba24e7433e
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformfontdialog.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformfontdialog_p.h"
+#include "qwidgetplatformdialog_p.h"
+
+#include <QtWidgets/qfontdialog.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformFontDialog::QWidgetPlatformFontDialog(QObject *parent)
+ : m_dialog(new QFontDialog)
+{
+ setParent(parent);
+
+ connect(m_dialog.data(), &QFontDialog::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog.data(), &QFontDialog::rejected, this, &QPlatformDialogHelper::reject);
+ connect(m_dialog.data(), &QFontDialog::currentFontChanged, this, &QPlatformFontDialogHelper::currentFontChanged);
+}
+
+QWidgetPlatformFontDialog::~QWidgetPlatformFontDialog()
+{
+}
+
+QFont QWidgetPlatformFontDialog::currentFont() const
+{
+ return m_dialog->currentFont();
+}
+
+void QWidgetPlatformFontDialog::setCurrentFont(const QFont &font)
+{
+ m_dialog->setCurrentFont(font);
+}
+
+void QWidgetPlatformFontDialog::exec()
+{
+ m_dialog->exec();
+}
+
+bool QWidgetPlatformFontDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ QSharedPointer<QFontDialogOptions> options = QPlatformFontDialogHelper::options();
+ m_dialog->setWindowTitle(options->windowTitle());
+ m_dialog->setOptions(static_cast<QFontDialog::FontDialogOptions>(int(options->options())) | QFontDialog::DontUseNativeDialog);
+
+ return QWidgetPlatformDialog::show(m_dialog.data(), flags, modality, parent);
+}
+
+void QWidgetPlatformFontDialog::hide()
+{
+ m_dialog->hide();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformfontdialog_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformfontdialog_p.h b/src/labs/platform/widgets/qwidgetplatformfontdialog_p.h
new file mode 100644
index 0000000000..e5d13b31e6
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformfontdialog_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMFONTDIALOG_P_H
+#define QWIDGETPLATFORMFONTDIALOG_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/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QFontDialog;
+
+class QWidgetPlatformFontDialog : public QPlatformFontDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformFontDialog(QObject *parent = nullptr);
+ ~QWidgetPlatformFontDialog();
+
+ QFont currentFont() const override;
+ void setCurrentFont(const QFont &font) override;
+
+ void exec() override;
+ bool show(Qt::WindowFlags windowFlags, Qt::WindowModality windowModality, QWindow *parent) override;
+ void hide() override;
+
+private:
+ QScopedPointer<QFontDialog> m_dialog;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMFONTDIALOG_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformmenu.cpp b/src/labs/platform/widgets/qwidgetplatformmenu.cpp
new file mode 100644
index 0000000000..5cb36eacdb
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmenu.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformmenu_p.h"
+#include "qwidgetplatformmenuitem_p.h"
+
+#include <QtGui/qaction.h>
+#include <QtGui/qwindow.h>
+#include <QtWidgets/qmenu.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformMenu::QWidgetPlatformMenu(QObject *parent)
+ : m_menu(new QMenu)
+{
+ setParent(parent);
+
+ connect(m_menu.data(), &QMenu::aboutToShow, this, &QPlatformMenu::aboutToShow);
+ connect(m_menu.data(), &QMenu::aboutToHide, this, &QPlatformMenu::aboutToHide);
+}
+
+QWidgetPlatformMenu::~QWidgetPlatformMenu()
+{
+}
+
+QMenu *QWidgetPlatformMenu::menu() const
+{
+ return m_menu.data();
+}
+
+void QWidgetPlatformMenu::insertMenuItem(QPlatformMenuItem *item, QPlatformMenuItem *before)
+{
+ QWidgetPlatformMenuItem *widgetItem = qobject_cast<QWidgetPlatformMenuItem *>(item);
+ if (!widgetItem)
+ return;
+
+ QWidgetPlatformMenuItem *widgetBefore = qobject_cast<QWidgetPlatformMenuItem *>(before);
+ m_menu->insertAction(widgetBefore ? widgetBefore->action() : nullptr, widgetItem->action());
+ int index = m_items.indexOf(widgetBefore);
+ if (index < 0)
+ index = m_items.count();
+ m_items.insert(index, widgetItem);
+}
+
+void QWidgetPlatformMenu::removeMenuItem(QPlatformMenuItem *item)
+{
+ QWidgetPlatformMenuItem *widgetItem = qobject_cast<QWidgetPlatformMenuItem *>(item);
+ if (!widgetItem)
+ return;
+
+ m_items.removeOne(widgetItem);
+ m_menu->removeAction(widgetItem->action());
+}
+
+void QWidgetPlatformMenu::syncMenuItem(QPlatformMenuItem *item)
+{
+ Q_UNUSED(item);
+}
+
+void QWidgetPlatformMenu::syncSeparatorsCollapsible(bool enable)
+{
+ m_menu->setSeparatorsCollapsible(enable);
+}
+
+void QWidgetPlatformMenu::setText(const QString &text)
+{
+ m_menu->setTitle(text);
+}
+
+void QWidgetPlatformMenu::setIcon(const QIcon &icon)
+{
+ m_menu->setIcon(icon);
+}
+
+void QWidgetPlatformMenu::setEnabled(bool enabled)
+{
+ m_menu->menuAction()->setEnabled(enabled);
+}
+
+bool QWidgetPlatformMenu::isEnabled() const
+{
+ return m_menu->menuAction()->isEnabled();
+}
+
+void QWidgetPlatformMenu::setVisible(bool visible)
+{
+ m_menu->menuAction()->setVisible(visible);
+}
+
+void QWidgetPlatformMenu::setMinimumWidth(int width)
+{
+ if (width > 0)
+ m_menu->setMinimumWidth(width);
+}
+
+void QWidgetPlatformMenu::setFont(const QFont &font)
+{
+ m_menu->setFont(font);
+}
+
+void QWidgetPlatformMenu::setMenuType(MenuType type)
+{
+ Q_UNUSED(type);
+}
+
+void QWidgetPlatformMenu::showPopup(const QWindow *window, const QRect &targetRect, const QPlatformMenuItem *item)
+{
+ m_menu->createWinId();
+ QWindow *handle = m_menu->windowHandle();
+ Q_ASSERT(handle);
+ handle->setTransientParent(const_cast<QWindow *>(window));
+
+ QPoint targetPos = targetRect.bottomLeft();
+ if (window)
+ targetPos = window->mapToGlobal(targetPos);
+
+ const QWidgetPlatformMenuItem *widgetItem = qobject_cast<const QWidgetPlatformMenuItem *>(item);
+ m_menu->popup(targetPos, widgetItem ? widgetItem->action() : nullptr);
+}
+
+void QWidgetPlatformMenu::dismiss()
+{
+ m_menu->close();
+}
+
+QPlatformMenuItem *QWidgetPlatformMenu::menuItemAt(int position) const
+{
+ return m_items.value(position);
+}
+
+QPlatformMenuItem *QWidgetPlatformMenu::menuItemForTag(quintptr tag) const
+{
+ for (QWidgetPlatformMenuItem *item : m_items) {
+ if (item->tag() == tag)
+ return item;
+ }
+ return nullptr;
+}
+
+QPlatformMenuItem *QWidgetPlatformMenu::createMenuItem() const
+{
+ return new QWidgetPlatformMenuItem;
+}
+
+QPlatformMenu *QWidgetPlatformMenu::createSubMenu() const
+{
+ return new QWidgetPlatformMenu;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformmenu_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformmenu_p.h b/src/labs/platform/widgets/qwidgetplatformmenu_p.h
new file mode 100644
index 0000000000..9d1ef57e2f
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmenu_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMMENU_P_H
+#define QWIDGETPLATFORMMENU_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/qpa/qplatformmenu.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMenu;
+class QWidgetPlatformMenuItem;
+
+class QWidgetPlatformMenu : public QPlatformMenu
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformMenu(QObject *parent = nullptr);
+ ~QWidgetPlatformMenu();
+
+ QMenu *menu() const;
+
+ void insertMenuItem(QPlatformMenuItem *item, QPlatformMenuItem *before) override;
+ void removeMenuItem(QPlatformMenuItem *item) override;
+ void syncMenuItem(QPlatformMenuItem *item) override;
+ void syncSeparatorsCollapsible(bool enable) override;
+
+ void setText(const QString &text) override;
+ void setIcon(const QIcon &icon) override;
+ void setEnabled(bool enabled) override;
+ bool isEnabled() const override;
+ void setVisible(bool visible) override;
+ void setMinimumWidth(int width) override;
+ void setFont(const QFont &font) override;
+ void setMenuType(MenuType type) override;
+
+ void showPopup(const QWindow *window, const QRect &targetRect, const QPlatformMenuItem *item) override;
+ void dismiss() override;
+
+ QPlatformMenuItem *menuItemAt(int position) const override;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
+
+ QPlatformMenuItem *createMenuItem() const override;
+ QPlatformMenu *createSubMenu() const override;
+
+private:
+ QScopedPointer<QMenu> m_menu;
+ QList<QWidgetPlatformMenuItem *> m_items;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMMENU_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformmenuitem.cpp b/src/labs/platform/widgets/qwidgetplatformmenuitem.cpp
new file mode 100644
index 0000000000..3539c17961
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmenuitem.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformmenuitem_p.h"
+#include "qwidgetplatformmenu_p.h"
+
+#include <QtGui/qaction.h>
+#include <QtWidgets/qmenu.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformMenuItem::QWidgetPlatformMenuItem(QObject *parent)
+ : m_action(new QAction)
+{
+ setParent(parent);
+ connect(m_action.data(), &QAction::hovered, this, &QPlatformMenuItem::hovered);
+ connect(m_action.data(), &QAction::triggered, this, &QPlatformMenuItem::activated);
+}
+
+QWidgetPlatformMenuItem::~QWidgetPlatformMenuItem()
+{
+}
+
+QAction *QWidgetPlatformMenuItem::action() const
+{
+ return m_action.data();
+}
+
+void QWidgetPlatformMenuItem::setText(const QString &text)
+{
+ m_action->setText(text);
+}
+
+void QWidgetPlatformMenuItem::setIcon(const QIcon &icon)
+{
+ m_action->setIcon(icon);
+}
+
+void QWidgetPlatformMenuItem::setMenu(QPlatformMenu *menu)
+{
+ QWidgetPlatformMenu *widgetMenu = qobject_cast<QWidgetPlatformMenu *>(menu);
+ m_action->setMenu(widgetMenu ? widgetMenu->menu() : nullptr);
+}
+
+void QWidgetPlatformMenuItem::setVisible(bool visible)
+{
+ m_action->setVisible(visible);
+}
+
+void QWidgetPlatformMenuItem::setIsSeparator(bool separator)
+{
+ m_action->setSeparator(separator);
+}
+
+void QWidgetPlatformMenuItem::setFont(const QFont &font)
+{
+ m_action->setFont(font);
+}
+
+void QWidgetPlatformMenuItem::setRole(MenuRole role)
+{
+ m_action->setMenuRole(static_cast<QAction::MenuRole>(role));
+}
+
+void QWidgetPlatformMenuItem::setCheckable(bool checkable)
+{
+ m_action->setCheckable(checkable);
+}
+
+void QWidgetPlatformMenuItem::setChecked(bool checked)
+{
+ m_action->setChecked(checked);
+}
+
+#if QT_CONFIG(shortcut)
+void QWidgetPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
+{
+ m_action->setShortcut(shortcut);
+}
+#endif
+
+void QWidgetPlatformMenuItem::setEnabled(bool enabled)
+{
+ m_action->setEnabled(enabled);
+}
+
+void QWidgetPlatformMenuItem::setIconSize(int size)
+{
+ Q_UNUSED(size);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformmenuitem_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformmenuitem_p.h b/src/labs/platform/widgets/qwidgetplatformmenuitem_p.h
new file mode 100644
index 0000000000..43b3fc174e
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmenuitem_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMMENUITEM_P_H
+#define QWIDGETPLATFORMMENUITEM_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/qpa/qplatformmenu.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAction;
+
+class QWidgetPlatformMenuItem : public QPlatformMenuItem
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformMenuItem(QObject *parent = nullptr);
+ ~QWidgetPlatformMenuItem();
+
+ QAction *action() const;
+
+ void setText(const QString &text) override;
+ void setIcon(const QIcon &icon) override;
+ void setMenu(QPlatformMenu *menu) override;
+ void setVisible(bool visible) override;
+ void setIsSeparator(bool separator) override;
+ void setFont(const QFont &font) override;
+ void setRole(MenuRole role) override;
+ void setCheckable(bool checkable) override;
+ void setChecked(bool checked) override;
+#if QT_CONFIG(shortcut)
+ void setShortcut(const QKeySequence& shortcut) override;
+#endif
+ void setEnabled(bool enabled) override;
+ void setIconSize(int size) override;
+
+private:
+ QScopedPointer<QAction> m_action;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMMENUITEM_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformmessagedialog.cpp b/src/labs/platform/widgets/qwidgetplatformmessagedialog.cpp
new file mode 100644
index 0000000000..f3d850eefb
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmessagedialog.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformmessagedialog_p.h"
+#include "qwidgetplatformdialog_p.h"
+
+#include <QtWidgets/qmessagebox.h>
+#include <QtWidgets/qabstractbutton.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformMessageDialog::QWidgetPlatformMessageDialog(QObject *parent)
+ : m_dialog(new QMessageBox)
+{
+ setParent(parent);
+
+ connect(m_dialog.data(), &QMessageBox::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog.data(), &QMessageBox::rejected, this, &QPlatformDialogHelper::reject);
+ connect(m_dialog.data(), &QMessageBox::buttonClicked, [this](QAbstractButton *button) {
+ QMessageBox::ButtonRole role = m_dialog->buttonRole(button);
+ QMessageBox::StandardButton standardButton = m_dialog->standardButton(button);
+ emit clicked(static_cast<StandardButton>(standardButton), static_cast<ButtonRole>(role));
+ });
+}
+
+QWidgetPlatformMessageDialog::~QWidgetPlatformMessageDialog()
+{
+}
+void QWidgetPlatformMessageDialog::exec()
+{
+ m_dialog->exec();
+}
+
+bool QWidgetPlatformMessageDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ QSharedPointer<QMessageDialogOptions> options = QPlatformMessageDialogHelper::options();
+ m_dialog->setWindowTitle(options->windowTitle());
+ m_dialog->setIcon(static_cast<QMessageBox::Icon>(options->icon()));
+ m_dialog->setText(options->text());
+ m_dialog->setInformativeText(options->informativeText());
+#if QT_CONFIG(textedit)
+ m_dialog->setDetailedText(options->detailedText());
+#endif
+ m_dialog->setStandardButtons(static_cast<QMessageBox::StandardButtons>(int(options->standardButtons())));
+
+ return QWidgetPlatformDialog::show(m_dialog.data(), flags, modality, parent);
+}
+
+void QWidgetPlatformMessageDialog::hide()
+{
+ m_dialog->hide();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformmessagedialog_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformmessagedialog_p.h b/src/labs/platform/widgets/qwidgetplatformmessagedialog_p.h
new file mode 100644
index 0000000000..6581337ab3
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformmessagedialog_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMMESSAGEDIALOG_P_H
+#define QWIDGETPLATFORMMESSAGEDIALOG_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/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QMessageBox;
+
+class QWidgetPlatformMessageDialog : public QPlatformMessageDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformMessageDialog(QObject *parent = nullptr);
+ ~QWidgetPlatformMessageDialog();
+
+ void exec() override;
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) override;
+ void hide() override;
+
+private:
+ QScopedPointer<QMessageBox> m_dialog;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMMESSAGEDIALOG_P_H
diff --git a/src/labs/platform/widgets/qwidgetplatformsystemtrayicon.cpp b/src/labs/platform/widgets/qwidgetplatformsystemtrayicon.cpp
new file mode 100644
index 0000000000..76d814256e
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformsystemtrayicon.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwidgetplatformsystemtrayicon_p.h"
+#include "qwidgetplatformmenu_p.h"
+
+#include <QtWidgets/qsystemtrayicon.h>
+
+QT_BEGIN_NAMESPACE
+
+QWidgetPlatformSystemTrayIcon::QWidgetPlatformSystemTrayIcon(QObject *parent)
+ : m_systray(new QSystemTrayIcon)
+{
+ setParent(parent);
+
+ connect(m_systray.data(), &QSystemTrayIcon::messageClicked, this, &QPlatformSystemTrayIcon::messageClicked);
+ connect(m_systray.data(), &QSystemTrayIcon::activated, [this](QSystemTrayIcon::ActivationReason reason) {
+ emit activated(static_cast<ActivationReason>(reason));
+ });
+}
+
+QWidgetPlatformSystemTrayIcon::~QWidgetPlatformSystemTrayIcon()
+{
+}
+
+void QWidgetPlatformSystemTrayIcon::init()
+{
+ m_systray->show();
+}
+
+void QWidgetPlatformSystemTrayIcon::cleanup()
+{
+ m_systray->hide();
+}
+
+void QWidgetPlatformSystemTrayIcon::updateIcon(const QIcon &icon)
+{
+ m_systray->setIcon(icon);
+}
+
+void QWidgetPlatformSystemTrayIcon::updateToolTip(const QString &tooltip)
+{
+ m_systray->setToolTip(tooltip);
+}
+
+void QWidgetPlatformSystemTrayIcon::updateMenu(QPlatformMenu *menu)
+{
+#if QT_CONFIG(menu)
+ QWidgetPlatformMenu *widgetMenu = qobject_cast<QWidgetPlatformMenu *>(menu);
+ if (!widgetMenu)
+ return;
+
+ m_systray->setContextMenu(widgetMenu->menu());
+#else
+ Q_UNUSED(menu);
+#endif
+}
+
+QRect QWidgetPlatformSystemTrayIcon::geometry() const
+{
+ return m_systray->geometry();
+}
+
+void QWidgetPlatformSystemTrayIcon::showMessage(const QString &title, const QString &msg, const QIcon &icon, MessageIcon iconType, int msecs)
+{
+ Q_UNUSED(icon);
+ m_systray->showMessage(title, msg, static_cast<QSystemTrayIcon::MessageIcon>(iconType), msecs);
+}
+
+bool QWidgetPlatformSystemTrayIcon::isSystemTrayAvailable() const
+{
+ return QSystemTrayIcon::isSystemTrayAvailable();
+}
+
+bool QWidgetPlatformSystemTrayIcon::supportsMessages() const
+{
+ return QSystemTrayIcon::supportsMessages();
+}
+
+QPlatformMenu *QWidgetPlatformSystemTrayIcon::createMenu() const
+{
+ return new QWidgetPlatformMenu;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwidgetplatformsystemtrayicon_p.cpp"
diff --git a/src/labs/platform/widgets/qwidgetplatformsystemtrayicon_p.h b/src/labs/platform/widgets/qwidgetplatformsystemtrayicon_p.h
new file mode 100644
index 0000000000..11ea5377b3
--- /dev/null
+++ b/src/labs/platform/widgets/qwidgetplatformsystemtrayicon_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Labs Platform module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWIDGETPLATFORMSYSTEMTRAYICON_P_H
+#define QWIDGETPLATFORMSYSTEMTRAYICON_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/qpa/qplatformsystemtrayicon.h>
+
+QT_REQUIRE_CONFIG(systemtrayicon);
+
+QT_BEGIN_NAMESPACE
+
+class QSystemTrayIcon;
+
+class QWidgetPlatformSystemTrayIcon : public QPlatformSystemTrayIcon
+{
+ Q_OBJECT
+
+public:
+ explicit QWidgetPlatformSystemTrayIcon(QObject *parent = nullptr);
+ ~QWidgetPlatformSystemTrayIcon();
+
+ void init() override;
+ void cleanup() override;
+ void updateIcon(const QIcon &icon) override;
+ void updateToolTip(const QString &tooltip) override;
+ void updateMenu(QPlatformMenu *menu) override;
+ QRect geometry() const override;
+ void showMessage(const QString &title, const QString &msg,
+ const QIcon &icon, MessageIcon iconType, int msecs) override;
+
+ bool isSystemTrayAvailable() const override;
+ bool supportsMessages() const override;
+
+ QPlatformMenu *createMenu() const override;
+
+private:
+ QScopedPointer<QSystemTrayIcon> m_systray;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWIDGETPLATFORMSYSTEMTRAYICON_P_H
diff --git a/src/labs/platform/widgets/widgets.pri b/src/labs/platform/widgets/widgets.pri
new file mode 100644
index 0000000000..54ad7187cc
--- /dev/null
+++ b/src/labs/platform/widgets/widgets.pri
@@ -0,0 +1,56 @@
+QT += widgets
+DEPENDPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qwidgetplatform_p.h
+
+qtConfig(systemtrayicon) {
+ HEADERS += \
+ $$PWD/qwidgetplatformsystemtrayicon_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformsystemtrayicon.cpp
+}
+
+qtConfig(colordialog) | qtConfig(filedialog) | qtConfig(fontdialog) | qtConfig(messagebox) {
+ HEADERS += \
+ $$PWD/qwidgetplatformdialog_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformdialog.cpp
+}
+
+qtConfig(colordialog) {
+ HEADERS += \
+ $$PWD/qwidgetplatformcolordialog_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformcolordialog.cpp
+}
+
+qtConfig(filedialog) {
+ HEADERS += \
+ $$PWD/qwidgetplatformfiledialog_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformfiledialog.cpp
+}
+
+qtConfig(fontdialog) {
+ HEADERS += \
+ $$PWD/qwidgetplatformfontdialog_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformfontdialog.cpp
+}
+
+qtConfig(menu) {
+ HEADERS += \
+ $$PWD/qwidgetplatformmenu_p.h \
+ $$PWD/qwidgetplatformmenuitem_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformmenu.cpp \
+ $$PWD/qwidgetplatformmenuitem.cpp
+}
+
+qtConfig(messagebox) {
+ HEADERS += \
+ $$PWD/qwidgetplatformmessagedialog_p.h
+ SOURCES += \
+ $$PWD/qwidgetplatformmessagedialog.cpp
+}
diff --git a/src/labs/sharedimage/doc/src/qsharedimage.qdoc b/src/labs/sharedimage/doc/src/qsharedimage.qdoc
index 119f49bf91..bb3cafebfe 100644
--- a/src/labs/sharedimage/doc/src/qsharedimage.qdoc
+++ b/src/labs/sharedimage/doc/src/qsharedimage.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule Qt.labs.sharedimage 1
+ \qmlmodule Qt.labs.sharedimage
\title Qt Quick Shared Image Provider
\ingroup qmlmodules
\brief Adds an image provider which utilizes shared CPU memory
diff --git a/src/labs/sharedimage/qsharedimageloader.cpp b/src/labs/sharedimage/qsharedimageloader.cpp
index c9e3ef3eb3..c37c4b890e 100644
--- a/src/labs/sharedimage/qsharedimageloader.cpp
+++ b/src/labs/sharedimage/qsharedimageloader.cpp
@@ -264,3 +264,5 @@ QString QSharedImageLoader::key(const QString &path, ImageParameters *params)
QT_END_NAMESPACE
+
+#include "moc_qsharedimageloader_p.cpp"
diff --git a/src/labs/sharedimage/qsharedimageprovider.cpp b/src/labs/sharedimage/qsharedimageprovider.cpp
index 74822a4e87..402bebfd71 100644
--- a/src/labs/sharedimage/qsharedimageprovider.cpp
+++ b/src/labs/sharedimage/qsharedimageprovider.cpp
@@ -46,6 +46,7 @@
Q_DECLARE_METATYPE(QQuickImageProviderOptions)
+QT_BEGIN_NAMESPACE
QuickSharedImageLoader::QuickSharedImageLoader(QObject *parent) : QSharedImageLoader(parent) {}
@@ -137,3 +138,7 @@ QImage SharedImageProvider::requestImage(const QString &id, QSize *size, const Q
return img;
}
+
+QT_END_NAMESPACE
+
+#include "moc_qsharedimageprovider_p.cpp"
diff --git a/src/labs/sharedimage/qsharedimageprovider_p.h b/src/labs/sharedimage/qsharedimageprovider_p.h
index f8bea9e784..d590372bf4 100644
--- a/src/labs/sharedimage/qsharedimageprovider_p.h
+++ b/src/labs/sharedimage/qsharedimageprovider_p.h
@@ -59,6 +59,8 @@
#include "qsharedimageloader_p.h"
+QT_BEGIN_NAMESPACE
+
class SharedImageProvider;
class QuickSharedImageLoader : public QSharedImageLoader
@@ -90,4 +92,7 @@ public:
protected:
QScopedPointer<QuickSharedImageLoader> loader;
};
+
+QT_END_NAMESPACE
+
#endif // QSHAREDIMAGEPROVIDER_H
diff --git a/src/labs/wavefrontmesh/CMakeLists.txt b/src/labs/wavefrontmesh/CMakeLists.txt
index 7a6c7a5cc0..2063f6fb4d 100644
--- a/src/labs/wavefrontmesh/CMakeLists.txt
+++ b/src/labs/wavefrontmesh/CMakeLists.txt
@@ -3,6 +3,8 @@ qt_internal_add_qml_module(LabsWavefrontMesh
VERSION "${PROJECT_VERSION}"
PLUGIN_TARGET qmlwavefrontmeshplugin
CLASS_NAME QmlWavefrontMeshPlugin
+ DEPENDENCIES
+ QtQuick
SOURCES
qwavefrontmesh.cpp qwavefrontmesh_p.h
qqmlwavefrontmeshglobal_p.h
diff --git a/src/labs/wavefrontmesh/qwavefrontmesh.cpp b/src/labs/wavefrontmesh/qwavefrontmesh.cpp
index 472b663509..5f5f6c4bfa 100644
--- a/src/labs/wavefrontmesh/qwavefrontmesh.cpp
+++ b/src/labs/wavefrontmesh/qwavefrontmesh.cpp
@@ -695,3 +695,5 @@ QVector3D QWavefrontMesh::projectionPlaneW() const
QT_END_NAMESPACE
+
+#include "moc_qwavefrontmesh_p.cpp"
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp
index 884edc3390..750c0446c8 100644
--- a/src/particles/qquickimageparticle.cpp
+++ b/src/particles/qquickimageparticle.cpp
@@ -766,6 +766,7 @@ void QQuickImageParticle::sceneGraphInvalidated()
m_material = nullptr;
delete m_outgoingNode;
m_outgoingNode = nullptr;
+ m_apiChecked = false;
}
void QQuickImageParticle::setImage(const QUrl &image)
@@ -1074,6 +1075,12 @@ void QQuickImageParticle::reset()
update();
}
+
+void QQuickImageParticle::invalidateSceneGraph()
+{
+ reset();
+}
+
void QQuickImageParticle::createEngine()
{
if (m_spriteEngine)
diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h
index 19000f6c9b..03a96b7901 100644
--- a/src/particles/qquickimageparticle_p.h
+++ b/src/particles/qquickimageparticle_p.h
@@ -395,6 +395,8 @@ private Q_SLOTS:
void spritesUpdate(qreal time = 0 );
void mainThreadFetchImageData();
void finishBuildParticleNodes(QSGNode **n);
+ void invalidateSceneGraph();
+
private:
struct ImageData {
QUrl source;
diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
index 3e75e39f86..c89fb86aec 100644
--- a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
+++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp
@@ -324,3 +324,5 @@ bool QPacketProtocolPrivate::readFromDevice(char *buffer, qint64 size)
*/
QT_END_NAMESPACE
+
+#include "moc_qpacketprotocol_p.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_debugger/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_debugger/CMakeLists.txt
index bfe9f06d98..67e408e8aa 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_debugger/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlDebuggerServiceFactoryPlugin
OUTPUT_NAME qmldbg_debugger
CLASS_NAME QQmlDebuggerServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qqmldebuggerservicefactory.cpp qqmldebuggerservicefactory.h
qqmlenginedebugservice.cpp qqmlenginedebugservice.h
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
index 3851cdc71f..c28bf0aaff 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp
@@ -56,3 +56,5 @@ QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebuggerservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
index 3afda162e6..89baceeb36 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp
@@ -808,9 +808,9 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
int lineNumber = 0;
QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex()));
- if (oldMethod && oldMethod->d()->function) {
- lineNumber = oldMethod->d()->function->compiledFunction->location.line;
- }
+ if (oldMethod && oldMethod->d()->function)
+ lineNumber = oldMethod->d()->function->compiledFunction->location.line();
+
QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber));
vmeMetaObject->setVmeMethod(prop->coreIndex(), v);
return true;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index e0c24979a9..381f09742a 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -211,8 +211,8 @@ void ValueLookupJob::run()
QScopedPointer<QObject> scopeObject;
QV4::ExecutionEngine *engine = collector->engine();
QV4::Scope scope(engine);
- QV4::Heap::ExecutionContext *qmlContext = nullptr;
- if (engine->qmlEngine() && !engine->qmlContext()) {
+ QV4::Heap::ExecutionContext *qmlContext = engine->qmlContext();
+ if (engine->qmlEngine() && !qmlContext) {
scopeObject.reset(new QObject);
qmlContext = QV4::QmlContext::create(engine->currentContext(),
QQmlContextData::get(engine->qmlEngine()->rootContext()),
diff --git a/src/plugins/qmltooling/qmldbg_inspector/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_inspector/CMakeLists.txt
index 968435f27b..40eee66b2e 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_inspector/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlInspectorServiceFactoryPlugin
OUTPUT_NAME qmldbg_inspector
CLASS_NAME QQmlInspectorServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
globalinspector.cpp globalinspector.h
highlight.cpp highlight.h
diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
index 301db59952..741cbe8f5a 100644
--- a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
+++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp
@@ -407,4 +407,6 @@ GlobalInspector::~GlobalInspector()
QT_END_NAMESPACE
+#include "moc_globalinspector.cpp"
+
#include <globalinspector.moc>
diff --git a/src/plugins/qmltooling/qmldbg_local/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_local/CMakeLists.txt
index 485f00df3b..82fb91d423 100644
--- a/src/plugins/qmltooling/qmldbg_local/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_local/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QLocalClientConnectionFactoryPlugin
OUTPUT_NAME qmldbg_local
CLASS_NAME QLocalClientConnectionFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qlocalclientconnection.cpp
qlocalclientconnectionfactory.h
diff --git a/src/plugins/qmltooling/qmldbg_messages/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_messages/CMakeLists.txt
index 428ea21ccd..9587709f1d 100644
--- a/src/plugins/qmltooling/qmldbg_messages/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_messages/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QDebugMessageServiceFactoryPlugin
OUTPUT_NAME qmldbg_messages
CLASS_NAME QDebugMessageServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qdebugmessageservice.cpp qdebugmessageservice.h
qdebugmessageservicefactory.cpp qdebugmessageservicefactory.h
diff --git a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
index 4f6cb9364d..2de805d40d 100644
--- a/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_messages/qdebugmessageservice.cpp
@@ -106,3 +106,5 @@ void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer)
}
QT_END_NAMESPACE
+
+#include "moc_qdebugmessageservice.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_native/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_native/CMakeLists.txt
index 1bb2ed9e39..1e300ba807 100644
--- a/src/plugins/qmltooling/qmldbg_native/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_native/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlNativeDebugConnectorFactoryPlugin
OUTPUT_NAME qmldbg_native
CLASS_NAME QQmlNativeDebugConnectorFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qqmlnativedebugconnector.cpp qqmlnativedebugconnector.h
LIBRARIES
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_nativedebugger/CMakeLists.txt
index 25d54236fd..ccfcd7e183 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlNativeDebugServiceFactoryPlugin
OUTPUT_NAME qmldbg_nativedebugger
CLASS_NAME QQmlNativeDebugServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qqmlnativedebugservice.cpp qqmlnativedebugservice.h
qqmlnativedebugservicefactory.cpp qqmlnativedebugservicefactory.h
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
index c0b74c74ff..f3990f7e57 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservicefactory.cpp
@@ -52,3 +52,5 @@ QQmlDebugService *QQmlNativeDebugServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlnativedebugservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
index f12d622716..7ebbf09dde 100644
--- a/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_preview/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlPreviewServiceFactoryPlugin
OUTPUT_NAME qmldbg_preview
CLASS_NAME QQmlPreviewServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qqmlpreviewblacklist.cpp qqmlpreviewblacklist.h
qqmlpreviewfileengine.cpp qqmlpreviewfileengine.h
@@ -34,6 +34,6 @@ qt_internal_extend_target(QQmlPreviewServiceFactoryPlugin CONDITION QT_FEATURE_t
SOURCES
proxytranslator.cpp proxytranslator.h
qqmldebugtranslationservice.cpp qqmldebugtranslationservice.h
- PUBLIC_LIBRARIES
+ LIBRARIES
Qt::Gui
)
diff --git a/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp
index 7f5227296a..ddf2df12ff 100644
--- a/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/proxytranslator.cpp
@@ -75,9 +75,10 @@ QString ProxyTranslator::originStringFromInformation(const TranslationBindingInf
QQmlSourceLocation ProxyTranslator::sourceLocationFromInformation(const TranslationBindingInformation &translationBindingInformation)
{
- return QQmlSourceLocation(translationBindingInformation.compilationUnit->fileName(),
- translationBindingInformation.compiledBinding->valueLocation.line,
- translationBindingInformation.compiledBinding->valueLocation.column);
+ return QQmlSourceLocation(
+ translationBindingInformation.compilationUnit->fileName(),
+ translationBindingInformation.compiledBinding->valueLocation.line(),
+ translationBindingInformation.compiledBinding->valueLocation.column());
}
@@ -125,7 +126,7 @@ QString ProxyTranslator::translate(const char *context, const char *sourceText,
result = m_qtTranslator->translate(context, sourceText, disambiguation, n);
if (result.isNull() && m_qmlTranslator)
result = m_qmlTranslator->translate(context, sourceText, disambiguation, n);
- m_translationFound = !result.isNull();
+ m_translationFound = !(result.isNull() || result.isEmpty() || result == sourceText);
return result;
}
@@ -154,3 +155,5 @@ QString ProxyTranslator::currentUILanguages() const
}
QT_END_NAMESPACE
+
+#include "moc_proxytranslator.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
index 4f9d76432f..d21f54dd2c 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.cpp
@@ -39,6 +39,7 @@
#include "qqmldebugtranslationservice.h"
#include "proxytranslator.h"
+#include "qqmlpreviewservice.h"
#include <QtCore/qtranslator.h>
#include <QtCore/qdebug.h>
@@ -73,8 +74,8 @@ QDebug operator<<(QDebug debug, const TranslationBindingInformation &translation
{
QQmlError error;
error.setUrl(translationBindingInformation.compilationUnit->url());
- error.setLine(translationBindingInformation.compiledBinding->valueLocation.line);
- error.setColumn(translationBindingInformation.compiledBinding->valueLocation.column);
+ error.setLine(translationBindingInformation.compiledBinding->valueLocation.line());
+ error.setColumn(translationBindingInformation.compiledBinding->valueLocation.column());
error.setDescription(
QString(QLatin1String(
"QDebug translation binding"
@@ -96,8 +97,7 @@ public:
void setState(const QString &stateName)
{
- if (currentQuickView) {
- QQuickItem *rootItem = currentQuickView->rootObject();
+ if (QQuickItem *rootItem = currentRootItem()) {
QQuickStateGroup *stateGroup = QQuickItemPrivate::get(rootItem)->_states();
if (stateGroup->findState(stateName)) {
connect(stateGroup, &QQuickStateGroup::stateChanged,
@@ -106,17 +106,16 @@ public:
stateGroup->setState(stateName);
}
else
- qWarning() << QString("Could not switch the state to %1").arg(stateName);
+ qWarning() << "Could not switch the state" << stateName << "at" << rootItem;
}
}
void sendStateChanged()
{
- QString stateName;
if (QQuickStateGroup *stateGroup = qobject_cast<QQuickStateGroup*>(sender()))
- stateName = stateGroup->state();
+ currentStateName = stateGroup->state();
QVersionedPacket<QQmlDebugConnector> packet;
- packet << Reply::StateChanged << stateName;
+ packet << Reply::StateChanged << currentStateName;
emit q->messageToClient(q->name(), packet.data());
}
@@ -124,17 +123,18 @@ public:
{
QVersionedPacket<QQmlDebugConnector> packet;
packet << Reply::StateList;
+ QVector<QmlState> qmlStates;
- QQuickItem *rootItem = currentQuickView->rootObject();
- QQuickStateGroup *stateGroup = QQuickItemPrivate::get(rootItem)->_states();
+ if (QQuickItem *rootItem = currentRootItem()) {
+ QQuickStateGroup *stateGroup = QQuickItemPrivate::get(rootItem)->_states();
- QList<QQuickState *> states = stateGroup->states();
- QVector<QmlState> qmlStates;
+ QList<QQuickState *> states = stateGroup->states();
- for (QQuickState *state : states) {
- QmlState qmlState;
- qmlState.name = state->name();
- qmlStates.append(qmlState);
+ for (QQuickState *state : states) {
+ QmlState qmlState;
+ qmlState.name = state->name();
+ qmlStates.append(qmlState);
+ }
}
packet << qmlStates;
@@ -157,6 +157,22 @@ public:
}
}
+ QString getStyleNameForFont(const QFont& font)
+ {
+ if (font.styleName() != "")
+ return font.styleName();
+ QString styleName;
+ if (font.bold())
+ styleName.append("Bold ");
+ if (font.italic())
+ styleName.append("Italic " );
+ if (font.strikeOut())
+ styleName.append("StrikeThrough ");
+ if (font.underline())
+ styleName.append("Underline ");
+ return styleName.trimmed();
+ }
+
void sendTranslatableTextOccurrences()
{
@@ -193,13 +209,14 @@ public:
qmlElement.fontFamily = font.family();
qmlElement.fontPointSize = font.pointSize();
qmlElement.fontPixelSize = font.pixelSize();
- qmlElement.fontStyleName = font.styleName();
+ qmlElement.fontStyleName = getStyleNameForFont(font);
qmlElement.horizontalAlignment =
scopeObject->property("horizontalAlignment").toInt();
qmlElement.verticalAlignment = scopeObject->property("verticalAlignment").toInt();
QQmlType qmlType = QQmlMetaType::qmlType(metaObject);
qmlElement.elementType = qmlType.qmlTypeName() + "/" + qmlType.typeName();
+ qmlElement.stateName = currentStateName;
qmlElements.append(qmlElement);
} else {
@@ -224,10 +241,10 @@ public:
emit q->messageToClient(q->name(), packet.data());
}
- void sendMissingTranslations()
+ void sendTranslationIssues()
{
QVersionedPacket<QQmlDebugConnector> packet;
- packet << Reply::MissingTranslations;
+ packet << Reply::TranslationIssues;
QVector<TranslationIssue> issues;
for (auto &&information : qAsConst(objectTranslationBindingMultiMap)) {
@@ -238,6 +255,18 @@ public:
issue.language = proxyTranslator->currentUILanguages();
issues.append(issue);
}
+
+ QObject *scopeObject = information.scopeObject;
+ QQuickText *quickText = static_cast<QQuickText*>(scopeObject);
+ if (quickText) {
+ if (quickText->truncated()) {
+ TranslationIssue issue;
+ issue.type = TranslationIssue::Type::Elided;
+ issue.codeMarker = codeMarker(information);
+ issue.language = proxyTranslator->currentUILanguages();
+ issues.append(issue);
+ }
+ }
}
std::sort(issues.begin(), issues.end(), [](const auto &l1, const auto &l2){
return l1.codeMarker < l2.codeMarker;
@@ -246,20 +275,6 @@ public:
emit q->messageToClient(q->name(), packet.data());
}
- void sendElidedTextWarning(const TranslationBindingInformation &information)
- {
- QVersionedPacket<QQmlDebugConnector> packet;
- packet << Reply::TextElided;
-
- TranslationIssue issue;
- issue.type = TranslationIssue::Type::Elided;
- issue.codeMarker = codeMarker(information);
- issue.language = proxyTranslator->currentUILanguages();
-
- packet << issue;
- emit q->messageToClient(q->name(), packet.data());
- }
-
QQmlDebugTranslationServiceImpl *q;
bool watchTextElides = false;
@@ -271,16 +286,26 @@ public:
QTimer translatableTextOccurrenceTimer;
QList<QPointer<QQuickItem>> translatableTextOccurrences;
- QPointer<QQuickView> currentQuickView;
+ QQuickItem *currentRootItem()
+ {
+ if (QQmlPreviewServiceImpl *service = QQmlDebugConnector::service<QQmlPreviewServiceImpl>())
+ return service->currentRootItem();
+ if (currentQuickView)
+ return currentQuickView->rootObject();
+ return nullptr;
+ }
+ QQuickView* currentQuickView = nullptr;
+
private:
CodeMarker codeMarker(const TranslationBindingInformation &information)
{
CodeMarker c;
c.url = information.compilationUnit->url();
- c.line = information.compiledBinding->valueLocation.line;
- c.column = information.compiledBinding->valueLocation.column;
+ c.line = information.compiledBinding->valueLocation.line();
+ c.column = information.compiledBinding->valueLocation.column();
return c;
}
+ QString currentStateName;
};
QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent)
@@ -300,14 +325,17 @@ QQmlDebugTranslationServiceImpl::QQmlDebugTranslationServiceImpl(QObject *parent
d, &QQmlDebugTranslationServicePrivate::setState,
Qt::QueuedConnection);
- connect(this, &QQmlDebugTranslationServiceImpl::stateList, d,
- &QQmlDebugTranslationServicePrivate::sendStateList, Qt::QueuedConnection);
+ connect(this, &QQmlDebugTranslationServiceImpl::stateList,
+ d, &QQmlDebugTranslationServicePrivate::sendStateList,
+ Qt::QueuedConnection);
connect(d->proxyTranslator, &ProxyTranslator::languageChanged,
- d, &QQmlDebugTranslationServicePrivate::sendLanguageChanged);
+ d, &QQmlDebugTranslationServicePrivate::sendLanguageChanged,
+ Qt::QueuedConnection);
- connect(this, &QQmlDebugTranslationServiceImpl::missingTranslations,
- d, &QQmlDebugTranslationServicePrivate::sendMissingTranslations);
+ connect(this, &QQmlDebugTranslationServiceImpl::translationIssues,
+ d, &QQmlDebugTranslationServicePrivate::sendTranslationIssues,
+ Qt::QueuedConnection);
connect(this, &QQmlDebugTranslationServiceImpl::sendTranslatableTextOccurrences,
d, &QQmlDebugTranslationServicePrivate::sendTranslatableTextOccurrences,
@@ -344,8 +372,8 @@ void QQmlDebugTranslationServiceImpl::messageReceived(const QByteArray &message)
emit stateList();
break;
}
- case QQmlDebugTranslation::Request::MissingTranslations: {
- emit missingTranslations();
+ case QQmlDebugTranslation::Request::TranslationIssues: {
+ emit translationIssues();
break;
}
case QQmlDebugTranslation::Request::TranslatableTextOccurrences: {
@@ -385,59 +413,18 @@ void QQmlDebugTranslationServiceImpl::engineAboutToBeRemoved(QJSEngine *engine)
emit detachedFromEngine(engine);
}
-QString QQmlDebugTranslationServiceImpl::foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText)
-{
- Q_UNUSED(layoutText)
- QString elidedTextResult = elideText;
- // do the check only for text objects which have translation bindings
- auto it = d->objectTranslationBindingMultiMap.find(textObject);
- if (it != d->objectTranslationBindingMultiMap.end()) {
- if (QQuickItem* quickItem = qobject_cast<QQuickItem*>(textObject)) {
- //const QColor originColor = quickItem->color();
- const TranslationBindingInformation information = d->objectTranslationBindingMultiMap.value(quickItem);
- if (d->watchTextElides && d->proxyTranslator->hasTranslation(information)) {
- d->sendElidedTextWarning(information);
- }
- if (!d->elideConnections.contains(quickItem)) {
- // add "refresh" elide state connections which remove themself
- auto clearElideInformation = [=]() {
- //quickItem->setColor(originColor);
- for (QMetaObject::Connection connection : d->elideConnections.value(quickItem))
- quickItem->disconnect(connection);
- d->elideConnections.remove(quickItem);
- };
-
- auto connectWithChangedWidthThreshold = [=] () {
- return connect(quickItem, &QQuickItem::widthChanged, [=]() {
- if (quickItem->implicitWidth() <= quickItem->width())
- clearElideInformation();
- });
- };
- auto connectImplicitWidthChangedThreshold = [=] () {
- return connect(quickItem, &QQuickItem::implicitWidthChanged, [=]() {
- if (quickItem->implicitWidth() <= quickItem->width())
- clearElideInformation();
- });
- };
-
- d->elideConnections.insert(quickItem,
- {connectWithChangedWidthThreshold(),
- connectImplicitWidthChangedThreshold()});
- }
- }
- }
- return elidedTextResult;
-}
-
void QQmlDebugTranslationServiceImpl::foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation)
{
QObject *scopeObject = translationBindingInformation.scopeObject;
connect(scopeObject, &QObject::destroyed, [this, scopeObject] () {
this->d->objectTranslationBindingMultiMap.remove(scopeObject);
});
+
d->objectTranslationBindingMultiMap.insert(scopeObject, translationBindingInformation);
}
QT_END_NAMESPACE
+#include "moc_qqmldebugtranslationservice.cpp"
+
#include <qqmldebugtranslationservice.moc>
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
index 72e70f4b29..e0d1b2d9a8 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmldebugtranslationservice.h
@@ -68,7 +68,6 @@ public:
QQmlDebugTranslationServiceImpl(QObject *parent = 0);
~QQmlDebugTranslationServiceImpl();
- QString foundElidedText(QObject *textObject, const QString &layoutText, const QString &elideText) override;
void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) override;
void messageReceived(const QByteArray &message) override;
@@ -80,7 +79,8 @@ signals:
void state(const QString &stateName);
void stateList();
void watchTextElides(bool);
- void missingTranslations();
+ void translationIssues();
+ void elidedTranslations();
void sendTranslatableTextOccurrences();
private:
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
index 5e78539155..e11b8c9776 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileengine.cpp
@@ -398,6 +398,14 @@ bool QQmlPreviewFileEngine::supportsExtension(Extension extension) const
void QQmlPreviewFileEngine::load() const
{
+ // We can get here from different threads on different instances of QQmlPreviewFileEngine.
+ // However, there is only one loader per QQmlPreviewFileEngineHandler and it is not thread-safe.
+ // Its content mutex doesn't help us here because we explicitly wait on it in load(), which
+ // causes it to be released. Therefore, lock the load mutex first.
+ // This doesn't cause any deadlocks because the only thread that wakes the loader on the content
+ // mutex never calls load(). It's the QML debug server thread that handles the debug protocol.
+ QMutexLocker loadLocker(m_loader->loadMutex());
+
m_result = m_loader->load(m_absolute);
switch (m_result) {
case QQmlPreviewFileLoader::File:
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
index ffe50697f8..48e61dcae8 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.cpp
@@ -60,7 +60,7 @@ QQmlPreviewFileLoader::QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service) :
for (int loc = QLibraryInfo::PrefixPath; loc < QLibraryInfo::TestsPath; ++loc) {
m_blacklist.blacklist(QLibraryInfo::path(
- static_cast<QLibraryInfo::LibraryLocation>(loc)));
+ static_cast<QLibraryInfo::LibraryPath>(loc)));
}
m_blacklist.blacklist(QLibraryInfo::path(QLibraryInfo::SettingsPath));
@@ -99,7 +99,7 @@ QQmlPreviewFileLoader::~QQmlPreviewFileLoader() {
QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_path = path;
auto fileIterator = m_fileCache.constFind(path);
@@ -122,19 +122,19 @@ QQmlPreviewFileLoader::Result QQmlPreviewFileLoader::load(const QString &path)
m_entries.clear();
m_contents.clear();
emit request(path);
- m_waitCondition.wait(&m_mutex);
+ m_waitCondition.wait(&m_contentMutex);
return m_result;
}
QByteArray QQmlPreviewFileLoader::contents()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_contents;
}
QStringList QQmlPreviewFileLoader::entries()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_entries;
}
@@ -142,20 +142,20 @@ void QQmlPreviewFileLoader::whitelist(const QUrl &url)
{
const QString path = QQmlFile::urlToLocalFileOrQrc(url);
if (!path.isEmpty()) {
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
}
}
bool QQmlPreviewFileLoader::isBlacklisted(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
return m_blacklist.isBlacklisted(path);
}
void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
m_fileCache[path] = contents;
if (path == m_path) {
@@ -167,7 +167,7 @@ void QQmlPreviewFileLoader::file(const QString &path, const QByteArray &contents
void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &entries)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.whitelist(path);
m_directoryCache[path] = entries;
if (path == m_path) {
@@ -179,7 +179,7 @@ void QQmlPreviewFileLoader::directory(const QString &path, const QStringList &en
void QQmlPreviewFileLoader::error(const QString &path)
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_blacklist.blacklist(path);
if (path == m_path) {
m_result = Fallback;
@@ -189,9 +189,11 @@ void QQmlPreviewFileLoader::error(const QString &path)
void QQmlPreviewFileLoader::clearCache()
{
- QMutexLocker locker(&m_mutex);
+ QMutexLocker locker(&m_contentMutex);
m_fileCache.clear();
m_directoryCache.clear();
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewfileloader.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
index 0c55c48c4a..ffda9c0dbf 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewfileloader.h
@@ -79,7 +79,9 @@ public:
QQmlPreviewFileLoader(QQmlPreviewServiceImpl *service);
~QQmlPreviewFileLoader();
+ QMutex *loadMutex() { return &m_loadMutex; }
Result load(const QString &file);
+
QByteArray contents();
QStringList entries();
@@ -90,7 +92,8 @@ signals:
void request(const QString &file);
private:
- QMutex m_mutex;
+ QMutex m_loadMutex;
+ QMutex m_contentMutex;
QWaitCondition m_waitCondition;
QThread m_thread;
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
index b8453128d8..e3dfa7b9ed 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp
@@ -112,6 +112,11 @@ bool QQmlPreviewHandler::eventFilter(QObject *obj, QEvent *event)
return QObject::eventFilter(obj, event);
}
+QQuickItem *QQmlPreviewHandler::currentRootItem()
+{
+ return m_currentRootItem;
+}
+
void QQmlPreviewHandler::addEngine(QQmlEngine *qmlEngine)
{
m_engines.append(qmlEngine);
@@ -288,6 +293,8 @@ void QQmlPreviewHandler::showObject(QObject *object)
item->setParentItem(m_currentWindow->contentItem());
m_currentWindow->resize(item->size().toSize());
+ // used by debug translation service to get the states
+ m_currentRootItem = item;
} else {
emit error(QLatin1String("Created object is neither a QWindow nor a QQuickItem."));
}
@@ -417,3 +424,5 @@ void QQmlPreviewHandler::tryCreateObject()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewhandler.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
index b7ee8fa09b..4e9a092a58 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h
@@ -74,6 +74,8 @@ public:
explicit QQmlPreviewHandler(QObject *parent = nullptr);
~QQmlPreviewHandler();
+ QQuickItem *currentRootItem();
+
void addEngine(QQmlEngine *engine);
void removeEngine(QQmlEngine *engine);
@@ -116,6 +118,7 @@ private:
QScopedPointer<QQuickItem> m_dummyItem;
QList<QQmlEngine *> m_engines;
+ QPointer<QQuickItem> m_currentRootItem;
QVector<QPointer<QObject>> m_createdObjects;
QScopedPointer<QQmlComponent> m_component;
QPointer<QQuickWindow> m_currentWindow;
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
index b6d6a7a220..cf61d25a0f 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.cpp
@@ -183,4 +183,11 @@ void QQmlPreviewServiceImpl::forwardFps(const QQmlPreviewHandler::FpsInfo &frame
emit messageToClient(name(), packet.data());
}
+QQuickItem *QQmlPreviewServiceImpl::currentRootItem()
+{
+ return m_handler.currentRootItem();
+}
+
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewservice.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
index 56deb7f092..39d68bbc39 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservice.h
@@ -90,6 +90,8 @@ public:
void forwardError(const QString &error);
void forwardFps(const QQmlPreviewHandler::FpsInfo &frames);
+ QQuickItem *currentRootItem();
+
signals:
void error(const QString &file);
void file(const QString &file, const QByteArray &contents);
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
index 23329dbcf2..9c09e1fc1a 100644
--- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
+++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewservicefactory.cpp
@@ -57,3 +57,5 @@ QQmlDebugService *QQmlPreviewServiceFactory::create(const QString &key)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewservicefactory.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_profiler/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_profiler/CMakeLists.txt
index 823a94493c..b18c9f7c1a 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_profiler/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQmlProfilerServiceFactoryPlugin
OUTPUT_NAME qmldbg_profiler
CLASS_NAME QQmlProfilerServiceFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qqmlenginecontrolservice.cpp qqmlenginecontrolservice.h
qqmlprofileradapter.cpp qqmlprofileradapter.h
diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
index 4702bc3c33..7a1b19ab8b 100644
--- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp
@@ -159,3 +159,5 @@ void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data,
}
QT_END_NAMESPACE
+
+#include "moc_qqmlprofileradapter.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_quickprofiler/CMakeLists.txt
index 529f0eaecc..5b38060052 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QQuickProfilerAdapterFactoryPlugin
OUTPUT_NAME qmldbg_quickprofiler
CLASS_NAME QQuickProfilerAdapterFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qquickprofileradapter.cpp qquickprofileradapter.h
qquickprofileradapterfactory.cpp qquickprofileradapterfactory.h
diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
index 79a1c82411..0abd54dfb1 100644
--- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
+++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp
@@ -175,3 +175,5 @@ void QQuickProfilerAdapter::receiveData(const QVector<QQuickProfilerData> &new_d
}
QT_END_NAMESPACE
+
+#include "moc_qquickprofileradapter.cpp"
diff --git a/src/plugins/qmltooling/qmldbg_server/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_server/CMakeLists.txt
index 7795b3acc2..927f077b64 100644
--- a/src/plugins/qmltooling/qmldbg_server/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_server/CMakeLists.txt
@@ -7,9 +7,9 @@
qt_internal_add_plugin(QQmlDebugServerFactoryPlugin
OUTPUT_NAME qmldbg_server
CLASS_NAME QQmlDebugServerFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
- qqmldebugserver.cpp
+ qqmldebugserverfactory.cpp
qqmldebugserverfactory.h
LIBRARIES
Qt::PacketProtocolPrivate
diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp
index 0e4c90f987..8f17eb94cd 100644
--- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp
+++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.cpp
@@ -766,4 +766,5 @@ QQmlDebugConnector *QQmlDebugServerFactory::create(const QString &key)
QT_END_NAMESPACE
-#include "qqmldebugserver.moc"
+#include "moc_qqmldebugserverfactory.cpp"
+#include "qqmldebugserverfactory.moc"
diff --git a/src/plugins/qmltooling/qmldbg_tcp/CMakeLists.txt b/src/plugins/qmltooling/qmldbg_tcp/CMakeLists.txt
index c9e07a4912..aaed477b60 100644
--- a/src/plugins/qmltooling/qmldbg_tcp/CMakeLists.txt
+++ b/src/plugins/qmltooling/qmldbg_tcp/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QTcpServerConnectionFactoryPlugin
OUTPUT_NAME qmldbg_tcp
CLASS_NAME QTcpServerConnectionFactory
- TYPE qmltooling
+ PLUGIN_TYPE qmltooling
SOURCES
qtcpserverconnection.cpp
qtcpserverconnectionfactory.h
diff --git a/src/plugins/scenegraph/openvg/CMakeLists.txt b/src/plugins/scenegraph/openvg/CMakeLists.txt
index 07cea45827..da1cb42656 100644
--- a/src/plugins/scenegraph/openvg/CMakeLists.txt
+++ b/src/plugins/scenegraph/openvg/CMakeLists.txt
@@ -7,7 +7,7 @@
qt_internal_add_plugin(QSGOpenVGAdaptationPlugin
OUTPUT_NAME qsgopenvgbackend
CLASS_NAME QSGOpenVGAdaptation
- TYPE scenegraph
+ PLUGIN_TYPE scenegraph
TARGET_PRODUCT "Qt Quick OpenVG Renderer (Qt $$QT_VERSION)"
TARGET_DESCRIPTION "Quick OpenVG Renderer for Qt."
SOURCES
diff --git a/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
index ab5cfb48b8..615d6e8726 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvghelpers.cpp
@@ -420,6 +420,7 @@ QImage::Format qVGImageFormatToQImageFormat(VGImageFormat format)
break;
case VG_sL_8:
qImageFormat = QImage::Format_Grayscale8;
+ break;
default:
qImageFormat = QImage::Format_ARGB32;
break;
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index af4ebb510f..1cacf0d889 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -19,6 +19,15 @@ if (QT_FEATURE_qml_worker_script)
)
endif()
+set(extra_cmake_files)
+set(extra_cmake_includes)
+if(ANDROID)
+ list(APPEND extra_cmake_files
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
+ list(APPEND extra_cmake_includes
+ "${INSTALL_CMAKE_NAMESPACE}AndroidQmlMacros.cmake")
+endif()
+
qt_internal_add_qml_module(Qml
URI "QtQml"
VERSION "${PROJECT_VERSION}"
@@ -381,10 +390,21 @@ qt_internal_add_qml_module(Qml
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}qmldirTemplate.cmake.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlPluginTemplate.cpp.in"
"${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
+ ${extra_cmake_files}
EXTRA_CMAKE_INCLUDES
"${INSTALL_CMAKE_NAMESPACE}QmlFindQmlscInternal.cmake"
+ ${extra_cmake_includes}
)
+# Linking to the static qml plugin should also automatically link to the worker script
+# static plugin otherwise you get errors like
+# module "QtQml.WorkerScript" plugin "workerscriptplugin" not found
+# import QtQuick 2.0
+# ^
+if(QT_FEATURE_qml_worker_script)
+ _qt_internal_add_qml_static_plugin_dependency(qmlplugin workerscriptplugin)
+endif()
+
# special case begin remove the block, handled manually
# QLALR Grammars:
#qt_process_qlalr(
@@ -478,22 +498,6 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_animation
animations
)
-#### Keys ignored in scope 18:.:common:common/common.pri:NOT build_pass:
-# compile_hash_contents = "// Generated file, DO NOT EDIT" "$${LITERAL_HASH}define QML_COMPILE_HASH "$$QML_COMPILE_HASH"" "$${LITERAL_HASH}define QML_COMPILE_HASH_LENGTH $$str_size($$QML_COMPILE_HASH)"
-# tag = <EMPTY>
-# tagFile = "$$PWD/../../.tag"
-
-#### Keys ignored in scope 19:.:common:common/common.pri:EXISTS _ss_tagFile:
-# QMAKE_INTERNAL_INCLUDED_FILES = "$$tagFile"
-# tag = "$$cat($$tagFile, singleline)"
-
-#### Keys ignored in scope 20:.:common:common/common.pri:NOT tag___equals____ss_{LITERAL_DOLLAR}Format AND %H_ss_{LITERAL_DOLLAR}:
-# QML_COMPILE_HASH = "$$tag"
-
-#### Keys ignored in scope 22:.:common:common/common.pri:EXISTS _ss_PWD/../../.git:
-# QML_COMPILE_HASH = "$$commit"
-# commit = "$$system(git rev-parse HEAD)"
-
qt_internal_extend_target(Qml CONDITION GCC AND QT_COMPILER_VERSION_MAJOR STREQUAL 5
COMPILE_OPTIONS
-fno-strict-aliasing
@@ -506,7 +510,7 @@ qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_debug
debugger/qqmldebug.cpp
debugger/qqmldebugconnector.cpp
debugger/qqmldebugpluginmanager_p.h
- debugger/qqmldebugserver_p.h
+ debugger/qqmldebugserver.cpp debugger/qqmldebugserver_p.h
debugger/qqmldebugserverconnection_p.h
debugger/qqmldebugservice.cpp debugger/qqmldebugservice_p.h
debugger/qqmldebugservicefactory_p.h
@@ -572,11 +576,6 @@ qt_internal_extend_target(Qml CONDITION hpux-_x_ OR solaris-_x_ OR (QT_FEATURE_c
rt
)
-qt_internal_extend_target(Qml CONDITION QT_FEATURE_qml_itemmodel
- SOURCES
- types/qqmlmodelindexvaluetype.cpp types/qqmlmodelindexvaluetype_p.h
-)
-
qt_internal_extend_target(Qml CONDITION disassembler AND ((TEST_architecture_arch STREQUAL "i386") OR (TEST_architecture_arch STREQUAL "x86_64"))
DEFINES
WTF_USE_UDIS86=1
@@ -669,3 +668,13 @@ qt_internal_create_tracepoints(Qml qtqml.tracepoints)
qt_internal_add_docs(Qml
doc/qtqml.qdocconf
)
+
+# include snippet projects for developer shared builds
+# static builds fail with
+# CMake Error: AUTOMOC for target qt_target_qml_sources_example_resources_3:
+# The "moc" executable does not exist
+if(QT_FEATURE_private_tests AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.19" AND QT_BUILD_SHARED_LIBS)
+ add_subdirectory(doc/snippets/cmake/qt_target_qml_sources)
+ qt_autogen_tools(qt_target_qml_sources_example ENABLE_AUTOGEN_TOOLS moc)
+ qt_autogen_tools(qt_target_qml_sources_exampleplugin ENABLE_AUTOGEN_TOOLS moc)
+endif()
diff --git a/src/qml/Qt6AndroidQmlMacros.cmake b/src/qml/Qt6AndroidQmlMacros.cmake
new file mode 100644
index 0000000000..12be515531
--- /dev/null
+++ b/src/qml/Qt6AndroidQmlMacros.cmake
@@ -0,0 +1,21 @@
+# The function collects qml root paths and sets the QT_QML_ROOT_PATH property to the ${target}
+# based on the provided qml source files.
+function(_qt_internal_collect_qml_root_paths target)
+ get_target_property(qml_root_paths ${target} QT_QML_ROOT_PATH)
+ if(NOT qml_root_paths)
+ set(qml_root_paths "")
+ endif()
+ foreach(file IN LISTS ARGN)
+ get_filename_component(extension "${file}" LAST_EXT)
+ if(NOT extension STREQUAL ".qml")
+ continue()
+ endif()
+
+ get_filename_component(dir "${file}" DIRECTORY)
+ get_filename_component(absolute_dir "${dir}" ABSOLUTE)
+ list(APPEND qml_root_paths "${absolute_dir}")
+ endforeach()
+
+ list(REMOVE_DUPLICATES qml_root_paths)
+ set_target_properties(${target} PROPERTIES QT_QML_ROOT_PATH "${qml_root_paths}")
+endfunction()
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index ea5d3606ce..c84a7a9d90 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -4,31 +4,12 @@
include_guard(GLOBAL)
-# This function is essentially a wrapper around qt6_add_qml_module().
-# It creates the targets explicitly and sets up internal properties before
-# passing those targets to qt6_add_qml_module() for further updates.
-# All keywords supported by qt_internal_add_module() can be used, as can most
-# keywords for qt6_add_qml_module() except RESOURCE_PREFIX and
-# OUTPUT_TARGETS.
-#
-# OUTPUT_DIRECTORY and INSTALL_DIRECTORY will be given more appropriate defaults
-# if not provided by the caller. The defaults are usually what you want to use.
-#
-# - SOURCES is only passed through to qt_internal_add_plugin() or
-# qt_internal_add_module() but not to qt6_add_qml_module().
-#
-# See qt_internal_add_plugin() and qt6_add_qml_module() for the full set of
-# supported keywords.
-function(qt_internal_add_qml_module target)
-
- qt_internal_get_internal_add_module_keywords(
- module_option_args
- module_single_args
- module_multi_args
- )
-
- set(qml_module_option_args
+macro(qt_internal_get_internal_add_qml_module_keywords
+ option_args single_args multi_args
+ internal_option_args internal_single_args internal_multi_args)
+ set(${option_args}
DESIGNER_SUPPORTED
+ NO_PLUGIN
NO_PLUGIN_OPTIONAL
NO_CREATE_PLUGIN_TARGET
NO_GENERATE_PLUGIN_SOURCE
@@ -37,15 +18,7 @@ function(qt_internal_add_qml_module target)
NO_LINT
NO_CACHEGEN
)
- # 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
- )
-
- set(qml_module_single_args
+ set(${single_args}
URI
VERSION
PLUGIN_TARGET
@@ -54,9 +27,7 @@ function(qt_internal_add_qml_module target)
CLASSNAME # TODO: Remove once all other repos have been updated to use
# CLASS_NAME instead.
)
-
- set(qml_module_multi_args
- # SOURCES will be handled by qt_internal_add_module()
+ set(${multi_args}
QML_FILES
RESOURCES
IMPORTS
@@ -65,7 +36,6 @@ function(qt_internal_add_qml_module target)
DEPENDENCIES
PAST_MAJOR_VERSIONS
)
-
# Args used by qt_internal_add_qml_module directly, which should not be passed to any other
# functions.
#
@@ -73,28 +43,71 @@ function(qt_internal_add_qml_module target)
# installed.
#
# INSTALL_SOURCE_QMLDIR takes a path to an existing qmldir file that should be installed.
- set(internal_option_args
+ set(${internal_option_args}
)
-
- set(internal_single_args
+ set(${internal_single_args}
INSTALL_SOURCE_QMLTYPES
INSTALL_SOURCE_QMLDIR
)
+ set(${internal_multi_args}
+ )
+
+endmacro()
+
+# This function is essentially a wrapper around qt6_add_qml_module().
+# It creates the targets explicitly and sets up internal properties before
+# passing those targets to qt6_add_qml_module() for further updates.
+# All keywords supported by qt_internal_add_module() can be used, as can most
+# keywords for qt6_add_qml_module() except RESOURCE_PREFIX and
+# OUTPUT_TARGETS.
+#
+# OUTPUT_DIRECTORY and INSTALL_DIRECTORY will be given more appropriate defaults
+# if not provided by the caller. The defaults are usually what you want to use.
+#
+# - SOURCES is only passed through to qt_internal_add_plugin() or
+# qt_internal_add_module() but not to qt6_add_qml_module().
+#
+# See qt_internal_add_plugin() and qt6_add_qml_module() for the full set of
+# supported keywords.
+function(qt_internal_add_qml_module target)
+
+ qt_internal_get_internal_add_module_keywords(
+ module_option_args
+ module_single_args
+ module_multi_args
+ )
+
+ qt_internal_get_internal_add_qml_module_keywords(
+ qml_module_option_args
+ qml_module_single_args
+ qml_module_multi_args
+ qml_module_internal_option_args
+ qml_module_internal_single_args
+ qml_module_internal_multi_args
+ )
+ # 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
+ )
set(option_args
${module_option_args}
${qml_module_option_args}
${ignore_option_args}
- ${internal_option_args}
+ ${qml_module_internal_option_args}
)
set(single_args
${module_single_args}
${qml_module_single_args}
- ${internal_single_args}
+ ${qml_module_internal_single_args}
)
set(multi_args
${module_multi_args}
${qml_module_multi_args}
+ ${qml_module_internal_multi_args}
)
qt_parse_all_arguments(arg "qt_internal_add_qml_module"
@@ -112,7 +125,9 @@ function(qt_internal_add_qml_module target)
if(NOT arg_INSTALL_DIRECTORY)
set(arg_INSTALL_DIRECTORY "${INSTALL_QMLDIR}/${target_path}")
endif()
- if(NOT arg_PLUGIN_TARGET)
+ if(arg_NO_PLUGIN)
+ unset(arg_PLUGIN_TARGET)
+ elseif(NOT arg_PLUGIN_TARGET)
set(arg_PLUGIN_TARGET ${target}plugin)
endif()
@@ -129,7 +144,7 @@ function(qt_internal_add_qml_module target)
endif()
set(plugin_args "")
- if(NOT arg_PLUGIN_TARGET STREQUAL target)
+ if(arg_NO_PLUGIN OR NOT arg_PLUGIN_TARGET STREQUAL target)
# Allow using an existing backing target.
if(NOT TARGET ${target})
# Create the backing target now to handle module-related things
@@ -139,8 +154,9 @@ function(qt_internal_add_qml_module target)
${qml_module_option_args}
${qml_module_single_args}
${qml_module_multi_args}
- ${internal_option_args}
- ${internal_single_args}
+ ${qml_module_internal_option_args}
+ ${qml_module_internal_single_args}
+ ${qml_module_internal_multi_args}
OUTPUT_DIRECTORY
INSTALL_DIRECTORY
ALL_ARGS
@@ -151,6 +167,9 @@ function(qt_internal_add_qml_module target)
${ARGN}
)
qt_internal_add_module(${target} ${module_args})
+ elseif(arg_SOURCES)
+ # If a module target was pre-created, we still need to pass the additional sources.
+ target_sources(${target} PRIVATE ${arg_SOURCES})
endif()
else()
# Since we are not creating a separate backing target, we have to pass
@@ -181,7 +200,9 @@ function(qt_internal_add_qml_module target)
)
endif()
- if(NOT arg_NO_CREATE_PLUGIN_TARGET)
+ set(add_qml_module_args "")
+
+ if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET)
# If the qt_internal_add_qml_module call didn't specify a CLASS_NAME, we need to pre-compute
# it here and pass it along to qt_internal_add_plugin -> qt_add_plugin so that
# qt_add_qml_plugin does not complain about differing class names (the default pre-computed
@@ -192,7 +213,7 @@ function(qt_internal_add_qml_module target)
# Create plugin target now so we can set internal things
list(APPEND plugin_args
- TYPE qml_plugin
+ PLUGIN_TYPE qml_plugin
DEFAULT_IF FALSE
OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
INSTALL_DIRECTORY ${arg_INSTALL_DIRECTORY}
@@ -201,6 +222,40 @@ function(qt_internal_add_qml_module target)
qt_internal_add_plugin(${arg_PLUGIN_TARGET} ${plugin_args})
+ # Use the plugin target name as the main part of the plugin basename.
+ set(plugin_basename "${arg_PLUGIN_TARGET}")
+
+ # If the target name already ends with a "plugin" suffix, remove it and re-add it to the end
+ # of the base name after the infix.
+ if(plugin_basename MATCHES "(.+)plugin$")
+ set(plugin_basename "${CMAKE_MATCH_1}")
+ endif()
+
+ # Add a the infix if Qt was configured with one.
+ if(QT_LIBINFIX)
+ string(APPEND plugin_basename "${QT_LIBINFIX}")
+ endif()
+
+ # Add the "plugin" suffix after the infix.
+ string(APPEND plugin_basename "plugin")
+
+ # Lowercase the whole thing and use it as the basename of the plugin library.
+ string(TOLOWER "${plugin_basename}" plugin_basename)
+ set_target_properties(${arg_PLUGIN_TARGET} PROPERTIES
+ OUTPUT_NAME "${plugin_basename}"
+ )
+
+ get_target_property(export_name ${arg_PLUGIN_TARGET} EXPORT_NAME)
+ if(export_name)
+ list(APPEND add_qml_module_args
+ INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${export_name}"
+ )
+ else()
+ list(APPEND add_qml_module_args
+ INSTALLED_PLUGIN_TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${arg_PLUGIN_TARGET}"
+ )
+ endif()
+
if(NOT arg_PLUGIN_TARGET STREQUAL target)
get_target_property(lib_type ${arg_PLUGIN_TARGET} TYPE)
if(lib_type STREQUAL "STATIC_LIBRARY")
@@ -217,14 +272,6 @@ function(qt_internal_add_qml_module target)
)
endif()
endif()
-
- # FIXME: Some repos expect this to be set and use it to install other
- # things relative to it. They should just specify the install
- # location directly. Once the other repos have been updated to
- # not rely on this, remove this property.
- set_target_properties(${arg_PLUGIN_TARGET} PROPERTIES
- QT_QML_MODULE_INSTALL_DIR ${arg_INSTALL_DIRECTORY}
- )
endif()
# TODO: Check if we need arg_SOURCES in this condition
@@ -246,13 +293,10 @@ function(qt_internal_add_qml_module target)
endif()
endforeach()
- if(QT_LIBINFIX)
- list(APPEND add_qml_module_args __QT_INTERNAL_QT_LIBINFIX "${QT_LIBINFIX}")
- endif()
-
# Update the backing and plugin targets with qml-specific things.
qt6_add_qml_module(${target}
${add_qml_module_args}
+ __QT_INTERNAL_INSTALL_METATYPES_JSON
OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
RESOURCE_PREFIX "/qt-project.org/imports"
OUTPUT_TARGETS output_targets
@@ -329,7 +373,7 @@ function(qt_internal_add_qml_module target)
if(NOT arg_NO_GENERATE_QMLTYPES)
qt_install(
- FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QMLTYPES_FILENAME>
+ FILES ${arg_OUTPUT_DIRECTORY}/$<TARGET_PROPERTY:${target},QT_QML_MODULE_TYPEINFO>
DESTINATION "${arg_INSTALL_DIRECTORY}"
)
endif()
@@ -342,10 +386,6 @@ function(qt_internal_add_qml_module target)
endif()
if(arg_INSTALL_SOURCE_QMLTYPES)
- message(AUTHOR_WARNING
- "INSTALL_SOURCE_QMLTYPES option is deprecated and should not be used. "
- "Please port your module to use declarative type registration.")
-
set(files ${arg_INSTALL_SOURCE_QMLTYPES})
if(QT_WILL_INSTALL)
install(
@@ -361,10 +401,6 @@ function(qt_internal_add_qml_module target)
endif()
if(arg_INSTALL_SOURCE_QMLDIR)
- message(AUTHOR_WARNING
- "INSTALL_SOURCE_QMLDIR option is deprecated and should not be used. "
- "Please port your module to use declarative type registration.")
-
set(files ${arg_INSTALL_SOURCE_QMLDIR})
if(QT_WILL_INSTALL)
install(
diff --git a/src/qml/Qt6QmlConfigExtras.cmake.in b/src/qml/Qt6QmlConfigExtras.cmake.in
index 3d5be2c22c..194dc9eef2 100644
--- a/src/qml/Qt6QmlConfigExtras.cmake.in
+++ b/src/qml/Qt6QmlConfigExtras.cmake.in
@@ -11,3 +11,10 @@ if(NOT QT_NO_CREATE_TARGETS AND
qt@PROJECT_VERSION_MAJOR@_import_qml_plugins
)
endif()
+
+if(ANDROID)
+ # Set the default staging path of qml modules when building for Android
+ if("${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
+ set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/android-qml")
+ endif()
+endif()
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index fe6078e58b..bda7b9b83a 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -9,6 +9,7 @@ function(qt6_add_qml_module target)
STATIC
SHARED
DESIGNER_SUPPORTED
+ NO_PLUGIN
NO_PLUGIN_OPTIONAL
NO_CREATE_PLUGIN_TARGET
NO_GENERATE_PLUGIN_SOURCE
@@ -16,12 +17,18 @@ function(qt6_add_qml_module target)
NO_GENERATE_QMLDIR
NO_LINT
NO_CACHEGEN
+ NO_RESOURCE_TARGET_PATH
# TODO: Remove once all usages have also been removed
SKIP_TYPE_REGISTRATION
+
+ # Used only by _qt_internal_qml_type_registration()
+ # TODO: Remove this once qt6_extract_metatypes does not install by default.
+ __QT_INTERNAL_INSTALL_METATYPES_JSON
)
set(args_single
PLUGIN_TARGET
+ INSTALLED_PLUGIN_TARGET # Internal option only, it may be removed
OUTPUT_TARGETS
RESOURCE_PREFIX
URI
@@ -36,7 +43,6 @@ function(qt6_add_qml_module target)
RESOURCE_EXPORT
INSTALL_DIRECTORY
INSTALL_LOCATION
- __QT_INTERNAL_QT_LIBINFIX # Used only by _qt_internal_target_generate_qmldir()
)
set(args_multi
@@ -116,25 +122,140 @@ function(qt6_add_qml_module target)
)
endif()
- # Provide defaults for options that have one
+ # Other arguments and checking for invalid combinations
if (NOT arg_TARGET_PATH)
+ # NOTE: This will always be used for copying things to the build
+ # directory, but it will not be used for resource paths if
+ # NO_RESOURCE_TARGET_PATH was given.
string(REPLACE "." "/" arg_TARGET_PATH ${arg_URI})
endif()
+ if(arg_NO_PLUGIN AND DEFINED arg_PLUGIN_TARGET)
+ message(FATAL_ERROR
+ "NO_PLUGIN was specified, but PLUGIN_TARGET was also given. "
+ "At most one of these can be present."
+ )
+ endif()
+
set(is_executable FALSE)
if(TARGET ${target})
+ if(arg_STATIC OR arg_SHARED)
+ message(FATAL_ERROR
+ "Cannot use STATIC or SHARED keyword when passed an existing target (${target})"
+ )
+ endif()
+
+ # With CMake 3.17 and earlier, a source file's generated property isn't
+ # visible outside of the directory scope in which it is set. That can
+ # lead to build errors for things like type registration due to CMake
+ # thinking nothing will create a missing file on the first run. With
+ # CMake 3.18 or later, we can force that visibility. Policy CMP0118
+ # added in CMake 3.20 should have made this unnecessary, but we can't
+ # rely on that because the user project controls what it is set to at
+ # the point where it matters, which is the end of the target's
+ # directory scope (hence we can't even test for it here).
+ get_target_property(source_dir ${target} SOURCE_DIR)
+ if(NOT source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR AND
+ CMAKE_VERSION VERSION_LESS "3.18")
+ message(WARNING
+ "qt6_add_qml_module() is being called in a different "
+ "directory scope to the one in which the target \"${target}\" "
+ "was created. CMake 3.18 or later is required to generate a "
+ "project robustly for this scenario, but you are using "
+ "CMake ${CMAKE_VERSION}. Ideally, qt6_add_qml_module() should "
+ "only be called from the same scope as the one the target was "
+ "created in to avoid dependency and visibility problems."
+ )
+ endif()
+
get_target_property(backing_target_type ${target} TYPE)
get_target_property(is_android_executable "${target}" _qt_is_android_executable)
if (backing_target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ if(DEFINED arg_PLUGIN_TARGET)
+ message(FATAL_ERROR
+ "A QML module with an executable as its backing target "
+ "cannot have a plugin."
+ )
+ endif()
+ if(arg_NO_CREATE_PLUGIN_TARGET)
+ message(WARNING
+ "A QML module with an executable as its backing target "
+ "cannot have a plugin. The NO_CREATE_PLUGIN_TARGET option "
+ "has no effect and should be removed."
+ )
+ endif()
+ set(arg_NO_PLUGIN TRUE)
+ set(lib_type "")
set(is_executable TRUE)
+ elseif(arg_NO_RESOURCE_TARGET_PATH)
+ message(FATAL_ERROR
+ "NO_RESOURCE_TARGET_PATH cannot be used for a backing target "
+ "that is not an executable"
+ )
+ elseif(backing_target_type STREQUAL "STATIC_LIBRARY")
+ set(lib_type STATIC)
+ elseif(backing_target_type MATCHES "(SHARED|MODULE)_LIBRARY")
+ set(lib_type SHARED)
+ else()
+ message(FATAL_ERROR "Unsupported backing target type: ${backing_target_type}")
+ endif()
+ else()
+ if(arg_STATIC AND arg_SHARED)
+ message(FATAL_ERROR
+ "Both STATIC and SHARED specified, at most one can be given"
+ )
+ endif()
+
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ message(FATAL_ERROR
+ "NO_RESOURCE_TARGET_PATH can only be provided when an existing "
+ "executable target is passed in as the backing target"
+ )
+ endif()
+
+ # Explicit arguments take precedence, otherwise default to using the same
+ # staticality as what Qt was built with. This follows the already
+ # established default behavior for building ordinary Qt plugins.
+ # We don't allow the standard CMake BUILD_SHARED_LIBS variable to control
+ # the default because that can lead to different defaults depending on
+ # whether you build with a separate backing target or not.
+ if(arg_STATIC)
+ set(lib_type STATIC)
+ elseif(arg_SHARED)
+ set(lib_type SHARED)
+ elseif(QT6_IS_SHARED_LIBS_BUILD)
+ set(lib_type SHARED)
+ else()
+ set(lib_type STATIC)
endif()
endif()
- if(NOT arg_NO_CREATE_PLUGIN_TARGET AND NOT DEFINED arg_PLUGIN_TARGET AND NOT is_executable)
+ if(arg_NO_PLUGIN)
+ # Simplifies things a bit further below
+ set(arg_PLUGIN_TARGET "")
+ elseif(NOT DEFINED arg_PLUGIN_TARGET)
+ if(arg_NO_CREATE_PLUGIN_TARGET)
+ # We technically could allow this and rely on the project using the
+ # default plugin target name, but not doing so gives us the
+ # flexibility to potentially change that default later if needed.
+ message(FATAL_ERROR
+ "PLUGIN_TARGET must also be provided when NO_CREATE_PLUGIN_TARGET "
+ "is used. If you want to disable creating a plugin altogether, "
+ "use the NO_PLUGIN option instead."
+ )
+ endif()
set(arg_PLUGIN_TARGET ${target}plugin)
endif()
- if(NOT DEFINED arg_PLUGIN_TARGET)
- set(arg_PLUGIN_TARGET "") # Simplifies things a bit further below
+ if(arg_NO_CREATE_PLUGIN_TARGET AND arg_PLUGIN_TARGET STREQUAL target AND NOT TARGET ${target})
+ message(FATAL_ERROR
+ "PLUGIN_TARGET is the same as the backing target, which is allowed, "
+ "but NO_CREATE_PLUGIN_TARGET was also given and the target does not "
+ "exist. Either ensure the target is already created or do not "
+ "specify NO_CREATE_PLUGIN_TARGET."
+ )
+ endif()
+ if(NOT arg_INSTALLED_PLUGIN_TARGET)
+ set(arg_INSTALLED_PLUGIN_TARGET ${arg_PLUGIN_TARGET})
endif()
set(no_gen_source)
@@ -142,13 +263,6 @@ function(qt6_add_qml_module target)
set(no_gen_source NO_GENERATE_PLUGIN_SOURCE)
endif()
- set(lib_type "")
- if(arg_STATIC)
- set(lib_type STATIC)
- elseif(arg_SHARED)
- set(lib_type SHARED)
- endif()
-
if(arg_OUTPUT_DIRECTORY)
get_filename_component(arg_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}"
@@ -156,6 +270,18 @@ function(qt6_add_qml_module target)
else()
if("${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
set(arg_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+ # For libraries, we assume/require that the source directory
+ # structure is consistent with the target path. For executables,
+ # the source directory will usually not reflect the target path
+ # and the project will often expect to be able to use resource
+ # paths that don't include the target path (they need the
+ # NO_RESOURCE_TARGET_PATH option if they do that). Tooling always
+ # needs the target path in the file system though, so the output
+ # directory should always have it. Handle the special case for
+ # executables to ensure this is what we get.
+ if(is_executable)
+ string(APPEND arg_OUTPUT_DIRECTORY "/${arg_TARGET_PATH}")
+ endif()
else()
if(NOT IS_ABSOLUTE "${QT_QML_OUTPUT_DIRECTORY}")
message(FATAL_ERROR
@@ -163,10 +289,29 @@ function(qt6_add_qml_module target)
"${QT_QML_OUTPUT_DIRECTORY}"
)
endif()
+ # This inherently does what we want for libraries and executables
set(arg_OUTPUT_DIRECTORY ${QT_QML_OUTPUT_DIRECTORY}/${arg_TARGET_PATH})
endif()
endif()
+ # Sanity check that we are not trying to have two different QML modules use
+ # the same output directory.
+ get_property(dirs GLOBAL PROPERTY _qt_all_qml_output_dirs)
+ if(dirs)
+ list(FIND dirs "${arg_OUTPUT_DIRECTORY}" index)
+ if(NOT index EQUAL -1)
+ get_property(qml_targets GLOBAL PROPERTY _qt_all_qml_targets)
+ list(GET qml_targets ${index} other_target)
+ message(FATAL_ERROR
+ "Output directory for target \"${target}\" is already used by "
+ "another QML module (target \"${other_target}\"). "
+ "Output directory is:\n ${arg_OUTPUT_DIRECTORY}\n"
+ )
+ endif()
+ endif()
+ set_property(GLOBAL APPEND PROPERTY _qt_all_qml_output_dirs ${arg_OUTPUT_DIRECTORY})
+ set_property(GLOBAL APPEND PROPERTY _qt_all_qml_targets ${target})
+
# TODO: Support for old keyword, remove once all repos no longer use CLASSNAME
if(arg_CLASSNAME)
if(arg_CLASS_NAME AND NOT arg_CLASSNAME STREQUAL arg_CLASS_NAME)
@@ -190,11 +335,6 @@ function(qt6_add_qml_module target)
endif()
if(TARGET ${target})
- if(arg_STATIC OR arg_SHARED)
- message(FATAL_ERROR
- "Cannot use STATIC or SHARED keyword when passed an existing target (${target})"
- )
- endif()
if(arg_PLUGIN_TARGET STREQUAL target)
# Insert the plugin's URI into its meta data to enable usage
# of static plugins in QtDeclarative (like in mkspecs/features/qml_plugin.prf).
@@ -203,21 +343,7 @@ function(qt6_add_qml_module target)
)
endif()
else()
- if(arg_STATIC AND arg_SHARED)
- message(FATAL_ERROR
- "Both STATIC and SHARED specified, at most one can be given"
- )
- endif()
-
if(arg_PLUGIN_TARGET STREQUAL target)
- if(arg_NO_CREATE_PLUGIN_TARGET AND NOT TARGET ${target})
- message(FATAL_ERROR
- "NO_CREATE_PLUGIN_TARGET was given, but PLUGIN_TARGET is "
- "the same as the backing target (which is allowed) and the "
- "target does not exist. Either ensure the target is already "
- "created or do not specify NO_CREATE_PLUGIN_TARGET."
- )
- endif()
qt6_add_qml_plugin(${target}
${lib_type}
${no_gen_source}
@@ -226,11 +352,7 @@ function(qt6_add_qml_module target)
CLASS_NAME ${arg_CLASS_NAME}
)
else()
- add_library(${target} ${lib_type})
- if(ANDROID)
- # TODO: Check if we need to do this for a backing library
- qt6_android_apply_arch_suffix(${target})
- endif()
+ qt6_add_library(${target} ${lib_type})
endif()
endif()
@@ -242,19 +364,6 @@ function(qt6_add_qml_module target)
set(arg_TYPEINFO ${target}.qmltypes)
endif()
- # Make the prefix conform to the following:
- # - Starts with a "/"
- # - Does not end with a "/" unless the prefix is exactly "/"
- if(NOT arg_RESOURCE_PREFIX)
- set(arg_RESOURCE_PREFIX "/")
- endif()
- if(NOT arg_RESOURCE_PREFIX MATCHES "^/")
- string(PREPEND arg_RESOURCE_PREFIX "/")
- endif()
- if(arg_RESOURCE_PREFIX MATCHES [[(.*)/$]])
- set(arg_RESOURCE_PREFIX "${CMAKE_MATCH_1}")
- endif()
-
foreach(import_set IN ITEMS IMPORTS OPTIONAL_IMPORTS)
foreach(import IN LISTS arg_${import_set})
string(FIND ${import} "/" slash_position REVERSE)
@@ -303,28 +412,53 @@ function(qt6_add_qml_module target)
endif()
endforeach()
- set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}")
+ _qt_internal_canonicalize_resource_path("${arg_RESOURCE_PREFIX}" arg_RESOURCE_PREFIX)
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}")
+ else()
+ if(arg_RESOURCE_PREFIX STREQUAL "/") # Checked so we prevent double-slash
+ set(qt_qml_module_resource_prefix "/${arg_TARGET_PATH}")
+ else()
+ set(qt_qml_module_resource_prefix "${arg_RESOURCE_PREFIX}/${arg_TARGET_PATH}")
+ endif()
+ endif()
set_target_properties(${target} PROPERTIES
QT_QML_MODULE_NO_LINT "${arg_NO_LINT}"
QT_QML_MODULE_NO_CACHEGEN "${arg_NO_CACHEGEN}"
QT_QML_MODULE_NO_GENERATE_QMLDIR "${arg_NO_GENERATE_QMLDIR}"
+ QT_QML_MODULE_NO_PLUGIN "${arg_NO_PLUGIN}"
QT_QML_MODULE_NO_PLUGIN_OPTIONAL "${arg_NO_PLUGIN_OPTIONAL}"
QT_QML_MODULE_URI "${arg_URI}"
QT_QML_MODULE_TARGET_PATH "${arg_TARGET_PATH}"
QT_QML_MODULE_VERSION "${arg_VERSION}"
QT_QML_MODULE_CLASS_NAME "${arg_CLASS_NAME}"
- QT_QML_MODULE_LIBINFIX "${arg___QT_INTERNAL_QT_LIBINFIX}"
+
QT_QML_MODULE_PLUGIN_TARGET "${arg_PLUGIN_TARGET}"
+ QT_QML_MODULE_INSTALLED_PLUGIN_TARGET "${arg_INSTALLED_PLUGIN_TARGET}"
+
+ # Also Save the PLUGIN_TARGET values in a separate property to circumvent
+ # https://gitlab.kitware.com/cmake/cmake/-/issues/21484 when exporting the properties
+ _qt_qml_module_plugin_target "${arg_PLUGIN_TARGET}"
+ _qt_qml_module_installed_plugin_target "${arg_INSTALLED_PLUGIN_TARGET}"
+
QT_QML_MODULE_DESIGNER_SUPPORTED "${arg_DESIGNER_SUPPORTED}"
- QT_QML_MODULE_OUTPUT_DIR "${arg_OUTPUT_DIRECTORY}"
+ QT_QML_MODULE_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
QT_QML_MODULE_RESOURCE_PREFIX "${qt_qml_module_resource_prefix}"
- QT_QML_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
- QT_QMLTYPES_FILENAME "${arg_TYPEINFO}"
+ QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
+ QT_QML_MODULE_TYPEINFO "${arg_TYPEINFO}"
# TODO: Check how this is used by qt6_android_generate_deployment_settings()
QT_QML_IMPORT_PATH "${arg_IMPORT_PATH}"
)
+
+ # Executables don't have a plugin target, so no need to export the properties.
+ if(NOT backing_target_type STREQUAL "EXECUTABLE" AND NOT is_android_executable)
+ set_property(TARGET ${target} APPEND PROPERTY
+ EXPORT_PROPERTIES _qt_qml_module_plugin_target _qt_qml_module_installed_plugin_target
+ )
+ endif()
+
set(ensure_set_properties
QT_QML_MODULE_PLUGIN_TYPES_FILE
QT_QML_MODULE_RESOURCE_PATHS
@@ -340,7 +474,11 @@ function(qt6_add_qml_module target)
endforeach()
if(NOT arg_NO_GENERATE_QMLTYPES)
- qt6_qml_type_registration(${target})
+ set(type_registration_extra_args "")
+ if(arg___QT_INTERNAL_INSTALL_METATYPES_JSON)
+ list(APPEND type_registration_extra_args __QT_INTERNAL_INSTALL_METATYPES_JSON)
+ endif()
+ _qt_internal_qml_type_registration(${target} ${type_registration_extra_args})
endif()
set(output_targets)
@@ -363,25 +501,52 @@ function(qt6_add_qml_module target)
# if Qt was built with CMake or qmake, while the build system transition phase is still
# happening.
string(REPLACE "/" "_" qmldir_resource_name "qmake_${arg_TARGET_PATH}")
+
+ # The qmldir file ALWAYS has to be under the target path, even in the
+ # resources. If it isn't, an explicit import can't find it. We need a
+ # second copy NOT under the target path if NO_RESOURCE_TARGET_PATH is
+ # given so that the implicit import will work.
+ set(prefixes "${qt_qml_module_resource_prefix}")
+ if(arg_NO_RESOURCE_TARGET_PATH)
+ # The above prefixes item won't include the target path, so add a
+ # second one that does.
+ if(qt_qml_module_resource_prefix STREQUAL "/")
+ list(APPEND prefixes "/${arg_TARGET_PATH}")
+ else()
+ list(APPEND prefixes "${qt_qml_module_resource_prefix}/${arg_TARGET_PATH}")
+ endif()
+ endif()
set_source_files_properties(${arg_OUTPUT_DIRECTORY}/qmldir
PROPERTIES QT_RESOURCE_ALIAS "qmldir"
)
- set(resource_targets)
- qt6_add_resources(${target} ${qmldir_resource_name}
- FILES ${arg_OUTPUT_DIRECTORY}/qmldir
- PREFIX "${qt_qml_module_resource_prefix}"
- OUTPUT_TARGETS resource_targets
- )
- list(APPEND output_targets ${resource_targets})
+
+ foreach(prefix IN LISTS prefixes)
+ set(resource_targets)
+ qt6_add_resources(${target} ${qmldir_resource_name}
+ FILES ${arg_OUTPUT_DIRECTORY}/qmldir
+ PREFIX "${prefix}"
+ OUTPUT_TARGETS resource_targets
+ )
+ list(APPEND output_targets ${resource_targets})
+ # If we are adding the same file twice, we need a different resource
+ # name for the second one. It has the same QT_RESOURCE_ALIAS but a
+ # different prefix, so we can't put it in the same resource.
+ string(APPEND qmldir_resource_name "_copy")
+ endforeach()
endif()
- if(arg_PLUGIN_TARGET AND NOT arg_NO_CREATE_PLUGIN_TARGET AND NOT is_executable)
+ if(NOT arg_NO_PLUGIN AND NOT arg_NO_CREATE_PLUGIN_TARGET)
# This also handles the case where ${arg_PLUGIN_TARGET} already exists,
# including where it is the same as ${target}. If ${arg_PLUGIN_TARGET}
# already exists, it will update the necessary things that are specific
# to qml plugins.
+ if(TARGET ${arg_PLUGIN_TARGET})
+ set(plugin_lib_type "")
+ else()
+ set(plugin_lib_type ${lib_type})
+ endif()
qt6_add_qml_plugin(${arg_PLUGIN_TARGET}
- ${lib_type}
+ ${plugin_lib_type}
${no_gen_source}
OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY}
BACKING_TARGET ${target}
@@ -405,13 +570,19 @@ function(qt6_add_qml_module target)
)
list(APPEND output_targets ${cache_target})
- # Build an init object library for static plugins.
+ # Build an init object library for static plugins and propagate it along with the plugin
+ # target.
+ # TODO: Figure out if we can move this code block into qt_add_qml_plugin. Need to consider
+ # various corner cases.
+ # QTBUG-96937
if(TARGET "${arg_PLUGIN_TARGET}")
- get_target_property(lib_type ${arg_PLUGIN_TARGET} TYPE)
- if(lib_type STREQUAL "STATIC_LIBRARY")
+ get_target_property(plugin_lib_type ${arg_PLUGIN_TARGET} TYPE)
+ if(plugin_lib_type STREQUAL "STATIC_LIBRARY")
__qt_internal_add_static_plugin_init_object_library(
"${arg_PLUGIN_TARGET}" plugin_init_target)
list(APPEND output_targets ${plugin_init_target})
+
+ __qt_internal_propagate_object_library("${arg_PLUGIN_TARGET}" "${plugin_init_target}")
endif()
endif()
@@ -420,9 +591,13 @@ function(qt6_add_qml_module target)
# Defer the write to allow more qml files to be added later by calls to
# qt6_target_qml_sources(). We wrap the deferred call with EVAL CODE
# so that ${target} is evaluated now rather than the end of the scope.
+ # We also delay target finalization until after our deferred write
+ # because the qmldir file must be written before any finalizer
+ # might call qt_import_qml_plugins().
cmake_language(EVAL CODE
- "cmake_language(DEFER CALL _qt_internal_write_deferred_qmldir_file ${target})"
+ "cmake_language(DEFER ID_VAR write_id CALL _qt_internal_write_deferred_qmldir_file ${target})"
)
+ _qt_internal_delay_finalization_until_after(${write_id})
else()
# Can't defer the write, have to do it now
_qt_internal_write_deferred_qmldir_file(${target})
@@ -438,9 +613,29 @@ endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_add_qml_module)
qt6_add_qml_module(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
endfunction()
endif()
+# Make the prefix conform to the following:
+# - Starts with a "/"
+# - Does not end with a "/" unless the prefix is exactly "/"
+function(_qt_internal_canonicalize_resource_path path out_var)
+ if(NOT path)
+ set(path "/")
+ endif()
+ if(NOT path MATCHES "^/")
+ string(PREPEND path "/")
+ endif()
+ if(path MATCHES [[(.+)/$]])
+ set(path "${CMAKE_MATCH_1}")
+ endif()
+ set(${out_var} "${path}" PARENT_SCOPE)
+endfunction()
+
function(_qt_internal_get_escaped_uri uri out_var)
string(REGEX REPLACE "[^A-Za-z0-9]" "_" escaped_uri "${uri}")
set(${out_var} "${escaped_uri}" PARENT_SCOPE)
@@ -465,6 +660,20 @@ macro(_qt_internal_genex_getoption var target property)
set(${var} "$<BOOL:$<TARGET_PROPERTY:${target},${property}>>")
endmacro()
+function(_qt_internal_extend_qml_import_paths import_paths_var)
+ set(local_var ${${import_paths_var}})
+
+ # prepend extra import path which is a current module's build dir: we need
+ # this to ensure correct importing of QML modules when having a prefix-build
+ # with QLibraryInfo::path(QLibraryInfo::QmlImportsPath) pointing to the
+ # install location
+ if(QT_BUILDING_QT AND QT_WILL_INSTALL)
+ list(PREPEND local_var -I "${QT_BUILD_DIR}/${INSTALL_QMLDIR}")
+ endif()
+
+ set(${import_paths_var} ${local_var} PARENT_SCOPE)
+endfunction()
+
function(_qt_internal_target_enable_qmllint target)
set(lint_target ${target}_qmllint)
if(TARGET ${lint_target})
@@ -479,17 +688,47 @@ function(_qt_internal_target_enable_qmllint target)
_qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
)
- # Facilitate self-import so it can find the qmldir file
- list(APPEND import_args -I "${CMAKE_CURRENT_BINARY_DIR}")
+ # Facilitate self-import so it can find the qmldir file. We also try to walk
+ # back up the directory structure to find a base path under which this QML
+ # module is located. Such a base path is likely to be used for other QML
+ # modules that we might need to find, so add it to the import path if we
+ # find a compatible directory structure. It doesn't make sense to do this
+ # for an executable though, since it can never be found as a QML module for
+ # a different QML module/target.
+ get_target_property(target_type ${target} TYPE)
+ get_target_property(is_android_executable ${target} _qt_is_android_executable)
+ if(target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ # The executable's own QML module's qmldir file will usually be under a
+ # subdirectory (matching the module's target path) below the target's
+ # build directory.
+ list(APPEND import_args -I "$<TARGET_PROPERTY:${target},BINARY_DIR>")
+ elseif(target_type MATCHES "LIBRARY")
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ if(output_dir MATCHES "${target_path}$")
+ string(REGEX REPLACE "(.*)/${target_path}" "\\1" base_dir "${output_dir}")
+ list(APPEND import_args -I "${base_dir}")
+ else()
+ message(WARNING
+ "The ${target} target is a QML module with target path ${target_path}. "
+ "It uses an OUTPUT_DIRECTORY of ${output_dir}, which should end in the "
+ "same target path, but doesn't. Tooling such as qmllint may not work "
+ "correctly."
+ )
+ endif()
+ endif()
if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
list(APPEND import_args -I "${QT_QML_OUTPUT_DIRECTORY}")
endif()
+ _qt_internal_extend_qml_import_paths(import_args)
+
set(cmd
${QT_TOOL_COMMAND_WRAPPER_PATH}
${QT_CMAKE_EXPORT_NAMESPACE}::qmllint
${import_args}
+ ${qrc_args}
${qmllint_files}
)
@@ -533,7 +772,7 @@ function(_qt_internal_propagate_qmlcache_object_lib
link_condition
output_generated_target)
set(resource_target "${target}_qmlcache")
- add_library("${resource_target}" OBJECT "${generated_source_code}")
+ qt6_add_library("${resource_target}" OBJECT "${generated_source_code}")
# Needed to trigger the handling of the object library for .prl generation.
set_property(TARGET ${resource_target} APPEND PROPERTY _qt_resource_name ${resource_target})
@@ -600,6 +839,9 @@ function(_qt_internal_target_enable_qmlcachegen target output_targets_var qmlcac
_qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
)
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ set(qmlcachegen "$<COMMAND_CONFIG:${qmlcachegen}>")
+ endif()
set(cmd
${QT_TOOL_COMMAND_WRAPPER_PATH}
${qmlcachegen}
@@ -624,6 +866,21 @@ function(_qt_internal_target_enable_qmlcachegen target output_targets_var qmlcac
$<TARGET_PROPERTY:${target},_qt_generated_qrc_files>
)
+ # The current scope sees the file as generated automatically, but the
+ # target scope may not if it is different. Force it where we can.
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${qmlcache_loader_cpp}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES GENERATED TRUE
+ )
+ endif()
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ add_custom_target(${target}_qmlcachegen DEPENDS ${qmlcache_loader_cpp})
+ add_dependencies(${target} ${target}_qmlcachegen)
+ endif()
+
# TODO: Probably need to reject ${target} being an object library as unsupported
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "STATIC_LIBRARY")
@@ -678,6 +935,8 @@ function(_qt_internal_target_generate_qmldir target)
endif()
set(content "module ${uri}\n")
+ _qt_internal_qmldir_item(linktarget QT_QML_MODULE_INSTALLED_PLUGIN_TARGET)
+
get_target_property(plugin_target ${target} QT_QML_MODULE_PLUGIN_TARGET)
if(plugin_target)
get_target_property(no_plugin_optional ${target} QT_QML_MODULE_NO_PLUGIN_OPTIONAL)
@@ -685,8 +944,13 @@ function(_qt_internal_target_generate_qmldir target)
string(APPEND content "optional ")
endif()
- get_target_property(qt_libinfix ${target} QT_QML_MODULE_LIBINFIX)
- string(APPEND content "plugin ${plugin_target}${qt_libinfix}\n")
+ get_target_property(target_path ${target} QT_QML_MODULE_TARGET_PATH)
+ _qt_internal_get_qml_plugin_output_name(plugin_output_name ${plugin_target}
+ TARGET_PATH "${target_path}"
+ URI "${uri}"
+ )
+ string(APPEND content "plugin ${plugin_output_name}\n")
+
_qt_internal_qmldir_item(classname QT_QML_MODULE_CLASS_NAME)
endif()
@@ -695,7 +959,7 @@ function(_qt_internal_target_generate_qmldir target)
string(APPEND content "designersupported\n")
endif()
- _qt_internal_qmldir_item(typeinfo QT_QMLTYPES_FILENAME)
+ _qt_internal_qmldir_item(typeinfo QT_QML_MODULE_TYPEINFO)
_qt_internal_qmldir_item_list(import QT_QML_MODULE_IMPORTS)
_qt_internal_qmldir_item_list("optional import" QT_QML_MODULE_OPTIONAL_IMPORTS)
@@ -722,61 +986,14 @@ function(_qt_internal_target_generate_qmldir target)
# NOTE: qt6_target_qml_sources() may append further content later.
endfunction()
-# TODO: Need to consider the case where an executable's finalizer might execute
-# before our deferred call. That can occur in the following situations:
-#
-# - The executable target is created in the same scope as the qml module
-# and the executable target is created first.
-# - The qml module is created in a parent scope of the executable.
-#
-# Note that the qml module can safely be created in another scope as long
-# as that scope has been finalized by the time the executable target's
-# finalizer is called. A child scope satisfies this, as does any other
-# scope that has already finished being processed earlier in the CMake run.
function(_qt_internal_write_deferred_qmldir_file target)
get_target_property(__qt_qmldir_content ${target} _qt_internal_qmldir_content)
- get_target_property(out_dir ${target} QT_QML_MODULE_OUTPUT_DIR)
+ get_target_property(out_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
set(qmldir_file "${out_dir}/qmldir")
configure_file(${__qt_qml_macros_module_base_dir}/Qt6qmldirTemplate.cmake.in ${qmldir_file} @ONLY)
endfunction()
-# Create a Qml plugin. Projects should not normally need to call this function
-# directly. Rather, it would normally be called by qt6_add_qml_module() to
-# create or update the plugin associated with its backing target.
-#
-# target: The name of the target to use for the qml plugin. If it does not
-# already exist, it will be created. (REQUIRED)
-#
-# STATIC, SHARED: Explicitly specify the type of plugin library to create.
-# At most one of these two options can be specified. (OPTIONAL)
-#
-# BACKING_TARGET: The backing target that the plugin is associated with. This
-# can be the same as ${target}, in which case there is only the one merged
-# target. If this option is not provided, then URI must be given. (OPTIONAL)
-#
-# URI: Declares the module identifier of the qml module this plugin is
-# associated with. The module identifier is the (dotted URI notation)
-# identifier for the qml module. If URI is not given, then a BACKING_TARGET
-# must be provided and the backing target must have its URI recorded on it
-# (typically by an earlier call to qt6_add_qml_module()). (OPTIONAL)
-#
-# CLASS_NAME: By default, the class name will be taken from the backing target,
-# if provided, or falling back to the URI with "Plugin" appended. Any
-# non-alphanumeric characters in the URI will be replaced with underscores.
-# (OPTIONAL)
-#
-# OUTPUT_DIRECTORY: Specifies the directory where the plugin library will be
-# created. When not given, the output directory will be obtained from the
-# BACKING_TARGET if one has been provided. If an output directory cannot be
-# obtained from there either, the standard default as provided by CMake
-# (${CMAKE_CURRENT_BINARY_DIR}) will be used. (OPTIONAL)
-#
-# NO_GENERATE_PLUGIN_SOURCE: A .cpp file will be created for the plugin class
-# by default and automatically added to the plugin target. Use this option to
-# indicate that no such .cpp file should be generated. The caller is then
-# responsible for providing their own plugin class. (OPTIONAL)
-#
function(qt6_add_qml_plugin target)
set(args_option
STATIC
@@ -844,6 +1061,8 @@ function(qt6_add_qml_plugin target)
endif()
if(TARGET ${target})
+ # Plugin target already exists. Perform a few sanity checks, but we
+ # otherwise trust that the target is appropriate for use as a plugin.
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "EXECUTABLE")
message(FATAL_ERROR "Plugins cannot be executables (target: ${target})")
@@ -857,10 +1076,19 @@ function(qt6_add_qml_plugin target)
endforeach()
get_target_property(existing_class_name ${target} QT_PLUGIN_CLASS_NAME)
- if(existing_class_name AND NOT existing_class_name STREQUAL arg_CLASS_NAME)
+ if(existing_class_name)
+ if(NOT existing_class_name STREQUAL arg_CLASS_NAME)
+ message(FATAL_ERROR
+ "An existing plugin target was given, but it has a different class name "
+ "(${existing_class_name}) to that being used here (${arg_CLASS_NAME})"
+ )
+ endif()
+ elseif(arg_CLASS_NAME)
+ set_property(TARGET ${target} PROPERTY QT_PLUGIN_CLASS_NAME "${arg_CLASS_NAME}")
+ else()
message(FATAL_ERROR
- "An existing target was given, but it has a different class name "
- "(${existing_class_name}) to that being used here (${arg_CLASS_NAME})"
+ "An existing '${target}' plugin target was given, but it has no class name set "
+ "and no new class name was provided."
)
endif()
else()
@@ -876,8 +1104,42 @@ function(qt6_add_qml_plugin target)
set(lib_type SHARED)
endif()
+ if(TARGET "${arg_BACKING_TARGET}")
+ # Ensure that the plugin type we create will be compatible with the
+ # type of backing target we were given
+ get_target_property(backing_type ${arg_BACKING_TARGET} TYPE)
+ if(backing_type STREQUAL "STATIC_LIBRARY")
+ if(lib_type STREQUAL "")
+ set(lib_type STATIC)
+ elseif(lib_type STREQUAL "SHARED")
+ message(FATAL_ERROR
+ "Mixing a static backing library with a non-static plugin "
+ "is not supported"
+ )
+ endif()
+ elseif(backing_type STREQUAL "SHARED_LIBRARY")
+ if(lib_type STREQUAL "")
+ set(lib_type SHARED)
+ elseif(lib_type STREQUAL "STATIC")
+ message(FATAL_ERROR
+ "Mixing a non-static backing library with a static plugin "
+ "is not supported"
+ )
+ endif()
+ elseif(backing_type STREQUAL "EXECUTABLE")
+ message(FATAL_ERROR
+ "A separate plugin should not be needed when the backing target "
+ "is an executable. Pre-create the plugin target before calling "
+ "this command if you really must have a separate plugin."
+ )
+ else()
+ # Object libraries, utility/custom targets
+ message(FATAL_ERROR "Unsupported backing target type: ${backing_type}")
+ endif()
+ endif()
+
qt6_add_plugin(${target} ${lib_type}
- TYPE qml_plugin
+ PLUGIN_TYPE qml_plugin
CLASS_NAME ${arg_CLASS_NAME}
)
endif()
@@ -900,36 +1162,21 @@ function(qt6_add_qml_plugin target)
)
endif()
- if (ANDROID)
- # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls
- # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/").
- # Example plugin names:
- # qtdeclarative
- # TARGET_PATH: QtQml/Models
- # file name: libqml_QtQml_Models_modelsplugin_arm64-v8a.so
- # qtquickcontrols2
- # TARGET_PATH: QtQuick/Controls.2/Material
- # file name:
- # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_arm64-v8a.so
- if(NOT arg_TARGET_PATH AND TARGET "${arg_BACKING_TARGET}")
- get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET} QT_QML_MODULE_TARGET_PATH)
- endif()
- if(arg_TARGET_PATH)
- string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}")
- else()
- string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}")
- endif()
-
- set(final_android_qml_plugin_name "qml_${android_plugin_name_infix_name}_${target}")
+ if(ANDROID)
+ _qt_internal_get_qml_plugin_output_name(plugin_output_name ${target}
+ BACKING_TARGET "${arg_BACKING_TARGET}"
+ TARGET_PATH "${arg_TARGET_PATH}"
+ URI "${arg_URI}"
+ )
set_target_properties(${target}
PROPERTIES
- LIBRARY_OUTPUT_NAME "${final_android_qml_plugin_name}"
+ LIBRARY_OUTPUT_NAME "${plugin_output_name}"
)
qt6_android_apply_arch_suffix(${target})
endif()
if(NOT arg_OUTPUT_DIRECTORY AND arg_BACKING_TARGET AND TARGET ${arg_BACKING_TARGET})
- get_target_property(arg_OUTPUT_DIRECTORY ${arg_BACKING_TARGET} QT_QML_OUTPUT_DIRECTORY)
+ get_target_property(arg_OUTPUT_DIRECTORY ${arg_BACKING_TARGET} QT_QML_MODULE_OUTPUT_DIRECTORY)
endif()
if(arg_OUTPUT_DIRECTORY)
# Plugin target must be in the output directory. The backing target,
@@ -948,7 +1195,7 @@ function(qt6_add_qml_plugin target)
# These are all substituted in the template file used further below
set(qt_qml_plugin_class_name "${arg_CLASS_NAME}")
set(qt_qml_plugin_moc_include_name "${generated_cpp_file_name_base}.moc")
- set(qt_qml_plugin_intro "extern void ${register_types_function_name}();")
+ set(qt_qml_plugin_intro "extern void ${register_types_function_name}();\nQ_GHS_KEEP_REFERENCE(${register_types_function_name});")
set(qt_qml_plugin_outro "")
if(QT_BUILDING_QT)
string(APPEND qt_qml_plugin_intro "\n\nQT_BEGIN_NAMESPACE")
@@ -977,10 +1224,24 @@ function(qt6_add_qml_plugin target)
endif()
target_link_libraries(${target} PRIVATE ${QT_CMAKE_EXPORT_NAMESPACE}::Qml)
- if(NOT "${arg_BACKING_TARGET}" STREQUAL target)
+
+ # Link plugin against its backing lib if it has one.
+ if(NOT arg_BACKING_TARGET STREQUAL "" AND NOT arg_BACKING_TARGET STREQUAL target)
target_link_libraries(${target} PRIVATE ${arg_BACKING_TARGET})
endif()
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
+ # Defer the collection of plugin dependencies until after any extra target_link_libraries
+ # calls that a user project might do.
+ # We wrap the deferred call with EVAL CODE
+ # so that ${target} is evaluated now rather than the end of the scope.
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER CALL _qt_internal_add_static_qml_plugin_dependencies \"${target}\" \"${arg_BACKING_TARGET}\")"
+ )
+ else()
+ # Can't defer, have to do it now.
+ _qt_internal_add_static_qml_plugin_dependencies("${target}" "${arg_BACKING_TARGET}")
+ endif()
endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
@@ -989,78 +1250,15 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endfunction()
endif()
-# Add Qml files (.qml,.js,.mjs) to a Qml module.
-#
-# target: The backing target of the qml module. (REQUIRED)
-#
-# QML_FILES: The qml files to add to the backing target. Supported file extensions
-# are .qml, .js and .mjs. No other file types should be listed. (REQUIRED)
-#
-# RESOURCES: Resources used in QML, for example images. (OPTIONAL)
-#
-# PREFIX: The resource path under which to add the compiled qml files. If not
-# specified, the QT_QML_MODULE_RESOURCE_PREFIX property of the target is used
-# as the default, if set (that property is set by qt6_add_qml_module()).
-# If the default is empty, this option must be provided. (OPTIONAL)
-#
-# OUTPUT_TARGETS: In static builds, additional CMake targets can be created
-# which consumers of the module will need to potentially install.
-# Supply the name of an output variable, which will be set to a list of these
-# targets. If installing the main target, you will also need to install these
-# output targets for static builds. (OPTIONAL)
-#
-# NO_LINT: Do not add the specified files to the ${target}_qmllint target.
-# If this option is not given, the default will be taken from the target.
-#
-# NO_CACHEGEN: Do not compile the qml files. Add the raw qml files to the
-# target resources instead. If this option is not given, the default will be
-# taken from the target.
-#
-# NO_QMLDIR_TYPES: Do not append type information from the qml files to the
-# qmldir file associated with the qml module. If this option is not given,
-# the default will be taken from the target.
-#
-# In addition to the above NO_... options, individual files can be explicitly
-# skipped by setting the relevant source property. These are:
-#
-# - QT_QML_SKIP_QMLLINT
-# - QT_QML_SKIP_QMLDIR_ENTRY
-# - QT_QML_SKIP_CACHEGEN
-#
-# Disabling the qmldir entry for a qml file would normally only be used for a
-# file that does not expose a public type (e.g. a private JS file).
-# If appending of type information has not been disabled for a particular qml
-# file, the following additional source properties can be specified to
-# customize the file's type details:
-#
-# QT_QML_SOURCE_VERSION: Version(s) for this qml file. If not present the module
-# version will be used.
-#
-# QT_QML_SOURCE_TYPENAME: Override the file's type name. If not present, the
-# type name will be deduced using the file's basename.
-#
-# QT_QML_SINGLETON_TYPE: Set to true if this qml file contains a singleton type.
-#
-# QT_QML_INTERNAL_TYPE: When set to true, the type specified by
-# QT_QML_SOURCE_TYPENAME will not be available to users of this module.
-#
-# e.g.:
-# set_source_files_properties(my_qml_file.qml
-# PROPERTIES
-# QT_QML_SOURCE_VERSION "2.0;6.0"
-# QT_QML_SOURCE_TYPENAME MyQmlFile
-#
-# qt6_target_qml_sources(my_qml_module
-# QML_FILES
-# my_qml_file.qml
-# )
-#
-# The above will produce the following entry in the qmldir file:
-#
-# MyQmlFile 2.0 my_qml_file.qml
-#
+
function(qt6_target_qml_sources target)
+ get_target_property(uri ${target} QT_QML_MODULE_URI)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(NOT uri OR NOT output_dir)
+ message(FATAL_ERROR "Target ${target} is not a QML module")
+ endif()
+
set(args_option
NO_LINT
NO_CACHEGEN
@@ -1085,17 +1283,20 @@ function(qt6_target_qml_sources target)
message(FATAL_ERROR "Unknown/unexpected arguments: ${arg_UNPARSED_ARGUMENTS}")
endif()
- if (NOT arg_QML_FILES)
+ if (NOT arg_QML_FILES AND NOT arg_RESOURCES)
if(arg_OUTPUT_TARGETS)
set(${arg_OUTPUT_TARGETS} "" PARENT_SCOPE)
endif()
return()
endif()
- if(arg___QT_INTERNAL_FORCE_DEFER_QMLDIR OR ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.19.0")
- set(can_defer_qmldir TRUE)
- else()
- set(can_defer_qmldir FALSE)
+ if(NOT arg___QT_INTERNAL_FORCE_DEFER_QMLDIR AND ${CMAKE_VERSION} VERSION_LESS "3.19.0")
+ message(FATAL_ERROR
+ "You are using CMake ${CMAKE_VERSION}, but CMake 3.19 or later "
+ "is required to add qml files with this function. Either pass "
+ "the qml files to qt6_add_qml_module() instead or update to "
+ "CMake 3.19 or later."
+ )
endif()
get_target_property(no_lint ${target} QT_QML_MODULE_NO_LINT)
@@ -1103,7 +1304,7 @@ function(qt6_target_qml_sources target)
get_target_property(no_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR)
get_target_property(resource_prefix ${target} QT_QML_MODULE_RESOURCE_PREFIX)
get_target_property(qml_module_version ${target} QT_QML_MODULE_VERSION)
- get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIR)
+ get_target_property(past_major_versions ${target} QT_QML_MODULE_PAST_MAJOR_VERSIONS)
if(NOT output_dir)
# Probably not a qml module. We still want to support tooling for this
@@ -1123,10 +1324,24 @@ function(qt6_target_qml_sources target)
)
endif()
endif()
- if(NOT arg_PREFIX MATCHES [[/$]])
+ _qt_internal_canonicalize_resource_path("${arg_PREFIX}" arg_PREFIX)
+ if(NOT arg_PREFIX STREQUAL "/")
string(APPEND arg_PREFIX "/")
endif()
+ if (qml_module_version MATCHES "^([0-9]+)\\.")
+ set(qml_module_files_versions "${CMAKE_MATCH_1}.0")
+ else()
+ message(FATAL_ERROR
+ "No major version found in '${qml_module_version}'."
+ )
+ endif()
+ if (past_major_versions OR past_major_versions STREQUAL "0")
+ foreach (past_major_version ${past_major_versions})
+ list(APPEND qml_module_files_versions "${past_major_version}.0")
+ endforeach()
+ endif()
+
# Linting and cachegen can still occur for a target that isn't a qml module,
# but for such targets, there is no qmldir file to update.
if(arg_NO_LINT)
@@ -1139,7 +1354,7 @@ function(qt6_target_qml_sources target)
set(no_qmldir TRUE)
endif()
- if(NOT no_cachegen)
+ if(NOT no_cachegen AND arg_QML_FILES)
_qt_internal_genex_getproperty(types_file ${target} QT_QML_MODULE_PLUGIN_TYPES_FILE)
_qt_internal_genex_getproperty(qmlcachegen ${target} QT_QMLCACHEGEN_BINARY)
_qt_internal_genex_getproperty(direct_calls ${target} QT_QMLCACHEGEN_DIRECT_CALLS)
@@ -1152,8 +1367,15 @@ function(qt6_target_qml_sources target)
_qt_internal_genex_getjoinedproperty(qrc_resource_args ${target}
_qt_generated_qrc_files "--resource$<SEMICOLON>" "$<SEMICOLON>"
)
+ get_target_property(target_type ${target} TYPE)
+ get_target_property(is_android_executable ${target} _qt_is_android_executable)
+ if(target_type STREQUAL "EXECUTABLE" OR is_android_executable)
+ # The application binary directory is part of the default import path.
+ list(APPEND import_paths -I "$<TARGET_PROPERTY:${target},BINARY_DIR>")
+ endif()
+ _qt_internal_extend_qml_import_paths(import_paths)
set(cachegen_args
- "$<${have_import_paths}:${import_paths}>"
+ ${import_paths}
"$<${have_types_file}:-i$<SEMICOLON>${types_file}>"
"$<${have_direct_calls}:--direct-calls>"
"$<${have_arguments}:${arguments}>"
@@ -1183,6 +1405,7 @@ function(qt6_target_qml_sources target)
set(non_qml_files)
set(output_targets)
+ set(copied_files)
foreach(file_src IN LISTS arg_QML_FILES arg_RESOURCES)
# We need to copy the file to the build directory now so that when
@@ -1212,12 +1435,14 @@ function(qt6_target_qml_sources target)
add_custom_command(OUTPUT ${file_out}
COMMAND ${CMAKE_COMMAND} -E copy ${file_src} ${file_out}
- DEPENDS ${file_src}
+ DEPENDS ${file_absolute}
WORKING_DIRECTORY $<TARGET_PROPERTY:${target},SOURCE_DIR>
)
+ list(APPEND copied_files ${file_out})
endif()
endforeach()
+ set(generated_sources_other_scope)
foreach(qml_file_src IN LISTS arg_QML_FILES)
# This is to facilitate updating code that used the earlier tech preview
# API function qt6_target_qml_files()
@@ -1226,9 +1451,13 @@ function(qt6_target_qml_sources target)
continue()
endif()
+ # Mark QML files as source files, so that they do not appear in <Other Locations> in Creator
+ # or other IDEs
+ set_source_files_properties(${qml_file_src} HEADER_FILE_ONLY ON)
+ target_sources(${target} PRIVATE ${qml_file_src})
+
get_filename_component(file_absolute ${qml_file_src} ABSOLUTE)
__qt_get_relative_resource_path_for_file(file_resource_path ${qml_file_src})
- set(qml_file_out ${output_dir}/${file_resource_path})
# For the tooling steps below, run the tools on the copied qml file in
# the build directory, not the source directory. This is required
@@ -1238,17 +1467,13 @@ function(qt6_target_qml_sources target)
# resource paths and the source locations might be structured quite
# differently.
- # Fed to qmlimportscanner in qt6_import_qml_plugins. Also may be used in
- # generator expressions to install all qml files for the target.
- set_property(TARGET ${target} APPEND PROPERTY QT_QML_MODULE_FILES ${qml_file_out})
-
# Add file to those processed by qmllint
get_source_file_property(skip_qmllint ${qml_file_src} QT_QML_SKIP_QMLLINT)
if(NOT no_lint AND NOT skip_qmllint)
# The set of qml files to run qmllint on may be a subset of the
# full set of files, so record these in a separate property.
_qt_internal_target_enable_qmllint(${target})
- set_property(TARGET ${target} APPEND PROPERTY QT_QML_LINT_FILES ${qml_file_src})
+ set_property(TARGET ${target} APPEND PROPERTY QT_QML_LINT_FILES ${file_absolute})
endif()
# Add qml file's type to qmldir
@@ -1256,27 +1481,45 @@ function(qt6_target_qml_sources target)
if(NOT no_qmldir AND NOT skip_qmldir)
get_source_file_property(qml_file_typename ${qml_file_src} QT_QML_SOURCE_TYPENAME)
if (NOT qml_file_typename)
- get_filename_component(qml_file_typename ${qml_file_src} NAME_WLE)
+ get_filename_component(qml_file_ext ${qml_file_src} EXT)
+ get_filename_component(qml_file_typename ${qml_file_src} NAME_WE)
endif()
# Do not add qmldir entries for lowercase names. Those are not components.
- if (qml_file_typename MATCHES "^[A-Z]")
- if(NOT can_defer_qmldir)
- message(FATAL_ERROR
- "You are using CMake ${CMAKE_VERSION}, but CMake 3.19 or later "
- "is required to add qml files with this function. Either pass "
- "the qml files to qt6_add_qml_module() instead or update to "
- "CMake 3.19 or later."
+ if (qml_file_typename AND qml_file_typename MATCHES "^[A-Z]")
+ if (qml_file_ext AND NOT qml_file_ext STREQUAL ".qml" AND NOT qml_file_ext STREQUAL ".ui.qml"
+ AND NOT qml_file_ext STREQUAL ".js" AND NOT qml_file_ext STREQUAL ".mjs")
+ message(AUTHOR_WARNING
+ "${qml_file_src} has a file extension different from .qml, .ui.qml, .js, "
+ "and .mjs. This leads to unexpected component names."
+ )
+ endif()
+
+ # We previously accepted the singular form of this property name
+ # during tech preview. Issue a warning for that, but still
+ # honor it. The plural form will override it if both are set.
+ get_property(have_singular_property SOURCE ${qml_file_src}
+ PROPERTY QT_QML_SOURCE_VERSION SET
+ )
+ if(have_singular_property)
+ message(AUTHOR_WARNING
+ "The QT_QML_SOURCE_VERSION source file property has been replaced "
+ "by QT_QML_SOURCE_VERSIONS (i.e. plural rather than singular). "
+ "The singular form will eventually be removed, please update "
+ "the project to use the plural form instead for the file at:\n"
+ " ${qml_file_src}"
)
endif()
+ get_source_file_property(qml_file_versions ${qml_file_src} QT_QML_SOURCE_VERSIONS)
+ if(NOT qml_file_versions AND have_singular_property)
+ get_source_file_property(qml_file_versions ${qml_file_src} QT_QML_SOURCE_VERSION)
+ endif()
- # TODO: rename to QT_QML_SOURCE_VERSIONS
- get_source_file_property(qml_file_versions ${qml_file_src} QT_QML_SOURCE_VERSION)
get_source_file_property(qml_file_singleton ${qml_file_src} QT_QML_SINGLETON_TYPE)
get_source_file_property(qml_file_internal ${qml_file_src} QT_QML_INTERNAL_TYPE)
if (NOT qml_file_versions)
- set(qml_file_versions ${qml_module_version})
+ set(qml_file_versions ${qml_module_files_versions})
endif()
set(qmldir_file_contents "")
@@ -1325,34 +1568,57 @@ function(qt6_target_qml_sources target)
"${CMAKE_CURRENT_BINARY_DIR}/.rcc/qmlcache/${target}_${compiled_file}.cpp")
get_filename_component(out_dir ${compiled_file} DIRECTORY)
+ if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config" AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.20")
+ set(qmlcachegen_cmd "$<COMMAND_CONFIG:${qmlcachegen}>")
+ else()
+ set(qmlcachegen_cmd "${qmlcachegen}")
+ endif()
add_custom_command(
OUTPUT ${compiled_file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${out_dir}
COMMAND
${QT_TOOL_COMMAND_WRAPPER_PATH}
- ${qmlcachegen}
+ ${qmlcachegen_cmd}
--resource-path "${file_resource_path}"
${cachegen_args}
-o "${compiled_file}"
"${file_absolute}"
COMMAND_EXPAND_LISTS
DEPENDS
- ${qmlcachegen}
+ ${qmlcachegen_cmd}
"${file_absolute}"
$<TARGET_PROPERTY:${target},_qt_generated_qrc_files>
"$<$<BOOL:${types_file}>:${types_file}>"
)
- target_sources(${target} PRIVATE
- ${compiled_file}
- ${qml_file_src} # Make the original qml file show up under this target in the IDE
- )
+ target_sources(${target} PRIVATE ${compiled_file})
set_source_files_properties(${compiled_file} PROPERTIES
SKIP_AUTOGEN ON
)
+ # The current scope automatically sees the file as generated, but the
+ # target scope may not if it is different. Force it where we can.
+ # We will also have to add the generated file to a target in this
+ # scope at the end to ensure correct dependencies.
+ get_target_property(target_source_dir ${target} SOURCE_DIR)
+ if(NOT target_source_dir STREQUAL CMAKE_CURRENT_SOURCE_DIR)
+ list(APPEND generated_sources_other_scope ${compiled_file})
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${compiled_file}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ )
+ endif()
+ endif()
endif()
endforeach()
+ if(ANDROID)
+ _qt_internal_collect_qml_root_paths("${target}" ${arg_QML_FILES})
+ endif()
+
if(non_qml_files)
list(JOIN non_qml_files "\n " file_list)
message(WARNING
@@ -1362,6 +1628,36 @@ function(qt6_target_qml_sources target)
)
endif()
+ if(copied_files OR generated_sources_other_scope)
+ if(CMAKE_VERSION VERSION_LESS 3.19)
+ # Called from qt6_add_qml_module() and we know there can only be
+ # this one call. With those constraints, we can use a custom target
+ # to implement the necessary dependencies to get files copied to the
+ # build directory when their source files change.
+ add_custom_target(${target}_tooling ALL
+ DEPENDS
+ ${copied_files}
+ ${generated_sources_other_scope}
+ )
+ add_dependencies(${target} ${target}_tooling)
+ else()
+ # We could be called multiple times and a custom target can only
+ # have file-level dependencies added at the time the target is
+ # created. Use an interface library instead, since we can add
+ # private sources to those and have the library act as a build
+ # system target from CMake 3.19 onward, and we can add the sources
+ # progressively over multiple calls.
+ if(NOT TARGET ${target}_tooling)
+ add_library(${target}_tooling INTERFACE)
+ add_dependencies(${target} ${target}_tooling)
+ endif()
+ target_sources(${target}_tooling PRIVATE
+ ${copied_files}
+ ${generated_sources_other_scope}
+ )
+ endif()
+ endif()
+
# Batch all the non-compiled qml sources into a single resource for this
# call. Subsequent calls for the same target will be in their own separate
# resource file.
@@ -1380,7 +1676,7 @@ function(qt6_target_qml_sources target)
set_target_properties(${target} PROPERTIES QT_QML_MODULE_RAW_QML_SETS ${counter})
list(APPEND output_targets ${resource_targets})
- if(arg_OUTPUT_TARGETS AND output_targets)
+ if(arg_OUTPUT_TARGETS)
set(${arg_OUTPUT_TARGETS} ${output_targets} PARENT_SCOPE)
endif()
@@ -1389,13 +1685,13 @@ endfunction()
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_target_qml_sources)
qt6_target_qml_sources(${ARGV})
+ cmake_parse_arguments(PARSE_ARGV 1 arg "" "OUTPUT_TARGETS" "")
+ if(arg_OUTPUT_TARGETS)
+ set(${arg_OUTPUT_TARGETS} ${${arg_OUTPUT_TARGETS}} PARENT_SCOPE)
+ endif()
endfunction()
endif()
-# NOTE: This function does not normally need to be called directly by projects.
-# It is called automatically by qt6_add_qml_module() unless
-# NO_GENERATE_QMLTYPES is also given to that function.
-#
# target: Expected to be the backing target for a qml module. Certain target
# properties normally set by qt6_add_qml_module() will be retrieved from this
# target. (REQUIRED)
@@ -1403,8 +1699,8 @@ endif()
# MANUAL_MOC_JSON_FILES: Specifies a list of json files, generated by a manual
# moc call, to extract metatypes. (OPTIONAL)
#
-function(qt6_qml_type_registration target)
- set(args_option "")
+function(_qt_internal_qml_type_registration target)
+ set(args_option __QT_INTERNAL_INSTALL_METATYPES_JSON)
set(args_single "")
set(args_multi MANUAL_MOC_JSON_FILES)
@@ -1419,7 +1715,7 @@ function(qt6_qml_type_registration target)
if (NOT import_name)
message(FATAL_ERROR "Target ${target} is not a QML module")
endif()
- get_target_property(qmltypes_output_name ${target} QT_QMLTYPES_FILENAME)
+ get_target_property(qmltypes_output_name ${target} QT_QML_MODULE_TYPEINFO)
if (NOT qmltypes_output_name)
get_target_property(compile_definitions_list ${target} COMPILE_DEFINITIONS)
list(FIND compile_definitions_list QT_PLUGIN is_a_plugin)
@@ -1430,25 +1726,20 @@ function(qt6_qml_type_registration target)
endif()
endif()
- # Horrible hack workaround to not install metatypes.json files for examples/ qml plugins into
- # ${qt_prefix}/lib/meta_types.
- # Put them into QT_QML_MODULE_INSTALL_DIR/lib/meta_types instead.
- get_target_property(qml_install_dir ${target} QT_QML_MODULE_INSTALL_DIR)
set(meta_types_json_args "")
-
- # TODO: This is internal Qt logic, it should be moved out of here.
- if(QT_BUILDING_QT AND QT_WILL_INSTALL AND qml_install_dir AND
- qml_install_dir MATCHES "^${INSTALL_EXAMPLESDIR}")
- set(meta_types_json_args "INSTALL_DIR" "${qml_install_dir}/lib/metatypes")
- endif()
-
if(arg_MANUAL_MOC_JSON_FILES)
list(APPEND meta_types_json_args "MANUAL_MOC_JSON_FILES" ${arg_MANUAL_MOC_JSON_FILES})
endif()
+
+ # Don't install the metatypes json files by default for user project created qml modules.
+ # Only install them for Qt provided qml modules.
+ if(NOT arg___QT_INTERNAL_INSTALL_METATYPES_JSON)
+ list(APPEND meta_types_json_args __QT_INTERNAL_NO_INSTALL)
+ endif()
qt6_extract_metatypes(${target} ${meta_types_json_args})
get_target_property(import_version ${target} QT_QML_MODULE_VERSION)
- get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIR)
+ get_target_property(output_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
get_target_property(target_source_dir ${target} SOURCE_DIR)
get_target_property(target_binary_dir ${target} BINARY_DIR)
get_target_property(target_metatypes_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
@@ -1489,7 +1780,7 @@ function(qt6_qml_type_registration target)
)
# Add past minor versions
- get_target_property(past_major_versions ${target} QT_QML_PAST_MAJOR_VERSIONS)
+ get_target_property(past_major_versions ${target} QT_QML_MODULE_PAST_MAJOR_VERSIONS)
if (past_major_versions OR past_major_versions STREQUAL "0")
foreach (past_major_version ${past_major_versions})
@@ -1519,6 +1810,11 @@ function(qt6_qml_type_registration target)
if (TARGET ${target}Private)
list(APPEND cmd_args --private-includes)
+ else()
+ string(REGEX MATCH "Private$" privateSuffix ${target})
+ if (privateSuffix)
+ list(APPEND cmd_args --private-includes)
+ endif()
endif()
get_target_property(target_metatypes_json_file ${target} INTERFACE_QT_META_TYPES_BUILD_FILE)
@@ -1591,6 +1887,19 @@ function(qt6_qml_type_registration target)
endif()
add_dependencies(all_qmltyperegistrations ${target}_qmltyperegistration)
+ # Both ${target} (via target_sources) and ${target}_qmltyperegistration (via add_custom_target
+ # DEPENDS option) depend on ${type_registration_cpp_file}.
+ # The new Xcode build system requires a common target to drive the generation of files,
+ # otherwise project configuration fails.
+ # Make ${target} the common target, by adding it as a dependency for
+ # ${target}_qmltyperegistration.
+ # The consequence is that the ${target}_qmllint target will now first build ${target} when using
+ # the Xcode generator (mostly only relevant for projects using Qt for iOS).
+ # See QTBUG-95763.
+ if(CMAKE_GENERATOR STREQUAL "Xcode")
+ add_dependencies(${target}_qmltyperegistration ${target})
+ endif()
+
target_sources(${target} PRIVATE ${type_registration_cpp_file})
# FIXME: The generated .cpp file has usually lost the path information for
@@ -1614,15 +1923,35 @@ function(qt6_qml_type_registration target)
SKIP_AUTOGEN ON
${additional_source_files_properties}
)
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set_source_files_properties(
+ ${type_registration_cpp_file}
+ TARGET_DIRECTORY ${target}
+ PROPERTIES
+ SKIP_AUTOGEN TRUE
+ GENERATED TRUE
+ ${additional_source_files_properties}
+ )
+ endif()
target_include_directories(${target} PRIVATE
$<TARGET_PROPERTY:${QT_CMAKE_EXPORT_NAMESPACE}::QmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
)
endfunction()
+function(qt6_qml_type_registration)
+ message(FATAL_ERROR
+ "This function, previously available under Technical Preview, has been removed. "
+ "Please use qt6_add_qml_module() instead."
+ )
+endfunction()
+
if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_qml_type_registration)
- qt6_qml_type_registration(${ARGV})
+ message(FATAL_ERROR
+ "This function, previously available under Technical Preview, has been removed. "
+ "Please use qt_add_qml_module() instead."
+ )
endfunction()
endif()
@@ -1643,7 +1972,7 @@ function(qt6_import_qml_plugins target)
set_target_properties(${target} PROPERTIES _QT_QML_PLUGINS_IMPORTED TRUE)
set(options)
- set(oneValueArgs "PATH_TO_SCAN")
+ set(oneValueArgs "PATH_TO_SCAN") # Internal option, may be removed
set(multiValueArgs)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@@ -1676,10 +2005,24 @@ but this file does not exist. Possible reasons include:
")
endif()
- # Find location of qml dir.
- # TODO: qt.prf implies that there might be more than one qml import path to
- # pass to qmlimportscanner.
- set(qml_path "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}")
+ # Find Qt provided QML import paths.
+ if("${_qt_additional_packages_prefix_paths}" STREQUAL "")
+ # We have one installation prefix for all Qt modules. Add the "<prefix>/qml" directory.
+ set(qml_import_paths "${QT6_INSTALL_PREFIX}/${QT6_INSTALL_QML}")
+ else()
+ # We have multiple installation prefixes: one per Qt repository (conan). Add those that have
+ # a "qml" subdirectory.
+ set(qml_import_paths)
+ __qt_internal_prefix_paths_to_roots(
+ additional_root_paths "${_qt_additional_packages_prefix_paths}")
+ foreach(root IN ITEMS ${QT6_INSTALL_PREFIX} ${additional_root_paths})
+ set(candidate "${root}/${QT6_INSTALL_QML}")
+ if(IS_DIRECTORY "${candidate}")
+ list(APPEND qml_import_paths "${candidate}")
+ endif()
+ endforeach()
+ endif()
+
# Small macro to avoid duplicating code in two different loops.
macro(_qt6_QmlImportScanner_parse_entry)
@@ -1688,7 +2031,8 @@ but this file does not exist. Possible reasons include:
set(entry_name "qml_import_scanner_import_${idx}")
cmake_parse_arguments("entry"
""
- "CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;" ""
+ "CLASSNAME;NAME;PATH;PLUGIN;RELATIVEPATH;TYPE;VERSION;LINKTARGET"
+ ""
${${entry_name}}
)
endmacro()
@@ -1700,28 +2044,41 @@ but this file does not exist. Possible reasons include:
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.qt_plugins)
set(cmd_args
- "${arg_PATH_TO_SCAN}"
+ -rootPath "${arg_PATH_TO_SCAN}"
-cmake-output
- -importPath "${qml_path}"
)
get_target_property(qml_import_path ${target} QT_QML_IMPORT_PATH)
-
- if (qml_import_path)
- list(APPEND cmd_args ${qml_import_path})
+ if(qml_import_path)
+ list(APPEND qml_import_paths ${qml_import_path})
endif()
# Facilitate self-import so we can find the qmldir file
- list(APPEND cmd_args "${CMAKE_CURRENT_BINARY_DIR}")
-
- if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "" AND EXISTS "${QT_QML_OUTPUT_DIRECTORY}")
- list(APPEND cmd_args "${QT_QML_OUTPUT_DIRECTORY}")
+ get_target_property(module_out_dir ${target} QT_QML_MODULE_OUTPUT_DIRECTORY)
+ if(module_out_dir)
+ list(APPEND qml_import_paths "${module_out_dir}")
endif()
- get_target_property(qml_files ${target} QT_QML_MODULE_FILES)
- if (qml_files)
- list(APPEND cmd_args "-qmlFiles" ${qml_files})
+ # Find qmldir files we copied to the build directory
+ if(NOT "${QT_QML_OUTPUT_DIRECTORY}" STREQUAL "")
+ if(EXISTS "${QT_QML_OUTPUT_DIRECTORY}")
+ list(APPEND qml_import_paths "${QT_QML_OUTPUT_DIRECTORY}")
+ endif()
+ else()
+ list(APPEND qml_import_paths "${CMAKE_CURRENT_BINARY_DIR}")
endif()
+ # Construct the -importPath arguments.
+ set(import_path_arguments)
+ foreach(path IN LISTS qml_import_paths)
+ list(APPEND import_path_arguments -importPath ${path})
+ endforeach()
+
+ list(APPEND cmd_args ${import_path_arguments})
+
+ # All of the module's .qml files will be listed in one of the generated
+ # .qrc files, so there's no need to list the files individually. We provide
+ # the .qrc files instead because they have the additional information for
+ # each file's resource alias.
get_target_property(qrc_files ${target} _qt_generated_qrc_files)
if (qrc_files)
list(APPEND cmd_args "-qrcFiles" ${qrc_files})
@@ -1779,28 +2136,20 @@ but this file does not exist. Possible reasons include:
# (typically brought in via find_package(Qt6...) ).
# For other plugins, the targets can come from the project itself.
#
- # Handles Qt provided Qml plugins
- if(TARGET "${QT_CMAKE_EXPORT_NAMESPACE}::${entry_PLUGIN}")
- set(plugin_target "${QT_CMAKE_EXPORT_NAMESPACE}::${entry_PLUGIN}")
- list(APPEND plugins_to_link "${plugin_target}")
-
- __qt_internal_get_static_plugin_init_target_name("${entry_PLUGIN}"
- plugin_init_target)
- set(plugin_init_target_prefixed
- "${QT_CMAKE_EXPORT_NAMESPACE}::${plugin_init_target}")
- list(APPEND plugin_inits_to_link "${plugin_init_target_prefixed}")
-
- # Handles user project provided Qml plugins
- elseif(TARGET ${entry_PLUGIN} AND TARGET ${entry_PLUGIN}_init)
- set(plugin_target "${entry_PLUGIN}")
- list(APPEND plugins_to_link "${plugin_target}")
-
- __qt_internal_get_static_plugin_init_target_name("${entry_PLUGIN}"
- plugin_init_target)
- list(APPEND plugin_inits_to_link "${plugin_init_target}")
-
- # TODO: QTBUG-94605 Figure out if this is a reasonable scenario to support
+ if(entry_LINKTARGET)
+ if(TARGET ${entry_LINKTARGET})
+ list(APPEND plugins_to_link "${entry_LINKTARGET}")
+ else()
+ message(WARNING
+ "The qml plugin '${entry_PLUGIN}' is a dependency of '${target}', "
+ "but the link target it defines (${entry_LINKTARGET}) does not exist "
+ "in the current scope. The plugin will not be linked."
+ )
+ endif()
+ elseif(TARGET ${entry_PLUGIN})
+ list(APPEND plugins_to_link "${entry_PLUGIN}")
else()
+ # TODO: QTBUG-94605 Figure out if this is a reasonable scenario to support
message(WARNING
"The qml plugin '${entry_PLUGIN}' is a dependency of '${target}', "
"but there is no target by that name in the current scope. The plugin will "
@@ -1811,27 +2160,18 @@ but this file does not exist. Possible reasons include:
endforeach()
if(plugins_to_link)
- # __qt_internal_propagate_object_library propagates object libraries by setting
- # INTERFACE linkage on ${target}. If ${target} is an executable, that would mean none
- # of the plugin init libraries would be linked to the executable itself. If ${target} is
- # a user shared library, it would be similar to the case above, the plugin init
- # libraries should be linked into the shared library, rather than to the consumer of the
- # shared library.
- # To achieve proper linkage in these cases, link the plugins and initializers directly.
- # For static libraries and INTERFACE libraries,
- # using __qt_internal_propagate_object_library is intended.
+ # If ${target} is an executable or a shared library, link the plugins directly to
+ # the target.
+ # If ${target} is a static or INTERFACE library, the plugins should be propagated
+ # across those libraries to the end target (executable or shared library).
+ # The plugin initializers will be linked via usage requirements from the plugin target.
get_target_property(target_type ${target} TYPE)
if(target_type STREQUAL "EXECUTABLE" OR target_type STREQUAL "SHARED_LIBRARY")
- # This links both the initializer object and the usage requirements of the object
- # library, so Qt::Core.
- target_link_libraries("${target}" PRIVATE ${plugin_inits_to_link})
- target_link_libraries("${target}" PRIVATE ${plugins_to_link})
+ set(link_type "PRIVATE")
else()
- foreach(plugin_init IN LISTS plugin_inits_to_link)
- __qt_internal_propagate_object_library("${target}" "${plugin_init}")
- endforeach()
- target_link_libraries("${target}" INTERFACE ${plugins_to_link})
+ set(link_type "INTERFACE")
endif()
+ target_link_libraries("${target}" ${link_type} ${plugins_to_link})
endif()
endif()
endfunction()
@@ -1845,3 +2185,188 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endif()
endfunction()
endif()
+
+function(_qt_internal_add_static_qml_plugin_dependencies plugin_target backing_target)
+ # Protect against multiple calls of qt_add_qml_plugin.
+ get_target_property(plugin_deps_added "${plugin_target}" _qt_extra_static_qml_plugin_deps_added)
+ if(plugin_deps_added)
+ return()
+ endif()
+ set_target_properties("${plugin_target}" PROPERTIES _qt_extra_static_qml_plugin_deps_added TRUE)
+
+ # Get the install plugin target name, which we will need for filtering later on.
+ if(TARGET "${backing_target}")
+ get_target_property(installed_plugin_target
+ "${backing_target}" _qt_qml_module_installed_plugin_target)
+ endif()
+
+ if(NOT backing_target STREQUAL plugin_target AND TARGET "${backing_target}")
+ set(has_backing_lib TRUE)
+ else()
+ set(has_backing_lib FALSE)
+ endif()
+
+ get_target_property(plugin_type ${plugin_target} TYPE)
+ set(skip_prl_marker "$<BOOL:QT_IS_PLUGIN_GENEX>")
+
+ # If ${plugin_target} is a static qml plugin, recursively get its private dependencies (and its
+ # backing lib private deps), identify which of those are qml modules, extract any associated qml
+ # plugin target from those qml modules and make them dependencies of ${plugin_target}.
+ #
+ # E.g. this ensures that if a user project links directly to the static qtquick2plugin plugin
+ # target (note the plugin target, not the backing lib) it will automatically also link to
+ # Quick's transitive plugin dependencies: qmlplugin, modelsplugin and workerscriptplugin, in
+ # addition to the the Qml, QmlModels and QmlWorkerScript backing libraries.
+ #
+ # Note this logic is not specific to qtquick2plugin, it applies to all static qml plugins.
+ #
+ # This eliminates the needed boilerplate to link to the full transitive closure of qml plugins
+ # in user projects that don't want to use qmlimportscanner / qt_import_qml_plugins.
+ set(additional_plugin_deps "")
+
+ if(plugin_type STREQUAL "STATIC_LIBRARY")
+ set(all_private_deps "")
+
+ # We walk both plugin_target and backing_lib private deps because they can have differing
+ # dependencies and we want to consider all of them.
+ __qt_internal_collect_all_target_dependencies(
+ "${plugin_target}" plugin_private_deps)
+ if(plugin_private_deps)
+ list(APPEND all_private_deps ${plugin_private_deps})
+ endif()
+
+ if(has_backing_lib)
+ __qt_internal_collect_all_target_dependencies(
+ "${backing_target}" backing_lib_private_deps)
+ if(backing_lib_private_deps)
+ list(APPEND all_private_deps ${backing_lib_private_deps})
+ endif()
+ endif()
+
+ foreach(dep IN LISTS all_private_deps)
+ if(NOT TARGET "${dep}")
+ continue()
+ endif()
+ get_target_property(dep_type ${dep} TYPE)
+ if(dep_type STREQUAL "STATIC_LIBRARY")
+ set(associated_qml_plugin "")
+
+ # Check if the target has an associated imported qml plugin (like a Qt-provided
+ # one).
+ get_target_property(associated_qml_plugin_candidate ${dep}
+ _qt_qml_module_installed_plugin_target)
+
+ if(associated_qml_plugin_candidate AND TARGET "${associated_qml_plugin_candidate}")
+ set(associated_qml_plugin "${associated_qml_plugin_candidate}")
+ endif()
+
+ # Check if the target has an associated qml plugin that's built as part of the
+ # current project (non-installed one, so without a target namespace prefix).
+ get_target_property(associated_qml_plugin_candidate ${dep}
+ _qt_qml_module_plugin_target)
+
+ if(NOT associated_qml_plugin AND
+ associated_qml_plugin_candidate
+ AND TARGET "${associated_qml_plugin_candidate}")
+ set(associated_qml_plugin "${associated_qml_plugin_candidate}")
+ endif()
+
+ # We need to filter out adding the plugin_target as a dependency to itself,
+ # when walking the backing lib of the plugin_target.
+ if(associated_qml_plugin
+ AND NOT associated_qml_plugin STREQUAL plugin_target
+ AND NOT associated_qml_plugin STREQUAL installed_plugin_target)
+ # Abuse a genex marker, to skip the dependency to be added into prl files.
+ # TODO: Introduce a more generic marker name in qtbase specifically
+ # for skipping deps in prl file deps generation.
+ set(wrapped_associated_qml_plugin
+ "$<${skip_prl_marker}:$<TARGET_NAME:${associated_qml_plugin}>>")
+
+ if(NOT wrapped_associated_qml_plugin IN_LIST additional_plugin_deps)
+ list(APPEND additional_plugin_deps "${wrapped_associated_qml_plugin}")
+ endif()
+ endif()
+ endif()
+ endforeach()
+ endif()
+
+ if(additional_plugin_deps)
+ target_link_libraries(${plugin_target} PRIVATE ${additional_plugin_deps})
+ endif()
+endfunction()
+
+# The function returns the output name of a qml plugin that will be used as library output
+# name and in a qmldir file as the 'plugin <plugin_output_name>' record.
+function(_qt_internal_get_qml_plugin_output_name out_var plugin_target)
+ cmake_parse_arguments(arg
+ ""
+ "BACKING_TARGET;TARGET_PATH;URI"
+ ""
+ ${ARGN}
+ )
+ set(plugin_name)
+ if(TARGET ${plugin_target})
+ get_target_property(plugin_name ${plugin_target} OUTPUT_NAME)
+ endif()
+ if(NOT plugin_name)
+ set(plugin_name "${plugin_target}")
+ endif()
+
+ if(ANDROID)
+ # In Android all plugins are stored in directly the /libs directory. This means that plugin
+ # names must be unique in scope of apk. To make this work we prepend uri-based prefix to
+ # each qml plugin in case if users don't use the manually written qmldir files.
+ get_target_property(no_generate_qmldir ${target} QT_QML_MODULE_NO_GENERATE_QMLDIR)
+ if(TARGET "${arg_BACKING_TARGET}")
+ get_target_property(no_generate_qmldir ${arg_BACKING_TARGET}
+ QT_QML_MODULE_NO_GENERATE_QMLDIR)
+
+ # Adjust Qml plugin names on Android similar to qml_plugin.prf which calls
+ # $$qt5LibraryTarget($$TARGET, "qml/$$TARGETPATH/").
+ # Example plugin names:
+ # qtdeclarative
+ # TARGET_PATH: QtQml/Models
+ # file name: libqml_QtQml_Models_modelsplugin_x86_64.so
+ # qtquickcontrols2
+ # TARGET_PATH: QtQuick/Controls.2/Material
+ # file name:
+ # libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_x86_64.so
+ if(NOT arg_TARGET_PATH)
+ get_target_property(arg_TARGET_PATH ${arg_BACKING_TARGET}
+ QT_QML_MODULE_TARGET_PATH)
+ endif()
+ endif()
+ if(arg_TARGET_PATH)
+ string(REPLACE "/" "_" android_plugin_name_infix_name "${arg_TARGET_PATH}")
+ else()
+ string(REPLACE "." "_" android_plugin_name_infix_name "${arg_URI}")
+ endif()
+
+ # If plugin supposed to use manually written qmldir file we don't prepend the uri-based
+ # prefix to the plugin output name. User should keep the file name of a QML plugin in
+ # qmldir the same as the name of plugin on a file system. Exception is the
+ # ABI-/platform-specific suffix that has the separate processing and should not be
+ # a part of plugin name in qmldir.
+ if(NOT no_generate_qmldir)
+ set(plugin_name
+ "qml_${android_plugin_name_infix_name}_${plugin_name}")
+ endif()
+ endif()
+
+ set(${out_var} "${plugin_name}" PARENT_SCOPE)
+endfunction()
+
+# Used to add extra dependencies between ${target} and ${dep_target} qml plugins in a static
+# Qt build, without creating a dependency in the genereated qmake .prl files.
+# These dependencies make manual linking to static plugins a nicer experience for users that don't
+# want to use qt_import_qml_plugins.
+function(_qt_internal_add_qml_static_plugin_dependency target dep_target)
+ if(NOT BUILD_SHARED_LIBS)
+ # Abuse a genex marker, to skip the dependency to be added into prl files.
+ # TODO: Introduce a more generic marker name in qtbase specifically
+ # for skipping deps in prl file deps generation.
+ set(skip_prl_marker "$<BOOL:QT_IS_PLUGIN_GENEX>")
+ target_link_libraries("${target}" PRIVATE
+ "$<${skip_prl_marker}:$<TARGET_NAME:${dep_target}>>")
+ endif()
+endfunction()
diff --git a/src/qml/animations/qabstractanimationjob.cpp b/src/qml/animations/qabstractanimationjob.cpp
index 76e3f2b7e6..05cf786e7d 100644
--- a/src/qml/animations/qabstractanimationjob.cpp
+++ b/src/qml/animations/qabstractanimationjob.cpp
@@ -243,6 +243,7 @@ void QQmlAnimationTimer::registerRunningAnimation(QAbstractAnimationJob *animati
void QQmlAnimationTimer::unregisterRunningAnimation(QAbstractAnimationJob *animation)
{
+ unsetJobTimer(animation);
if (animation->userControlDisabled())
return;
@@ -307,9 +308,10 @@ QAbstractAnimationJob::~QAbstractAnimationJob()
Q_ASSERT(m_state == Stopped);
if (oldState == Running) {
- Q_ASSERT(QQmlAnimationTimer::instance(false) == m_timer);
- if (m_timer)
+ if (m_timer) {
+ Q_ASSERT(QQmlAnimationTimer::instance(false) == m_timer);
m_timer->unregisterAnimation(this);
+ }
}
Q_ASSERT(!m_hasRegisteredTimer);
}
@@ -551,6 +553,14 @@ void QAbstractAnimationJob::stop()
setState(Stopped);
}
+void QAbstractAnimationJob::complete()
+{
+ // Simulate the full animation cycle
+ setState(Running);
+ setCurrentTime(m_direction == Forward ? duration() : 0);
+ setState(Stopped);
+}
+
void QAbstractAnimationJob::pause()
{
if (m_state == Stopped) {
diff --git a/src/qml/animations/qabstractanimationjob_p.h b/src/qml/animations/qabstractanimationjob_p.h
index 184bfe5e4f..dd978c93d0 100644
--- a/src/qml/animations/qabstractanimationjob_p.h
+++ b/src/qml/animations/qabstractanimationjob_p.h
@@ -114,6 +114,7 @@ public:
void pause();
void resume();
void stop();
+ void complete();
enum ChangeType {
Completion = 0x01,
diff --git a/src/qml/animations/qcontinuinganimationgroupjob.cpp b/src/qml/animations/qcontinuinganimationgroupjob.cpp
index 7d24d8ce55..6d2dc38bfd 100644
--- a/src/qml/animations/qcontinuinganimationgroupjob.cpp
+++ b/src/qml/animations/qcontinuinganimationgroupjob.cpp
@@ -81,9 +81,9 @@ void QContinuingAnimationGroupJob::updateState(QAbstractAnimationJob::State newS
return;
}
for (QAbstractAnimationJob *animation : m_children) {
- resetUncontrolledAnimationFinishTime(animation);
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
animation->setDirection(m_direction);
- animation->start();
+ RETURN_IF_DELETED(animation->start());
}
break;
}
diff --git a/src/qml/animations/qparallelanimationgroupjob.cpp b/src/qml/animations/qparallelanimationgroupjob.cpp
index 4da4a06af2..0d67b2451e 100644
--- a/src/qml/animations/qparallelanimationgroupjob.cpp
+++ b/src/qml/animations/qparallelanimationgroupjob.cpp
@@ -144,10 +144,10 @@ void QParallelAnimationGroupJob::updateState(QAbstractAnimationJob::State newSta
animation->stop();
m_previousLoop = m_direction == Forward ? 0 : m_loopCount - 1;
}
- resetUncontrolledAnimationFinishTime(animation);
+ RETURN_IF_DELETED(resetUncontrolledAnimationFinishTime(animation));
animation->setDirection(m_direction);
if (shouldAnimationStart(animation, oldState == Stopped))
- animation->start();
+ RETURN_IF_DELETED(animation->start());
}
break;
}
diff --git a/src/qml/common/qqmljsfixedpoolarray_p.h b/src/qml/common/qqmljsfixedpoolarray_p.h
index b65b994d6c..15a8cd6878 100644
--- a/src/qml/common/qqmljsfixedpoolarray_p.h
+++ b/src/qml/common/qqmljsfixedpoolarray_p.h
@@ -86,7 +86,7 @@ public:
if (QTypeInfo<T>::isComplex) {
for (int i = 0; i < count; ++i)
new (data + i) T(vector.at(i));
- } else {
+ } else if (count) {
memcpy(data, static_cast<const void*>(vector.constData()), count * sizeof(T));
}
}
diff --git a/src/qml/common/qv4alloca_p.h b/src/qml/common/qv4alloca_p.h
index 65c3e4d65a..b42f74a67b 100644
--- a/src/qml/common/qv4alloca_p.h
+++ b/src/qml/common/qv4alloca_p.h
@@ -100,8 +100,10 @@ QT_END_NAMESPACE
type *name = nullptr
#define Q_ALLOCA_ASSIGN(type, name, size) \
- _qt_alloca_##name.allocate(size); \
- name = static_cast<type*>(_qt_alloca_##name.data())
+ do { \
+ _qt_alloca_##name.allocate(size); \
+ name = static_cast<type*>(_qt_alloca_##name.data()); \
+ } while (false)
#endif
diff --git a/src/qml/common/qv4compileddata_p.h b/src/qml/common/qv4compileddata_p.h
index 00a1890bf6..8b2d5066c6 100644
--- a/src/qml/common/qv4compileddata_p.h
+++ b/src/qml/common/qv4compileddata_p.h
@@ -79,7 +79,11 @@ QT_BEGIN_NAMESPACE
// Also change the comment behind the number to describe the latest change. This has the added
// benefit that if another patch changes the version too, it will result in a merge conflict, and
// not get removed silently.
-#define QV4_DATA_STRUCTURE_VERSION 0x33 // added new bytecode instruction for type assertions
+
+// Note: We got two different versions 0x36 now, one with builtin value types and one without.
+// However, the one without is exclusive to Qt 6.4+ and the compiled data cannot be preserved
+// across Qt versions. Therefore, this is fine.
+#define QV4_DATA_STRUCTURE_VERSION 0x36 // reordered runtime functions when compiling at run time
class QIODevice;
class QQmlTypeNameCache;
@@ -128,33 +132,45 @@ struct TableIterator
struct Location
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 20> line;
- quint32_le_bitfield<20, 12> column;
- };
-
- Location() : _dummy(0) { }
- Location(quint32 l, quint32 c)
- : Location()
+ Location() : m_data(QSpecialIntegerBitfieldZero) {}
+ Location(quint32 l, quint32 c) : Location()
{
- line = l;
- column = c;
- Q_ASSERT(line == l);
- Q_ASSERT(column == c);
+ m_data.set<LineField>(l);
+ m_data.set<ColumnField>(c);
+ Q_ASSERT(m_data.get<LineField>() == l);
+ Q_ASSERT(m_data.get<ColumnField>() == c);
}
inline bool operator<(const Location &other) const {
- return line < other.line ||
- (line == other.line && column < other.column);
+ return m_data.get<LineField>() < other.m_data.get<LineField>()
+ || (m_data.get<LineField>() == other.m_data.get<LineField>()
+ && m_data.get<ColumnField>() < other.m_data.get<ColumnField>());
}
friend size_t qHash(const Location &location, size_t seed = 0)
{
- return QT_PREPEND_NAMESPACE(qHash)(location._dummy, seed);
+ return QT_PREPEND_NAMESPACE(qHash)(location.m_data.data(), seed);
+ }
+
+ friend bool operator==(const Location &a, const Location &b)
+ {
+ return a.m_data.data()== b.m_data.data();
+ }
+
+ void set(quint32 line, quint32 column)
+ {
+ m_data.set<LineField>(line);
+ m_data.set<ColumnField>(column);
}
- friend bool operator==(const Location &a, const Location &b) { return a._dummy == b._dummy; }
+ quint32 line() const { return m_data.get<LineField>(); }
+ quint32 column() const { return m_data.get<ColumnField>(); }
+
+private:
+ using LineField = quint32_le_bitfield_member<0, 20>;
+ using ColumnField = quint32_le_bitfield_member<20, 12>;
+
+ quint32_le_bitfield_union<LineField, ColumnField> m_data;
};
static_assert(sizeof(Location) == 4, "Location structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -168,13 +184,21 @@ struct RegExp
RegExp_Unicode = 0x08,
RegExp_Sticky = 0x10
};
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 5> flags;
- quint32_le_bitfield<5, 27> stringIndex;
- };
- RegExp() : _dummy(0) { }
+ RegExp() : m_data(QSpecialIntegerBitfieldZero) {}
+ RegExp(quint32 flags, quint32 stringIndex) : RegExp()
+ {
+ m_data.set<FlagsField>(flags);
+ m_data.set<StringIndexField>(stringIndex);
+ }
+
+ quint32 flags() const { return m_data.get<FlagsField>(); }
+ quint32 stringIndex() const { return m_data.get<StringIndexField>(); }
+
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 5>;
+ using StringIndexField = quint32_le_bitfield_member<5, 27>;
+ quint32_le_bitfield_union<FlagsField, StringIndexField> m_data;
};
static_assert(sizeof(RegExp) == 4, "RegExp structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -187,25 +211,40 @@ struct Lookup
Type_QmlContextPropertyGetter = 3
};
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 4> type_and_flags;
- quint32_le_bitfield<4, 28> nameIndex;
- };
+ quint32 typeAndFlags() const { return m_data.get<TypeAndFlagsField>(); }
+ quint32 nameIndex() const { return m_data.get<NameIndexField>(); }
- Lookup() : _dummy(0) { }
+ Lookup() : m_data(QSpecialIntegerBitfieldZero) {}
+ Lookup(Type type, quint32 nameIndex) : Lookup()
+ {
+ m_data.set<TypeAndFlagsField>(type);
+ m_data.set<NameIndexField>(nameIndex);
+ }
+
+private:
+ using TypeAndFlagsField = quint32_le_bitfield_member<0, 4>;
+ using NameIndexField = quint32_le_bitfield_member<4, 28>;
+ quint32_le_bitfield_union<TypeAndFlagsField, NameIndexField> m_data;
};
static_assert(sizeof(Lookup) == 4, "Lookup structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct JSClassMember
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 31> nameOffset;
- quint32_le_bitfield<31, 1> isAccessor;
- };
+ JSClassMember() : m_data(QSpecialIntegerBitfieldZero) {}
+
+ void set(quint32 nameOffset, bool isAccessor)
+ {
+ m_data.set<NameOffsetField>(nameOffset);
+ m_data.set<IsAccessorField>(isAccessor ? 1 : 0);
+ }
+
+ quint32 nameOffset() const { return m_data.get<NameOffsetField>(); }
+ bool isAccessor() const { return m_data.get<IsAccessorField>() != 0; }
- JSClassMember() : _dummy(0) { }
+private:
+ using NameOffsetField = quint32_le_bitfield_member<0, 31>;
+ using IsAccessorField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<NameOffsetField, IsAccessorField> m_data;
};
static_assert(sizeof(JSClassMember) == 4, "JSClassMember structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -265,11 +304,26 @@ enum class BuiltinType : unsigned int {
struct ParameterType
{
- union {
- quint32 _dummy;
- quint32_le_bitfield<0, 1> indexIsBuiltinType;
- quint32_le_bitfield<1, 31> typeNameIndexOrBuiltinType;
- };
+ void set(bool indexIsBuiltinType, quint32 typeNameIndexOrBuiltinType)
+ {
+ m_data.set<IndexIsBuiltinTypeField>(indexIsBuiltinType ? 1 : 0);
+ m_data.set<TypeNameIndexOrBuiltinTypeField>(typeNameIndexOrBuiltinType);
+ }
+
+ bool indexIsBuiltinType() const
+ {
+ return m_data.get<IndexIsBuiltinTypeField>() != 0;
+ }
+
+ quint32 typeNameIndexOrBuiltinType() const
+ {
+ return m_data.get<TypeNameIndexOrBuiltinTypeField>();
+ }
+
+private:
+ using IndexIsBuiltinTypeField = quint32_le_bitfield_member<0, 1>;
+ using TypeNameIndexOrBuiltinTypeField = quint32_le_bitfield_member<1, 31>;
+ quint32_le_bitfield_union<IndexIsBuiltinTypeField, TypeNameIndexOrBuiltinTypeField> m_data;
};
static_assert(sizeof(ParameterType) == 4, "ParameterType structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -287,7 +341,8 @@ struct Function
enum Flags : unsigned int {
IsStrict = 0x1,
IsArrowFunction = 0x2,
- IsGenerator = 0x4
+ IsGenerator = 0x4,
+ IsClosureWrapper = 0x8,
};
// Absolute offset into file where the code for this function is located.
@@ -448,7 +503,7 @@ struct Binding
{
quint32_le propertyNameIndex;
- enum ValueType : unsigned int {
+ enum Type : unsigned int {
Type_Invalid,
Type_Boolean,
Type_Number,
@@ -462,7 +517,7 @@ struct Binding
Type_GroupProperty
};
- enum Flags : unsigned int {
+ enum Flag : unsigned int {
IsSignalHandlerExpression = 0x1,
IsSignalHandlerObject = 0x2,
IsOnAssignment = 0x4,
@@ -475,11 +530,20 @@ struct Binding
IsFunctionExpression = 0x200,
IsPropertyObserver = 0x400
};
+ Q_DECLARE_FLAGS(Flags, Flag);
+
+ using FlagsField = quint32_le_bitfield_member<0, 16>;
+ using TypeField = quint32_le_bitfield_member<16, 16>;
+ quint32_le_bitfield_union<FlagsField, TypeField> flagsAndType;
+
+ void clearFlags() { flagsAndType.set<FlagsField>(0); }
+ void setFlag(Flag flag) { flagsAndType.set<FlagsField>(flagsAndType.get<FlagsField>() | flag); }
+ bool hasFlag(Flag flag) const { return Flags(flagsAndType.get<FlagsField>()) & flag; }
+ Flags flags() const { return Flags(flagsAndType.get<FlagsField>()); }
+
+ void setType(Type type) { flagsAndType.set<TypeField>(type); }
+ Type type() const { return Type(flagsAndType.get<TypeField>()); }
- union {
- quint32_le_bitfield<0, 16> flags;
- quint32_le_bitfield<16, 16> type;
- };
union {
bool b;
quint32_le constantValueIndex;
@@ -493,24 +557,31 @@ struct Binding
Location location;
Location valueLocation;
+ bool hasSignalHandlerBindingFlag() const
+ {
+ const Flags bindingFlags = flags();
+ return bindingFlags & IsSignalHandlerExpression
+ || bindingFlags & IsSignalHandlerObject
+ || bindingFlags & IsPropertyObserver;
+ }
+
bool isValueBinding() const
{
- if (type == Type_AttachedProperty
- || type == Type_GroupProperty)
- return false;
- if (flags & IsSignalHandlerExpression
- || flags & IsSignalHandlerObject
- || flags & IsPropertyObserver)
+ switch (type()) {
+ case Type_AttachedProperty:
+ case Type_GroupProperty:
return false;
- return true;
+ default:
+ return !hasSignalHandlerBindingFlag();
+ }
}
- bool isValueBindingNoAlias() const { return isValueBinding() && !(flags & IsBindingToAlias); }
- bool isValueBindingToAlias() const { return isValueBinding() && (flags & IsBindingToAlias); }
+ bool isValueBindingNoAlias() const { return isValueBinding() && !hasFlag(IsBindingToAlias); }
+ bool isValueBindingToAlias() const { return isValueBinding() && hasFlag(IsBindingToAlias); }
bool isSignalHandler() const
{
- if (flags & IsSignalHandlerExpression || flags & IsSignalHandlerObject || flags & IsPropertyObserver) {
+ if (hasSignalHandlerBindingFlag()) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isAttachedProperty());
Q_ASSERT(!isGroupProperty());
@@ -521,7 +592,7 @@ struct Binding
bool isAttachedProperty() const
{
- if (type == Type_AttachedProperty) {
+ if (type() == Type_AttachedProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isGroupProperty());
@@ -532,7 +603,7 @@ struct Binding
bool isGroupProperty() const
{
- if (type == Type_GroupProperty) {
+ if (type() == Type_GroupProperty) {
Q_ASSERT(!isValueBinding());
Q_ASSERT(!isSignalHandler());
Q_ASSERT(!isAttachedProperty());
@@ -541,7 +612,7 @@ struct Binding
return false;
}
- bool isFunctionExpression() const { return (flags & IsFunctionExpression); }
+ bool isFunctionExpression() const { return hasFlag(IsFunctionExpression); }
//reverse of Lexer::singleEscape()
static QString escapedString(const QString &string)
@@ -586,16 +657,19 @@ struct Binding
return tmp;
}
- bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; }
- bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); }
+ bool isTranslationBinding() const
+ {
+ const Binding::Type bindingType = type();
+ return bindingType == Type_Translation || bindingType == Type_TranslationById;
+ }
+ bool evaluatesToString() const { return type() == Type_String || isTranslationBinding(); }
bool valueAsBoolean() const
{
- if (type == Type_Boolean)
+ if (type() == Type_Boolean)
return value.b;
return false;
}
-
};
static_assert(sizeof(Binding) == 24, "Binding structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -668,37 +742,57 @@ static_assert(sizeof(Signal) == 12, "Signal structure needs to have the expected
struct Property
{
- quint32_le nameIndex;
- union {
- quint32_le_bitfield<0, 28> builtinTypeOrTypeNameIndex;
- quint32_le_bitfield<28, 1> isRequired;
- quint32_le_bitfield<29, 1> isBuiltinType;
- quint32_le_bitfield<30, 1> isList;
- quint32_le_bitfield<31, 1> isReadOnly;
- };
+private:
+ using BuiltinTypeOrTypeNameIndexField = quint32_le_bitfield_member<0, 28>;
+ using IsRequiredField = quint32_le_bitfield_member<28, 1>;
+ using IsBuiltinTypeField = quint32_le_bitfield_member<29, 1>;
+ using IsListField = quint32_le_bitfield_member<30, 1>;
+ using IsReadOnlyField = quint32_le_bitfield_member<31, 1>;
+public:
+ quint32_le nameIndex;
+ quint32_le_bitfield_union<
+ BuiltinTypeOrTypeNameIndexField,
+ IsRequiredField,
+ IsBuiltinTypeField,
+ IsListField,
+ IsReadOnlyField> data;
Location location;
void setBuiltinType(BuiltinType t)
{
- builtinTypeOrTypeNameIndex = static_cast<quint32>(t);
- isBuiltinType = true;
+ data.set<BuiltinTypeOrTypeNameIndexField>(static_cast<quint32>(t));
+ data.set<IsBuiltinTypeField>(true);
}
+
BuiltinType builtinType() const {
- if (isBuiltinType)
- return static_cast<BuiltinType>(quint32(builtinTypeOrTypeNameIndex));
+ if (data.get<IsBuiltinTypeField>() != 0)
+ return BuiltinType(data.get<BuiltinTypeOrTypeNameIndexField>());
return BuiltinType::InvalidBuiltin;
}
+
void setCustomType(int nameIndex)
{
- builtinTypeOrTypeNameIndex = nameIndex;
- isBuiltinType = false;
+ data.set<BuiltinTypeOrTypeNameIndexField>(nameIndex);
+ data.set<IsBuiltinTypeField>(false);
}
int customType() const
{
- return isBuiltinType ? -1 : builtinTypeOrTypeNameIndex;
+ return data.get<IsBuiltinTypeField>() ? -1 : data.get<BuiltinTypeOrTypeNameIndexField>();
}
+
+ bool isBuiltinType() const { return data.get<IsBuiltinTypeField>(); }
+ uint builtinTypeOrTypeNameIndex() const { return data.get<BuiltinTypeOrTypeNameIndexField>(); }
+
+ bool isList() const { return data.get<IsListField>(); }
+ void setIsList(bool isList) { data.set<IsListField>(isList); }
+
+ bool isRequired() const { return data.get<IsRequiredField>(); }
+ void setIsRequired(bool isRequired) { data.set<IsRequiredField>(isRequired); }
+
+ bool isReadOnly() const { return data.get<IsReadOnlyField>(); }
+ void setIsReadOnly(bool isReadOnly) { data.set<IsReadOnlyField>(isReadOnly); }
};
static_assert(sizeof(Property) == 12, "Property structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
@@ -709,20 +803,31 @@ struct RequiredPropertyExtraData {
static_assert (sizeof(RequiredPropertyExtraData) == 4, "RequiredPropertyExtraData structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Alias {
- enum Flags : unsigned int {
+private:
+ using NameIndexField = quint32_le_bitfield_member<0, 29>;
+ using FlagsField = quint32_le_bitfield_member<29, 3>;
+
+ // object id index (in QQmlContextData::idValues)
+ using TargetObjectIdField = quint32_le_bitfield_member<0, 31>;
+ using AliasToLocalAliasField = quint32_le_bitfield_member<31, 1>;
+
+public:
+
+ enum Flag : unsigned int {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
- union {
- quint32_le_bitfield<0, 29> nameIndex;
- quint32_le_bitfield<29, 3> flags;
- };
+ Q_DECLARE_FLAGS(Flags, Flag)
+
+ quint32_le_bitfield_union<NameIndexField, FlagsField> nameIndexAndFlags;
+
union {
quint32_le idIndex; // string index
- quint32_le_bitfield<0, 31> targetObjectId; // object id index (in QQmlContextData::idValues)
- quint32_le_bitfield<31, 1> aliasToLocalAlias;
+ quint32_le_bitfield_union<TargetObjectIdField, AliasToLocalAliasField>
+ targetObjectIdAndAliasToLocalAlias;
};
+
union {
quint32_le propertyNameIndex; // string index
qint32_le encodedMetaPropertyIndex;
@@ -731,16 +836,67 @@ struct Alias {
Location location;
Location referenceLocation;
- bool isObjectAlias() const {
- Q_ASSERT(flags & Resolved);
+ bool hasFlag(Flag flag) const
+ {
+ return nameIndexAndFlags.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ nameIndexAndFlags.set<FlagsField>(nameIndexAndFlags.get<FlagsField>() | flag);
+ }
+
+ void clearFlags()
+ {
+ nameIndexAndFlags.set<FlagsField>(0);
+ }
+
+ quint32 nameIndex() const
+ {
+ return nameIndexAndFlags.get<NameIndexField>();
+ }
+
+ void setNameIndex(quint32 nameIndex)
+ {
+ nameIndexAndFlags.set<NameIndexField>(nameIndex);
+ }
+
+ bool isObjectAlias() const
+ {
+ Q_ASSERT(hasFlag(Resolved));
return encodedMetaPropertyIndex == -1;
}
+
+ bool isAliasToLocalAlias() const
+ {
+ return targetObjectIdAndAliasToLocalAlias.get<AliasToLocalAliasField>();
+ }
+
+ void setIsAliasToLocalAlias(bool isAliasToLocalAlias)
+ {
+ targetObjectIdAndAliasToLocalAlias.set<AliasToLocalAliasField>(isAliasToLocalAlias);
+ }
+
+ quint32 targetObjectId() const
+ {
+ return targetObjectIdAndAliasToLocalAlias.get<TargetObjectIdField>();
+ }
+
+ void setTargetObjectId(quint32 targetObjectId)
+ {
+ targetObjectIdAndAliasToLocalAlias.set<TargetObjectIdField>(targetObjectId);
+ }
};
static_assert(sizeof(Alias) == 20, "Alias structure needs to have the expected size to be binary compatible on disk when generated by host compiler and loaded by target");
struct Object
{
- enum Flags : unsigned int {
+private:
+ using FlagsField = quint32_le_bitfield_member<0, 15>;
+ using DefaultPropertyIsAliasField = quint32_le_bitfield_member<15, 1>;
+ using IdField = quint32_le_bitfield_member<16, 16, qint32>;
+public:
+ enum Flag : unsigned int {
NoFlag = 0x0,
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
HasDeferredBindings = 0x2, // any of the bindings are deferred
@@ -748,17 +904,15 @@ struct Object
IsInlineComponentRoot = 0x8,
InPartOfInlineComponent = 0x10
};
+ Q_DECLARE_FLAGS(Flags, Flag);
// Depending on the use, this may be the type name to instantiate before instantiating this
// object. For grouped properties the type name will be empty and for attached properties
// it will be the name of the attached type.
quint32_le inheritedTypeNameIndex;
quint32_le idNameIndex;
- union {
- quint32_le_bitfield<0, 15> flags;
- quint32_le_bitfield<15, 1> defaultPropertyIsAlias;
- qint32_le_bitfield<16, 16> id;
- };
+ quint32_le_bitfield_union<FlagsField, DefaultPropertyIsAliasField, IdField>
+ flagsAndDefaultPropertyIsAliasAndId;
qint32_le indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
quint16_le nFunctions;
quint16_le nProperties;
@@ -787,6 +941,48 @@ struct Object
// InlineComponent[]
// RequiredPropertyExtraData[]
+ Flags flags() const
+ {
+ return Flags(flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>());
+ }
+
+ bool hasFlag(Flag flag) const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() & flag;
+ }
+
+ void setFlag(Flag flag)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(
+ flagsAndDefaultPropertyIsAliasAndId.get<FlagsField>() | flag);
+ }
+
+ void setFlags(Flags flags)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<FlagsField>(flags);
+ }
+
+ bool hasAliasAsDefaultProperty() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<DefaultPropertyIsAliasField>();
+ }
+
+ void setHasAliasAsDefaultProperty(bool defaultAlias)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<DefaultPropertyIsAliasField>(defaultAlias);
+ }
+
+ qint32 objectId() const
+ {
+ return flagsAndDefaultPropertyIsAliasAndId.get<IdField>();
+ }
+
+ void setObjectId(qint32 id)
+ {
+ flagsAndDefaultPropertyIsAliasAndId.set<IdField>(id);
+ }
+
+
static int calculateSizeExcludingSignalsAndEnums(int nFunctions, int nProperties, int nAliases, int nEnums, int nSignals, int nBindings, int nNamedObjectsInComponent, int nInlineComponents, int nRequiredPropertyExtraData)
{
return ( sizeof(Object)
@@ -1138,8 +1334,8 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto prop = obj->propertiesBegin();
auto const propEnd = obj->propertiesEnd();
for ( ; prop != propEnd; ++prop) {
- if (!prop->isBuiltinType) {
- TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex, prop->location);
+ if (!prop->isBuiltinType()) {
+ TypeReference &r = this->add(prop->builtinTypeOrTypeNameIndex(), prop->location);
r.errorWhenNotFound = true;
}
}
@@ -1147,7 +1343,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
auto binding = obj->bindingsBegin();
auto const bindingEnd = obj->bindingsEnd();
for ( ; binding != bindingEnd; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty)
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty)
this->add(binding->propertyNameIndex, binding->location);
}
@@ -1329,7 +1525,7 @@ public:
QString bindingValueAsString(const CompiledData::Binding *binding) const
{
using namespace CompiledData;
- switch (binding->type) {
+ switch (binding->type()) {
case Binding::Type_Script:
case Binding::Type_String:
return stringAt(binding->stringIndex);
@@ -1352,14 +1548,14 @@ public:
QString bindingValueAsScriptString(const CompiledData::Binding *binding) const
{
- return (binding->type == CompiledData::Binding::Type_String)
+ return (binding->type() == CompiledData::Binding::Type_String)
? CompiledData::Binding::escapedString(stringAt(binding->stringIndex))
: bindingValueAsString(binding);
}
double bindingValueAsNumber(const CompiledData::Binding *binding) const
{
- if (binding->type != CompiledData::Binding::Type_Number)
+ if (binding->type() != CompiledData::Binding::Type_Number)
return 0.0;
return constants[binding->value.constantValueIndex].doubleValue();
}
@@ -1386,7 +1582,8 @@ public:
template<typename Char>
bool saveToDisk(const std::function<bool(const Char *, quint32)> &writer) const
{
- auto cleanup = qScopeGuard([this]() { mutableFlags() ^= temporaryFlags; });
+ const quint32_le oldFlags = mutableFlags();
+ auto cleanup = qScopeGuard([this, oldFlags]() { mutableFlags() = oldFlags; });
mutableFlags() |= temporaryFlags;
return writer(data<Char>(), size());
}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 3b1d9f4595..9739c936da 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -76,7 +76,7 @@ void Object::simplifyRequiredProperties() {
for (auto it = this->propertiesBegin(); it != this->propertiesEnd(); ++it) {
auto requiredIt = required.find(it->nameIndex);
if (requiredIt != required.end()) {
- it->isRequired = true;
+ it->setIsRequired(true);
required.erase(requiredIt);
}
}
@@ -106,20 +106,18 @@ bool Parameter::init(QV4::CompiledData::Parameter *param, const QV4::Compiler::J
bool Parameter::initType(QV4::CompiledData::ParameterType *paramType, const QV4::Compiler::JSUnitGenerator *stringGenerator, int typeNameIndex)
{
- paramType->indexIsBuiltinType = false;
- paramType->typeNameIndexOrBuiltinType = 0;
const QString typeName = stringGenerator->stringForIndex(typeNameIndex);
auto builtinType = stringToBuiltinType(typeName);
if (builtinType == QV4::CompiledData::BuiltinType::InvalidBuiltin) {
- if (typeName.isEmpty() || !typeName.at(0).isUpper())
+ if (typeName.isEmpty() || !typeName.at(0).isUpper()) {
+ paramType->set(false, 0);
return false;
- paramType->indexIsBuiltinType = false;
- paramType->typeNameIndexOrBuiltinType = typeNameIndex;
+ }
Q_ASSERT(quint32(typeNameIndex) < (1u << 31));
+ paramType->set(false, typeNameIndex);
} else {
- paramType->indexIsBuiltinType = true;
- paramType->typeNameIndexOrBuiltinType = static_cast<quint32>(builtinType);
Q_ASSERT(quint32(builtinType) < (1u << 31));
+ paramType->set(true, static_cast<quint32>(builtinType));
}
return true;
}
@@ -172,7 +170,7 @@ QV4::CompiledData::BuiltinType Parameter::stringToBuiltinType(const QString &typ
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex,
const QV4::CompiledData::Location &loc)
{
- Q_ASSERT(loc.line > 0 && loc.column > 0);
+ Q_ASSERT(loc.line() > 0 && loc.column() > 0);
inheritedTypeNameIndex = typeNameIndex;
location = loc;
idNameIndex = idIndex;
@@ -197,8 +195,8 @@ QString IRBuilder::sanityCheckFunctionNames(Object *obj, const QSet<QString> &il
QSet<int> functionNames;
for (auto functionit = obj->functionsBegin(); functionit != obj->functionsEnd(); ++functionit) {
Function *f = functionit.ptr;
- errorLocation->startLine = f->location.line;
- errorLocation->startColumn = f->location.column;
+ errorLocation->startLine = f->location.line();
+ errorLocation->startColumn = f->location.column();
if (functionNames.contains(f->nameIndex))
return tr("Duplicate method name");
functionNames.insert(f->nameIndex);
@@ -258,6 +256,10 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool
if (p->nameIndex == prop->nameIndex)
return tr("Duplicate property name");
+ for (Alias *a = target->aliases->first; a; a = a->next)
+ if (a->nameIndex() == prop->nameIndex)
+ return tr("Property duplicates alias name");
+
if (propertyName.constData()->isUpper())
return tr("Property names cannot begin with an upper case letter");
@@ -278,12 +280,19 @@ QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefau
if (!target)
target = this;
- auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
- return targetAlias.nameIndex == alias->nameIndex;
+ const auto aliasWithSameName = std::find_if(target->aliases->begin(), target->aliases->end(), [&alias](const Alias &targetAlias){
+ return targetAlias.nameIndex() == alias->nameIndex();
});
if (aliasWithSameName != target->aliases->end())
return tr("Duplicate alias name");
+ const auto aliasSameAsProperty = std::find_if(target->properties->begin(), target->properties->end(), [&alias](const Property &targetProp){
+ return targetProp.nameIndex == alias->nameIndex();
+ });
+
+ if (aliasSameAsProperty != target->properties->end())
+ return tr("Alias has same name as existing property");
+
if (aliasName.constData()->isUpper())
return tr("Alias names cannot begin with an upper case letter");
@@ -322,13 +331,17 @@ void Object::appendRequiredPropertyExtraData(RequiredPropertyExtraData *extraDat
QString Object::appendBinding(Binding *b, bool isListBinding)
{
const bool bindingToDefaultProperty = (b->propertyNameIndex == quint32(0));
- if (!isListBinding && !bindingToDefaultProperty
- && b->type != QV4::CompiledData::Binding::Type_GroupProperty
- && b->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && !(b->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (!isListBinding
+ && !bindingToDefaultProperty
+ && b->type() != QV4::CompiledData::Binding::Type_GroupProperty
+ && b->type() != QV4::CompiledData::Binding::Type_AttachedProperty
+ && !b->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
Binding *existing = findBinding(b->propertyNameIndex);
- if (existing && existing->isValueBinding() == b->isValueBinding() && !(existing->flags & QV4::CompiledData::Binding::IsOnAssignment))
+ if (existing
+ && existing->isValueBinding() == b->isValueBinding()
+ && !existing->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
return tr("Property value set multiple times");
+ }
}
if (bindingToDefaultProperty)
insertSorted(b);
@@ -396,8 +409,7 @@ void ScriptDirectivesCollector::importFile(const QString &jsfile, const QString
import->type = QV4::CompiledData::Import::ImportScript;
import->uriIndex = jsGenerator->registerString(jsfile);
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -408,8 +420,7 @@ void ScriptDirectivesCollector::importModule(const QString &uri, const QString &
import->uriIndex = jsGenerator->registerString(uri);
import->version = IRBuilder::extractVersion(QStringView(version));
import->qualifierIndex = jsGenerator->registerString(module);
- import->location.line = lineNumber;
- import->location.column = column;
+ import->location.set(lineNumber, column);
document->imports << import;
}
@@ -594,8 +605,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiInlineComponent *ast)
inlineComponent->nameIndex = registerString(ast->name.toString());
inlineComponent->objectIndex = idx;
auto location = ast->firstSourceLocation();
- inlineComponent->location.line = location.startLine;
- inlineComponent->location.column = location.startColumn;
+ inlineComponent->location.set(location.startLine, location.startColumn);
_object->appendInlineComponent(inlineComponent);
return false;
}
@@ -791,8 +801,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiImport *node)
import->version = QTypeRevision();
}
- import->location.line = node->importToken.startLine;
- import->location.column = node->importToken.startColumn;
+ import->location.set(node->importToken.startLine, node->importToken.startColumn);
import->uriIndex = registerString(uri);
@@ -821,8 +830,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPragma *node)
return false;
}
- pragma->location.line = node->pragmaToken.startLine;
- pragma->location.column = node->pragmaToken.startColumn;
+ pragma->location.set(node->pragmaToken.startLine, node->pragmaToken.startColumn);
_pragmas.append(pragma);
return false;
@@ -855,8 +863,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
if (enumName.at(0).isLower())
COMPILE_EXCEPTION(node->enumToken, tr("Scoped enum names must begin with an upper case letter"));
- enumeration->location.line = node->enumToken.startLine;
- enumeration->location.column = node->enumToken.startColumn;
+ enumeration->location.set(node->enumToken.startLine, node->enumToken.startColumn);
enumeration->enumValues = New<PoolList<EnumValue>>();
@@ -875,8 +882,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiEnumDeclaration *node)
COMPILE_EXCEPTION(e->valueToken, tr("Enum value out of range"));
enumValue->value = e->value;
- enumValue->location.line = e->memberToken.startLine;
- enumValue->location.column = e->memberToken.startColumn;
+ enumValue->location.set(e->memberToken.startLine, e->memberToken.startColumn);
enumeration->enumValues->append(enumValue);
e = e->next;
@@ -900,8 +906,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
signal->nameIndex = registerString(signalName);
QQmlJS::SourceLocation loc = node->typeToken;
- signal->location.line = loc.startLine;
- signal->location.column = loc.startColumn;
+ signal->location.set(loc.startLine, loc.startColumn);
signal->parameters = New<PoolList<Parameter> >();
@@ -950,8 +955,8 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
const QStringView &name = node->name;
Property *property = New<Property>();
- property->isReadOnly = node->isReadonlyMember;
- property->isRequired = node->isRequired;
+ property->setIsReadOnly(node->isReadonlyMember);
+ property->setIsRequired(node->isRequired);
QV4::CompiledData::BuiltinType builtinPropertyType = Parameter::stringToBuiltinType(memberType);
bool typeFound = builtinPropertyType != QV4::CompiledData::BuiltinType::InvalidBuiltin;
@@ -963,7 +968,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
property->setCustomType(registerString(memberType));
if (typeModifier == QLatin1String("list")) {
- property->isList = true;
+ property->setIsList(true);
} else if (!typeModifier.isEmpty()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
@@ -983,8 +988,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
property->nameIndex = registerString(propName);
QQmlJS::SourceLocation loc = node->firstSourceLocation();
- property->location.line = loc.startLine;
- property->location.column = loc.startColumn;
+ property->location.set(loc.startLine, loc.startColumn);
QQmlJS::SourceLocation errorLocation;
QString error;
@@ -1028,8 +1032,7 @@ bool IRBuilder::visit(QQmlJS::AST::UiSourceElement *node)
Function *f = New<Function>();
QQmlJS::SourceLocation loc = funDecl->identifierToken;
- f->location.line = loc.startLine;
- f->location.column = loc.startColumn;
+ f->location.set(loc.startLine, loc.startColumn);
f->index = index;
f->nameIndex = registerString(funDecl->name.toString());
@@ -1102,32 +1105,31 @@ QStringView IRBuilder::textRefAt(const QQmlJS::SourceLocation &first, const QQml
void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST::Statement *statement, QQmlJS::AST::Node *parentNode)
{
QQmlJS::SourceLocation loc = statement->firstSourceLocation();
- binding->valueLocation.line = loc.startLine;
- binding->valueLocation.column = loc.startColumn;
- binding->type = QV4::CompiledData::Binding::Type_Invalid;
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ binding->valueLocation.set(loc.startLine, loc.startColumn);
+ binding->setType(QV4::CompiledData::Binding::Type_Invalid);
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (exprStmt) {
QQmlJS::AST::ExpressionNode * const expr = exprStmt->expression;
if (QQmlJS::AST::StringLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::StringLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = registerString(lit->value.toString());
} else if (QQmlJS::AST::TemplateLiteral *templateLit = QQmlJS::AST::cast<QQmlJS::AST::TemplateLiteral *>(expr);
templateLit && templateLit->hasNoSubstitution) {
// A template literal without substitution is just a string.
// With substitution, it could however be an arbitrarily complex expression
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = registerString(templateLit->value.toString());
} else if (expr->kind == QQmlJS::AST::Node::Kind_TrueLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = true;
} else if (expr->kind == QQmlJS::AST::Node::Kind_FalseLiteral) {
- binding->type = QV4::CompiledData::Binding::Type_Boolean;
+ binding->setType(QV4::CompiledData::Binding::Type_Boolean);
binding->value.b = false;
} else if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(lit->value));
} else if (QQmlJS::AST::CallExpression *call = QQmlJS::AST::cast<QQmlJS::AST::CallExpression *>(expr)) {
if (QQmlJS::AST::IdentifierExpression *base = QQmlJS::AST::cast<QQmlJS::AST::IdentifierExpression *>(call->base)) {
@@ -1136,21 +1138,21 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
// below.
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::FunctionExpression *>(expr)) {
- binding->flags |= QV4::CompiledData::Binding::IsFunctionExpression;
+ binding->setFlag(QV4::CompiledData::Binding::IsFunctionExpression);
} else if (QQmlJS::AST::UnaryMinusExpression *unaryMinus = QQmlJS::AST::cast<QQmlJS::AST::UnaryMinusExpression *>(expr)) {
if (QQmlJS::AST::NumericLiteral *lit = QQmlJS::AST::cast<QQmlJS::AST::NumericLiteral *>(unaryMinus->expression)) {
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = jsGenerator->registerConstant(QV4::Encode(-lit->value));
}
} else if (QQmlJS::AST::cast<QQmlJS::AST::NullExpression *>(expr)) {
- binding->type = QV4::CompiledData::Binding::Type_Null;
+ binding->setType(QV4::CompiledData::Binding::Type_Null);
binding->value.nullMarker = 0;
}
}
// Do binding instead
- if (binding->type == QV4::CompiledData::Binding::Type_Invalid) {
- binding->type = QV4::CompiledData::Binding::Type_Script;
+ if (binding->type() == QV4::CompiledData::Binding::Type_Invalid) {
+ binding->setType(QV4::CompiledData::Binding::Type_Script);
CompiledFunctionOrExpression *expr = New<CompiledFunctionOrExpression>();
expr->node = statement;
@@ -1161,7 +1163,15 @@ void IRBuilder::setBindingValue(QV4::CompiledData::Binding *binding, QQmlJS::AST
binding->value.compiledScriptIndex = index;
// We don't need to store the binding script as string, except for script strings
// and types with custom parsers. Those will be added later in the compilation phase.
- binding->stringIndex = emptyStringIndex;
+ // Except that we cannot recover the string when cachegen runs; we need to therefore retain
+ // "undefined". Any other "special" strings (for the various literals) are already handled above
+ QQmlJS::AST::Node *nodeForString = statement;
+ if (exprStmt)
+ nodeForString = exprStmt->expression;
+ if (asStringRef(nodeForString) == u"undefined")
+ binding->stringIndex = registerString(u"undefined"_qs);
+ else
+ binding->stringIndex = emptyStringIndex;
}
}
@@ -1206,7 +1216,7 @@ void IRBuilder::tryGeneratingTranslationBinding(QStringView base, AST::ArgumentL
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_Translation;
+ binding->setType(QV4::CompiledData::Binding::Type_Translation);
binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
} else if (base == QLatin1String("qsTrId")) {
QV4::CompiledData::TranslationData translationData;
@@ -1239,7 +1249,7 @@ void IRBuilder::tryGeneratingTranslationBinding(QStringView base, AST::ArgumentL
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_TranslationById;
+ binding->setType(QV4::CompiledData::Binding::Type_TranslationById);
binding->value.translationDataIndex = jsGenerator->registerTranslation(translationData);
} else if (base == QLatin1String("QT_TR_NOOP") || base == QLatin1String("QT_TRID_NOOP")) {
if (!args || !args->expression)
@@ -1256,7 +1266,7 @@ void IRBuilder::tryGeneratingTranslationBinding(QStringView base, AST::ArgumentL
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = jsGenerator->registerString(str.toString());
} else if (base == QLatin1String("QT_TRANSLATE_NOOP")) {
if (!args || !args->expression)
@@ -1277,7 +1287,7 @@ void IRBuilder::tryGeneratingTranslationBinding(QStringView base, AST::ArgumentL
if (args)
return; // too many arguments, stop
- binding->type = QV4::CompiledData::Binding::Type_String;
+ binding->setType(QV4::CompiledData::Binding::Type_String);
binding->stringIndex = jsGenerator->registerString(str.toString());
}
}
@@ -1314,9 +1324,8 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
- binding->flags = 0;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
+ binding->clearFlags();
setBindingValue(binding, value, parentNode);
QString error = bindingsTarget()->appendBinding(binding, /*isListBinding*/false);
if (!error.isEmpty()) {
@@ -1334,27 +1343,26 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
- binding->location.line = nameLocation.startLine;
- binding->location.column = nameLocation.startColumn;
+ binding->location.set(nameLocation.startLine, nameLocation.startColumn);
const Object *obj = _objects.at(objectIndex);
binding->valueLocation = obj->location;
- binding->flags = 0;
+ binding->clearFlags();
- if (_propertyDeclaration && _propertyDeclaration->isReadOnly)
- binding->flags |= QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration;
+ if (_propertyDeclaration && _propertyDeclaration->isReadOnly())
+ binding->setFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration);
// No type name on the initializer means it must be a group property
if (_objects.at(objectIndex)->inheritedTypeNameIndex == emptyStringIndex)
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(Binding::Type_GroupProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_Object;
+ binding->setType(Binding::Type_Object);
if (isOnAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(Binding::IsOnAssignment);
if (isListItem)
- binding->flags |= QV4::CompiledData::Binding::IsListItem;
+ binding->setFlag(Binding::IsListItem);
binding->value.objectIndex = objectIndex;
QString error = bindingsTarget()->appendBinding(binding, isListItem);
@@ -1366,16 +1374,15 @@ void IRBuilder::appendBinding(const QQmlJS::SourceLocation &qualifiedNameLocatio
bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
{
Alias *alias = New<Alias>();
- alias->flags = 0;
+ alias->clearFlags();
if (node->isReadonlyMember)
- alias->flags |= QV4::CompiledData::Alias::IsReadOnly;
+ alias->setFlag(QV4::CompiledData::Alias::IsReadOnly);
const QString propName = node->name.toString();
- alias->nameIndex = registerString(propName);
+ alias->setNameIndex(registerString(propName));
QQmlJS::SourceLocation loc = node->firstSourceLocation();
- alias->location.line = loc.startLine;
- alias->location.column = loc.startColumn;
+ alias->location.set(loc.startLine, loc.startColumn);
alias->propertyNameIndex = emptyStringIndex;
@@ -1389,8 +1396,7 @@ bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
rhsLoc = node->statement->firstSourceLocation();
else
rhsLoc = node->semicolonToken;
- alias->referenceLocation.line = rhsLoc.startLine;
- alias->referenceLocation.column = rhsLoc.startColumn;
+ alias->referenceLocation.set(rhsLoc.startLine, rhsLoc.startColumn);
QStringList aliasReference;
@@ -1485,8 +1491,7 @@ bool IRBuilder::setId(const QQmlJS::SourceLocation &idLocation, QQmlJS::AST::Sta
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
_object->idNameIndex = registerString(idQString);
- _object->locationOfIdProperty.line = idLocation.startLine;
- _object->locationOfIdProperty.column = idLocation.startColumn;
+ _object->locationOfIdProperty.set(idLocation.startLine, idLocation.startColumn);
return true;
}
@@ -1532,19 +1537,19 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = qualifiedIdElement->identifierToken.offset;
- binding->location.line = qualifiedIdElement->identifierToken.startLine;
- binding->location.column = qualifiedIdElement->identifierToken.startColumn;
- binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine;
- binding->valueLocation.column = qualifiedIdElement->next->identifierToken.startColumn;
- binding->flags = 0;
+ binding->location.set(qualifiedIdElement->identifierToken.startLine,
+ qualifiedIdElement->identifierToken.startColumn);
+ binding->valueLocation.set(qualifiedIdElement->next->identifierToken.startLine,
+ qualifiedIdElement->next->identifierToken.startColumn);
+ binding->clearFlags();
if (onAssignment)
- binding->flags |= QV4::CompiledData::Binding::IsOnAssignment;
+ binding->setFlag(QV4::CompiledData::Binding::IsOnAssignment);
if (isAttachedProperty)
- binding->type = QV4::CompiledData::Binding::Type_AttachedProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_AttachedProperty);
else
- binding->type = QV4::CompiledData::Binding::Type_GroupProperty;
+ binding->setType(QV4::CompiledData::Binding::Type_GroupProperty);
int objIndex = 0;
if (!defineQMLObject(&objIndex, nullptr, binding->location, nullptr, nullptr))
@@ -1605,7 +1610,7 @@ bool IRBuilder::isStatementNodeScript(QQmlJS::AST::Statement *statement)
bool IRBuilder::isRedundantNullInitializerForPropertyDeclaration(Property *property, QQmlJS::AST::Statement *statement)
{
- if (property->isBuiltinType || property->isList)
+ if (property->isBuiltinType() || property->isList())
return false;
QQmlJS::AST::ExpressionStatement *exprStmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement *>(statement);
if (!exprStmt)
@@ -1707,10 +1712,10 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
- objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
- objectToWrite->flags = o->flags;
+ objectToWrite->setHasAliasAsDefaultProperty(o->defaultPropertyIsAlias);
+ objectToWrite->setFlags(QV4::CompiledData::Object::Flags(o->flags));
objectToWrite->idNameIndex = o->idNameIndex;
- objectToWrite->id = o->id;
+ objectToWrite->setObjectId(o->id);
objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@@ -1885,7 +1890,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, Binding
continue;
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
*bindingToWrite = *b;
- if (b->type == QV4::CompiledData::Binding::Type_Script)
+ if (b->type() == QV4::CompiledData::Binding::Type_Script)
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
bindingPtr += sizeof(QV4::CompiledData::Binding);
}
@@ -1924,6 +1929,12 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
scan.enterEnvironment(f.parentNode, QV4::Compiler::ContextType::Binding, qmlName(f));
}
+ /* We do not want to visit the whole function, as we already called enterQmlFunction
+ However, there might be a function defined as a default argument of the function.
+ That needs to be considered, too, so we call handleTopLevelFunctionFormals to
+ deal with them.
+ */
+ scan.handleTopLevelFunctionFormals(function);
scan(function ? function->body : f.node);
scan.leaveEnvironment();
}
@@ -1973,60 +1984,23 @@ QVector<int> JSCodeGen::generateJSCodeForFunctionsAndBindings(const QList<Compil
return runtimeFunctionIndices;
}
-bool JSCodeGen::generateCodeForComponents(const QVector<quint32> &componentRoots)
-{
- for (int i = 0; i < componentRoots.count(); ++i) {
- if (!compileComponent(componentRoots.at(i)))
- return false;
- }
-
- return compileComponent(/*root object*/0);
-}
-
-bool JSCodeGen::compileComponent(int contextObject)
-{
- const QmlIR::Object *obj = document->objects.at(contextObject);
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
- Q_ASSERT(obj->bindingCount() == 1);
- const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
- contextObject = componentBinding->value.objectIndex;
- }
-
- return compileJavaScriptCodeInObjectsRecursively(contextObject, contextObject);
-}
-
-bool JSCodeGen::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
+bool JSCodeGen::generateRuntimeFunctions(QmlIR::Object *object)
{
- QmlIR::Object *object = document->objects.at(objectIndex);
- if (object->flags & QV4::CompiledData::Object::IsComponent && !object->isInlineComponent)
+ if (object->functionsAndExpressions->count == 0)
return true;
- for (auto it = object->inlineComponentsBegin(); it != object->inlineComponentsEnd(); ++it)
- compileComponent(it->objectIndex);
-
- if (object->functionsAndExpressions->count > 0) {
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
- if (hasError())
- return false;
-
- object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
- runtimeFunctionIndices);
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ functionsToCompile.reserve(object->functionsAndExpressions->count);
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe;
+ foe = foe->next) {
+ functionsToCompile << *foe;
}
- for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type < QV4::CompiledData::Binding::Type_Object)
- continue;
-
- int target = binding->value.objectIndex;
- int scope = binding->type == QV4::CompiledData::Binding::Type_Object ? target : scopeObjectIndex;
-
- if (!compileJavaScriptCodeInObjectsRecursively(binding->value.objectIndex, scope))
- return false;
- }
+ const auto runtimeFunctionIndices = generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ if (hasError())
+ return false;
+ object->runtimeFunctionIndices.allocate(document->jsParserEngine.pool(),
+ runtimeFunctionIndices);
return true;
}
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 99c1af6cbf..93e550a530 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -394,6 +394,10 @@ public:
int namedObjectsInComponentCount() const { return namedObjectsInComponent.size(); }
const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); }
+ bool hasFlag(QV4::CompiledData::Object::Flag flag) const { return flags & flag; }
+ qint32 objectId() const { return id; }
+ bool hasAliasAsDefaultProperty() const { return defaultPropertyIsAlias; }
+
private:
friend struct ::QQmlIRLoader;
@@ -591,9 +595,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen
// Returns mapping from input functions to index in IR::Module::functions / compiledData->runtimeFunctions
QVector<int> generateJSCodeForFunctionsAndBindings(const QList<CompiledFunctionOrExpression> &functions);
- bool generateCodeForComponents(const QVector<quint32> &componentRoots);
- bool compileComponent(int contextObject);
- bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
+ bool generateRuntimeFunctions(QmlIR::Object *object);
private:
Document *document;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index f7c4e2c98f..4f00131a09 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -3048,12 +3048,17 @@ bool Codegen::visit(ThisExpression *)
if (hasError())
return false;
- if (_context->isArrowFunction) {
- Reference r = referenceForName(QStringLiteral("this"), false);
- r.isReadonly = true;
- setExprResult(r);
- return false;
+ for (Context *parentContext = _context; parentContext; parentContext = parentContext->parent) {
+ if (parentContext->isArrowFunction) {
+ Reference r = referenceForName(QStringLiteral("this"), false);
+ r.isReadonly = true;
+ setExprResult(r);
+ return false;
+ }
+ if (parentContext->contextType != ContextType::Block)
+ break;
}
+
setExprResult(Reference::fromThis(this));
return false;
}
@@ -3158,6 +3163,17 @@ bool Codegen::visit(YieldExpression *ast)
return false;
}
+ auto innerMostCurentFunctionContext = _context;
+ while (innerMostCurentFunctionContext && innerMostCurentFunctionContext->contextType != ContextType::Function)
+ innerMostCurentFunctionContext = innerMostCurentFunctionContext->parent;
+
+ Q_ASSERT(innerMostCurentFunctionContext); // yield outside function would have been rejected by parser
+
+ if (!innerMostCurentFunctionContext->isGenerator) {
+ throwSyntaxError(ast->firstSourceLocation(), u"Yield is only valid in generator functions"_qs);
+ return false;
+ }
+
RegisterScope scope(this);
TailCallBlocker blockTailCalls(this);
Reference expr = ast->expression ? expression(ast->expression) : Reference::fromConst(this, Encode::undefined());
diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp
index 5511ed304a..fdb5fcb331 100644
--- a/src/qml/compiler/qv4compiler.cpp
+++ b/src/qml/compiler/qv4compiler.cpp
@@ -154,10 +154,7 @@ int QV4::Compiler::JSUnitGenerator::registerGetterLookup(const QString &name)
int QV4::Compiler::JSUnitGenerator::registerGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Getter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Getter, nameIndex);
return lookups.size() - 1;
}
@@ -168,49 +165,37 @@ int QV4::Compiler::JSUnitGenerator::registerSetterLookup(const QString &name)
int QV4::Compiler::JSUnitGenerator::registerSetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_Setter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_Setter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerGlobalGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_GlobalGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_GlobalGetter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerQmlContextPropertyGetterLookup(int nameIndex)
{
- CompiledData::Lookup l;
- l.type_and_flags = CompiledData::Lookup::Type_QmlContextPropertyGetter;
- l.nameIndex = nameIndex;
- lookups << l;
+ lookups << CompiledData::Lookup(CompiledData::Lookup::Type_QmlContextPropertyGetter, nameIndex);
return lookups.size() - 1;
}
int QV4::Compiler::JSUnitGenerator::registerRegExp(QQmlJS::AST::RegExpLiteral *regexp)
{
- CompiledData::RegExp re;
- re.stringIndex = registerString(regexp->pattern.toString());
-
- re.flags = 0;
+ quint32 flags = 0;
if (regexp->flags & QQmlJS::Lexer::RegExp_Global)
- re.flags |= CompiledData::RegExp::RegExp_Global;
+ flags |= CompiledData::RegExp::RegExp_Global;
if (regexp->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
- re.flags |= CompiledData::RegExp::RegExp_IgnoreCase;
+ flags |= CompiledData::RegExp::RegExp_IgnoreCase;
if (regexp->flags & QQmlJS::Lexer::RegExp_Multiline)
- re.flags |= CompiledData::RegExp::RegExp_Multiline;
+ flags |= CompiledData::RegExp::RegExp_Multiline;
if (regexp->flags & QQmlJS::Lexer::RegExp_Unicode)
- re.flags |= CompiledData::RegExp::RegExp_Unicode;
+ flags |= CompiledData::RegExp::RegExp_Unicode;
if (regexp->flags & QQmlJS::Lexer::RegExp_Sticky)
- re.flags |= CompiledData::RegExp::RegExp_Sticky;
+ flags |= CompiledData::RegExp::RegExp_Sticky;
- regexps.append(re);
+ regexps.append(CompiledData::RegExp(flags, registerString(regexp->pattern.toString())));
return regexps.size() - 1;
}
@@ -243,8 +228,7 @@ int QV4::Compiler::JSUnitGenerator::registerJSClass(const QStringList &members)
CompiledData::JSClassMember *member = reinterpret_cast<CompiledData::JSClassMember*>(jsClass + 1);
for (const auto &name : members) {
- member->nameOffset = registerString(name);
- member->isAccessor = false;
+ member->set(registerString(name), false);
++member;
}
@@ -432,9 +416,21 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
function->flags |= CompiledData::Function::IsArrowFunction;
if (irFunction->isGenerator)
function->flags |= CompiledData::Function::IsGenerator;
- function->nestedFunctionIndex =
- irFunction->returnsClosure ? quint32(module->functions.indexOf(irFunction->nestedContexts.first()))
- : std::numeric_limits<uint32_t>::max();
+ if (irFunction->returnsClosure)
+ function->flags |= CompiledData::Function::IsClosureWrapper;
+
+ if (!irFunction->returnsClosure
+ || irFunction->innerFunctionAccessesThis
+ || irFunction->innerFunctionAccessesNewTarget) {
+ // If the inner function does things with this and new.target we need to do some work in
+ // the outer function. Then we shouldn't directly access the nested function.
+ function->nestedFunctionIndex = std::numeric_limits<uint32_t>::max();
+ } else {
+ // Otherwise we can directly use the nested function.
+ function->nestedFunctionIndex
+ = quint32(module->functions.indexOf(irFunction->nestedContexts.first()));
+ }
+
function->length = irFunction->formals ? irFunction->formals->length() : 0;
function->nFormals = irFunction->arguments.size();
function->formalsOffset = currentOffset;
@@ -462,8 +458,7 @@ void QV4::Compiler::JSUnitGenerator::writeFunction(char *f, QV4::Compiler::Conte
currentOffset += function->nLabelInfos * sizeof(quint32);
}
- function->location.line = irFunction->line;
- function->location.column = irFunction->column;
+ function->location.set(irFunction->line, irFunction->column);
function->codeOffset = currentOffset;
function->codeSize = irFunction->code.size();
diff --git a/src/qml/compiler/qv4compiler_p.h b/src/qml/compiler/qv4compiler_p.h
index 5155c25c06..457c150b5e 100644
--- a/src/qml/compiler/qv4compiler_p.h
+++ b/src/qml/compiler/qv4compiler_p.h
@@ -125,7 +125,7 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT JSUnitGenerator {
int registerSetterLookup(int nameIndex);
int registerGlobalGetterLookup(int nameIndex);
int registerQmlContextPropertyGetterLookup(int nameIndex);
- int lookupNameIndex(int index) const { return lookups[index].nameIndex; }
+ int lookupNameIndex(int index) const { return lookups[index].nameIndex(); }
QString lookupName(int index) const { return stringForIndex(lookupNameIndex(index)); }
int registerRegExp(QQmlJS::AST::RegExpLiteral *regexp);
diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp
index 9dec968a91..7a558478dd 100644
--- a/src/qml/compiler/qv4compilerscanfunctions.cpp
+++ b/src/qml/compiler/qv4compilerscanfunctions.cpp
@@ -57,10 +57,7 @@ using namespace QQmlJS::AST;
static CompiledData::Location location(const QQmlJS::SourceLocation &astLocation)
{
- CompiledData::Location target;
- target.line = astLocation.startLine;
- target.column = astLocation.startColumn;
- return target;
+ return CompiledData::Location(astLocation.startLine, astLocation.startColumn);
}
@@ -382,8 +379,11 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
if (!_allowFuncDecls)
_cg->throwSyntaxError(expr->functionToken, QStringLiteral("conditional function or closure declaration"));
- if (!enterFunction(expr, /*enterName*/ true))
+ if (!enterFunction(expr, expr->identifierToken.length > 0
+ ? FunctionNameContext::Inner
+ : FunctionNameContext::None)) {
return false;
+ }
Node::accept(expr->formals, this);
Node::accept(expr->body, this);
leaveEnvironment();
@@ -399,7 +399,9 @@ bool ScanFunctions::visit(ExpressionStatement *ast)
bool ScanFunctions::visit(FunctionExpression *ast)
{
- return enterFunction(ast, /*enterName*/ false);
+ return enterFunction(ast, ast->identifierToken.length > 0
+ ? FunctionNameContext::Inner
+ : FunctionNameContext::None);
}
bool ScanFunctions::visit(ClassExpression *ast)
@@ -496,12 +498,12 @@ bool ScanFunctions::visit(ArrayPattern *ast)
return false;
}
-bool ScanFunctions::enterFunction(FunctionExpression *ast, bool enterName)
+bool ScanFunctions::enterFunction(FunctionExpression *ast, FunctionNameContext nameContext)
{
Q_ASSERT(_context);
if (_context->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
_cg->throwSyntaxError(ast->identifierToken, QStringLiteral("Function name may not be eval or arguments in strict mode"));
- return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName);
+ return enterFunction(ast, ast->name.toString(), ast->formals, ast->body, nameContext);
}
void ScanFunctions::endVisit(FunctionExpression *)
@@ -536,7 +538,7 @@ void ScanFunctions::endVisit(PatternProperty *)
bool ScanFunctions::visit(FunctionDeclaration *ast)
{
- return enterFunction(ast, /*enterName*/ true);
+ return enterFunction(ast, FunctionNameContext::Outer);
}
void ScanFunctions::endVisit(FunctionDeclaration *)
@@ -674,7 +676,9 @@ void ScanFunctions::endVisit(WithStatement *)
leaveEnvironment();
}
-bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParameterList *formals, StatementList *body, bool enterName)
+bool ScanFunctions::enterFunction(
+ Node *ast, const QString &name, FormalParameterList *formals, StatementList *body,
+ FunctionNameContext nameContext)
{
Context *outerContext = _context;
enterEnvironment(ast, ContextType::Function, name);
@@ -685,7 +689,7 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
if (outerContext) {
outerContext->hasNestedFunctions = true;
// The identifier of a function expression cannot be referenced from the enclosing environment.
- if (enterName) {
+ if (nameContext == FunctionNameContext::Outer) {
if (!outerContext->addLocalVar(name, Context::FunctionDefinition, VariableScope::Var, expr)) {
_cg->throwSyntaxError(ast->firstSourceLocation(), QStringLiteral("Identifier %1 has already been declared").arg(name));
return false;
@@ -711,8 +715,10 @@ bool ScanFunctions::enterFunction(Node *ast, const QString &name, FormalParamete
}
- if (!enterName && (!name.isEmpty() && (!formals || !formals->containsName(name))))
+ if (nameContext == FunctionNameContext::Inner
+ && (!name.isEmpty() && (!formals || !formals->containsName(name)))) {
_context->addLocalVar(name, Context::ThisFunctionName, VariableScope::Var);
+ }
_context->formals = formals;
if (body && !_context->isStrict)
diff --git a/src/qml/compiler/qv4compilerscanfunctions_p.h b/src/qml/compiler/qv4compilerscanfunctions_p.h
index 0336398cac..d2868fc428 100644
--- a/src/qml/compiler/qv4compilerscanfunctions_p.h
+++ b/src/qml/compiler/qv4compilerscanfunctions_p.h
@@ -83,15 +83,32 @@ public:
ScanFunctions(Codegen *cg, const QString &sourceCode, ContextType defaultProgramType);
void operator()(QQmlJS::AST::Node *node);
+ // see comment at its call site in generateJSCodeForFunctionsAndBindings
+ // for why this function is necessary
+ void handleTopLevelFunctionFormals(QQmlJS::AST::FunctionExpression *node) {
+ if (node && node->formals)
+ node->formals->accept(this);
+ }
+
void enterGlobalEnvironment(ContextType compilationMode);
void enterEnvironment(QQmlJS::AST::Node *node, ContextType compilationMode,
const QString &name);
void leaveEnvironment();
void enterQmlFunction(QQmlJS::AST::FunctionExpression *ast)
- { enterFunction(ast, false); }
+ { enterFunction(ast, FunctionNameContext::None); }
protected:
+ // Function declarations add their name to the outer scope, but not the
+ // inner scope. Function expressions add their name to the inner scope,
+ // unless the name is actually picked from the outer scope rather than
+ // given after the function token. QML functions don't add their name
+ // anywhere because the name is already recorded in the QML element.
+ // This enum is used to control the behavior of enterFunction().
+ enum class FunctionNameContext {
+ None, Inner, Outer
+ };
+
using Visitor::visit;
using Visitor::endVisit;
@@ -118,7 +135,8 @@ protected:
bool visit(QQmlJS::AST::FieldMemberExpression *) override;
bool visit(QQmlJS::AST::ArrayPattern *) override;
- bool enterFunction(QQmlJS::AST::FunctionExpression *ast, bool enterName);
+ bool enterFunction(QQmlJS::AST::FunctionExpression *ast,
+ FunctionNameContext nameContext);
void endVisit(QQmlJS::AST::FunctionExpression *) override;
@@ -161,7 +179,7 @@ protected:
protected:
bool enterFunction(QQmlJS::AST::Node *ast, const QString &name,
QQmlJS::AST::FormalParameterList *formals,
- QQmlJS::AST::StatementList *body, bool enterName);
+ QQmlJS::AST::StatementList *body, FunctionNameContext nameContext);
void calcEscapingVariables();
// fields:
diff --git a/src/qml/configure.cmake b/src/qml/configure.cmake
index 11c29620d6..a587a8fe1d 100644
--- a/src/qml/configure.cmake
+++ b/src/qml/configure.cmake
@@ -7,9 +7,12 @@
#### Libraries
-# special case begin
qt_find_package(LTTngUST PROVIDED_TARGETS LTTng::UST MODULE_NAME qml QMAKE_LIB lttng-ust)
-# special case end
+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 "")
+endif()
#### Tests
@@ -200,13 +203,9 @@ qt_feature("qml-xmllistmodel" PRIVATE
CONDITION QT_FEATURE_qml_itemmodel AND QT_FEATURE_future
)
-# special case begin
-qt_qml_find_python(__qt_qml_python_path __qt_qml_python_found)
-# special case end
-
qt_feature("qml-python" PRIVATE
LABEL "python"
- CONDITION __qt_qml_python_found # special case
+ CONDITION Python_Interpreter_FOUND
)
qt_configure_add_summary_section(NAME "Qt QML")
qt_configure_add_summary_entry(ARGS "qml-network")
diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp
index 58b8ea2c4f..0ca56f3a70 100644
--- a/src/qml/debugger/qqmldebug.cpp
+++ b/src/qml/debugger/qqmldebug.cpp
@@ -44,17 +44,26 @@
#include <private/qqmlengine_p.h>
#include <private/qv4compileddata_p.h>
+#include <atomic>
#include <cstdio>
QT_REQUIRE_CONFIG(qml_debug);
QT_BEGIN_NAMESPACE
+#if __cplusplus >= 202002L
+# define Q_ATOMIC_FLAG_INIT {}
+#else
+# define Q_ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT // deprecated in C++20
+#endif
+
+static std::atomic_flag s_printedWarning = Q_ATOMIC_FLAG_INIT;
+
QQmlDebuggingEnabler::QQmlDebuggingEnabler(bool printWarning)
{
- if (!QQmlEnginePrivate::qml_debugging_enabled && printWarning)
+ if (printWarning && !s_printedWarning.test_and_set(std::memory_order_relaxed))
fprintf(stderr, "QML debugging is enabled. Only use this in a safe environment.\n");
- QQmlEnginePrivate::qml_debugging_enabled = true;
+ QQmlEnginePrivate::qml_debugging_enabled.store(true, std::memory_order_relaxed);
}
/*!
diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp
index 74b10e64d7..a576cddf1a 100644
--- a/src/qml/debugger/qqmldebugconnector.cpp
+++ b/src/qml/debugger/qqmldebugconnector.cpp
@@ -111,7 +111,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance()
if (!params)
return nullptr;
- if (!QQmlEnginePrivate::qml_debugging_enabled) {
+ if (!QQmlEnginePrivate::qml_debugging_enabled.load(std::memory_order_relaxed)) {
if (!params->arguments.isEmpty()) {
qWarning().noquote() << QString::fromLatin1(
"QML Debugger: Ignoring \"-qmljsdebugger=%1\". Debugging "
diff --git a/src/qml/debugger/qqmldebugconnector_p.h b/src/qml/debugger/qqmldebugconnector_p.h
index d1ad90adfd..4f7b013160 100644
--- a/src/qml/debugger/qqmldebugconnector_p.h
+++ b/src/qml/debugger/qqmldebugconnector_p.h
@@ -65,6 +65,7 @@ QT_BEGIN_NAMESPACE
class Q_QML_PRIVATE_EXPORT QQmlDebugConnector
{
+ virtual ~QQmlDebugConnector() = default; // don't break 'override' on ~QQmlDebugServer
public:
static QQmlDebugConnector *instance() { return nullptr; }
diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp
new file mode 100644
index 0000000000..5119fc4209
--- /dev/null
+++ b/src/qml/debugger/qqmldebugserver.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmldebugserver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlDebugServer::~QQmlDebugServer()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmldebugserver_p.cpp"
diff --git a/src/qml/debugger/qqmldebugserver_p.h b/src/qml/debugger/qqmldebugserver_p.h
index e848b00bda..c99155051c 100644
--- a/src/qml/debugger/qqmldebugserver_p.h
+++ b/src/qml/debugger/qqmldebugserver_p.h
@@ -62,6 +62,7 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugServer : public QQmlDebugConnector
{
Q_OBJECT
public:
+ ~QQmlDebugServer() override;
virtual void setDevice(QIODevice *socket) = 0;
};
diff --git a/src/qml/debugger/qqmldebugserviceinterfaces_p.h b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
index 5d58e4d2e0..d01e472edb 100644
--- a/src/qml/debugger/qqmldebugserviceinterfaces_p.h
+++ b/src/qml/debugger/qqmldebugserviceinterfaces_p.h
@@ -108,7 +108,6 @@ class QQmlEngineControlService {};
class QQmlNativeDebugService {};
class QQmlDebugTranslationService {
public:
- virtual QString foundElidedText(QObject *, const QString &, const QString &) {return {};}
virtual void foundTranslationBinding(const TranslationBindingInformation &) {}
};
@@ -186,7 +185,6 @@ class Q_QML_PRIVATE_EXPORT QQmlDebugTranslationService : public QQmlDebugService
public:
static const QString s_key;
- virtual QString foundElidedText(QObject *qQuickTextObject, const QString &layoutText, const QString &elideText) = 0;
virtual void foundTranslationBinding(const TranslationBindingInformation &translationBindingInformation) = 0;
protected:
friend class QQmlDebugConnector;
diff --git a/src/qml/debugger/qqmldebugtranslationprotocol_p.h b/src/qml/debugger/qqmldebugtranslationprotocol_p.h
index 467b34d509..06d3850510 100644
--- a/src/qml/debugger/qqmldebugtranslationprotocol_p.h
+++ b/src/qml/debugger/qqmldebugtranslationprotocol_p.h
@@ -64,19 +64,23 @@ enum class Request {
ChangeLanguage = 1,
StateList,
ChangeState,
- MissingTranslations,
+ TranslationIssues,
TranslatableTextOccurrences,
WatchTextElides,
DisableWatchTextElides,
+ // following are obsolete, just provided for compilation compatibility
+ MissingTranslations
};
enum class Reply {
LanguageChanged = 101,
StateList,
StateChanged,
- MissingTranslations,
+ TranslationIssues,
TranslatableTextOccurrences,
- TextElided,
+ // following are obsolete, just provided for compilation compatibility
+ MissingTranslations,
+ TextElided
};
inline QByteArray createChangeLanguageRequest(QDataStream &packet, const QUrl &url,
@@ -98,6 +102,12 @@ inline QByteArray createMissingTranslationsRequest(QDataStream &packet)
return qobject_cast<QBuffer *>(packet.device())->data();
}
+inline QByteArray createTranslationIssuesRequest(QDataStream &packet)
+{
+ packet << Request::TranslationIssues;
+ return qobject_cast<QBuffer *>(packet.device())->data();
+}
+
inline QByteArray createTranslatableTextOccurrencesRequest(QDataStream &packet)
{
packet << Request::TranslatableTextOccurrences;
@@ -210,7 +220,7 @@ public:
>> qmlElement.propertyName >> qmlElement.translationId >> qmlElement.translatedText
>> qmlElement.fontFamily >> qmlElement.fontPointSize >> qmlElement.fontPixelSize
>> qmlElement.fontStyleName >> qmlElement.horizontalAlignment
- >> qmlElement.verticalAlignment;
+ >> qmlElement.verticalAlignment >> qmlElement.stateName;
}
friend QDataStream &operator<<(QDataStream &stream, const QmlElement &qmlElement)
@@ -220,7 +230,7 @@ public:
<< qmlElement.translatedText << qmlElement.fontFamily
<< qmlElement.fontPointSize << qmlElement.fontPixelSize
<< qmlElement.fontStyleName << qmlElement.horizontalAlignment
- << qmlElement.verticalAlignment;
+ << qmlElement.verticalAlignment << qmlElement.stateName;
}
CodeMarker codeMarker;
@@ -232,10 +242,12 @@ public:
QString elementId;
QString elementType;
qreal fontPointSize = 0.0;
+ QString stateName;
int fontPixelSize = 0;
int horizontalAlignment = 0;
int verticalAlignment = 0;
};
+
class QmlState
{
public:
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index f7dc326def..9e2ba98ca4 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -176,7 +176,7 @@ public:
RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url,
const QV4::CompiledData::Object *obj, const QString &type)
- : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
+ : Location(QQmlSourceLocation(type, obj->location.line(), obj->location.column()), url),
locationType(Creating), sent(false)
{
unit = ref;
diff --git a/src/qml/doc/qtqml.qdocconf b/src/qml/doc/qtqml.qdocconf
index b2f2c0cb77..820e7c67d2 100644
--- a/src/qml/doc/qtqml.qdocconf
+++ b/src/qml/doc/qtqml.qdocconf
@@ -65,5 +65,3 @@ manifestmeta.thumbnail.names += "QtQml/Chapter 4*" \
navigation.landingpage = "Qt QML"
navigation.cppclassespage = "Qt QML C++ Classes"
navigation.qmltypespage = "Qt QML QML Types"
-
-macro.versionlessNote = "If \\l{Versionless commands}{versionless commands} are disabled, use \\c{\1} instead. It supports the same set of arguments as this command."
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt b/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt
new file mode 100644
index 0000000000..d33f009e38
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.19)
+project(qt_target_qml_sources_snippet)
+
+set(CMAKE_AUTOMOC TRUE)
+set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+
+# ![0]
+set_source_files_properties(nested/way/down/File.qml PROPERTIES
+ QT_RESOURCE_ALIAS File.qml
+)
+set_source_files_properties(TemplateFile.qml PROPERTIES
+ QT_RESOURCE_ALIAS templates/File.qml
+ QT_QML_SKIP_QMLDIR_ENTRY TRUE
+ QT_QML_SKIP_QMLLINT TRUE
+ QT_QML_SKIP_CACHEGEN TRUE
+)
+set_source_files_properties(FunnySingleton.qml PROPERTIES
+ QT_QML_SINGLETON_TYPE TRUE
+)
+qt_add_qml_module(qt_target_qml_sources_example
+ URI Example
+ VERSION 2.3
+ RESOURCE_PREFIX /my.company.com/imports
+ QML_FILES
+ nested/way/down/File.qml
+ TemplateFile.qml
+ FunnySingleton.qml
+)
+
+set_source_files_properties(some_old_thing.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "1.1;2.0"
+ QT_QML_SOURCE_TYPENAME OldThing
+)
+set_source_files_properties(../../../images/button-types.png PROPERTIES
+ QT_RESOURCE_ALIAS button-types.png
+)
+qt_target_qml_sources(qt_target_qml_sources_example
+ QML_FILES some_old_thing.qml
+ RESOURCES
+ ../../../images/button-types.png
+ doc/README.txt
+)
+# ![0]
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml
new file mode 100644
index 0000000000..4aec01c32d
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/FunnySingleton.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [0]
+pragma Singleton
+import QtQml
+
+QtObject {}
+//! [0]
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/TemplateFile.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt b/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt
new file mode 100644
index 0000000000..52d51e034d
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/doc/README.txt
@@ -0,0 +1 @@
+Dummy file, contents not important.
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/nested/way/down/File.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml b/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml
new file mode 100644
index 0000000000..8fc36a40da
--- /dev/null
+++ b/src/qml/doc/snippets/cmake/qt_target_qml_sources/some_old_thing.qml
@@ -0,0 +1,3 @@
+import QtQml
+
+QtObject {}
diff --git a/src/qml/doc/snippets/code/doc_src_qtqml.cmake b/src/qml/doc/snippets/code/doc_src_qtqml.cmake
index c2e5d3d9d2..c312201ff8 100644
--- a/src/qml/doc/snippets/code/doc_src_qtqml.cmake
+++ b/src/qml/doc/snippets/code/doc_src_qtqml.cmake
@@ -1,4 +1,4 @@
#! [0]
-find_package(Qt6 COMPONENTS Qml REQUIRED)
+find_package(Qt6 REQUIRED COMPONENTS Qml)
target_link_libraries(mytarget PRIVATE Qt6::Qml)
#! [0]
diff --git a/src/qml/doc/snippets/qml/CMakeLists.txt b/src/qml/doc/snippets/qml/CMakeLists.txt
new file mode 100644
index 0000000000..24e775341f
--- /dev/null
+++ b/src/qml/doc/snippets/qml/CMakeLists.txt
@@ -0,0 +1,11 @@
+qt_add_library(extra_module STATIC)
+qt_add_qml_module(extra_module
+ URI "ExtraModule"
+ VERSION 1.0
+ QML_FILES
+ Extra.qml
+ SOURCES
+ extrathing.cpp extrathing.h
+)
+
+add_subdirectory(ExtraModule)
diff --git a/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt b/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt
new file mode 100644
index 0000000000..3e5cbd4565
--- /dev/null
+++ b/src/qml/doc/snippets/qml/MajorProject-CMakeLists.txt
@@ -0,0 +1,23 @@
+
+set_source_files_properties(Thing.qml
+ PROPERTIES
+ QT_QML_SOURCE_VERSIONS "1.4;2.0;3.0"
+)
+
+set_source_files_properties(OtherThing.qml
+ PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;3.0"
+)
+
+qt_add_qml_module(my_module
+ URI MyModule
+ VERSION 3.2
+ PAST_MAJOR_VERSIONS
+ 1 2
+ QML_FILES
+ Thing.qml
+ OtherThing.qml
+ OneMoreThing.qml
+ SOURCES
+ everything.cpp everything.h
+)
diff --git a/src/qml/doc/snippets/qml/createQmlObject.qml b/src/qml/doc/snippets/qml/createQmlObject.qml
index 8a082a71de..bfb1d98ca8 100644
--- a/src/qml/doc/snippets/qml/createQmlObject.qml
+++ b/src/qml/doc/snippets/qml/createQmlObject.qml
@@ -58,9 +58,18 @@ Rectangle {
function createIt() {
//![0]
-var newObject = Qt.createQmlObject('import QtQuick 2.0; Rectangle {color: "red"; width: 20; height: 20}',
- parentItem,
- "dynamicSnippet1");
+const newObject = Qt.createQmlObject(`
+ import QtQuick 2.0
+
+ Rectangle {
+ color: "red"
+ width: 20
+ height: 20
+ }
+ `,
+ parentItem,
+ "myDynamicSnippet"
+);
//![0]
//![destroy]
diff --git a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
index 86c3e078c8..1326b8c87a 100644
--- a/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
+++ b/src/qml/doc/snippets/qml/integrating-javascript/includejs/script.mjs
@@ -50,8 +50,9 @@
//![0]
// script.mjs
import { factorial } from "factorial.mjs"
+export { factorial }
-function showCalculations(value) {
+export function showCalculations(value) {
console.log(
"Call factorial() from script.js:",
factorial(value));
diff --git a/src/qml/doc/snippets/qml/myProject-CMakeLists.txt b/src/qml/doc/snippets/qml/myProject-CMakeLists.txt
new file mode 100644
index 0000000000..49c63a1513
--- /dev/null
+++ b/src/qml/doc/snippets/qml/myProject-CMakeLists.txt
@@ -0,0 +1,13 @@
+qt_add_executable(main_program main.cpp)
+
+qt_add_qml_module(main_program
+ VERSION 1.0
+ URI myProject
+ QML_FILES
+ main.qml
+ SOURCES
+ onething.cpp onething.h
+
+)
+
+target_link_libraries(main_program PRIVATE extra_moduleplugin)
diff --git a/src/qml/doc/snippets/qml/myimageprovider.txt b/src/qml/doc/snippets/qml/myimageprovider.txt
new file mode 100644
index 0000000000..4605734398
--- /dev/null
+++ b/src/qml/doc/snippets/qml/myimageprovider.txt
@@ -0,0 +1,15 @@
+qt_add_qml_module(imageproviderplugin
+ VERSION 1.0
+ URI "ImageProvider"
+ PLUGIN_TARGET imageproviderplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ CLASS_NAME ImageProviderExtensionPlugin
+ QML_FILES
+ AAA.qml
+ BBB.qml
+ SOURCES
+ moretypes.cpp moretypes.h
+ myimageprovider.cpp myimageprovider.h
+ plugin.cpp
+)
diff --git a/src/qml/doc/snippets/qml/plugin.cpp.txt b/src/qml/doc/snippets/qml/plugin.cpp.txt
new file mode 100644
index 0000000000..02d1112a4a
--- /dev/null
+++ b/src/qml/doc/snippets/qml/plugin.cpp.txt
@@ -0,0 +1,14 @@
+#include <myimageprovider.h>
+#include <QtQml/qqmlextensionplugin.h>
+
+class ImageProviderExtensionPlugin : public QQmlEngineExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlEngineExtensionInterface_iid)
+public:
+ void initializeEngine(QQmlEngine *engine, const char *uri) final
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("myimg", new MyImageProvider);
+ }
+};
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp
new file mode 100644
index 0000000000..0064d66a5c
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//! [qjs-as-container]
+
+ class Cache : public QObject
+ {
+ Q_OBJECT
+ QML_ELEMENT
+
+ public:
+ Q_INVOKABLE QJSValue lookup(const QString &key) {
+ if (auto it = m_cache.constFind(key); it != m_cache.constEnd()) {
+ return *it; // impicit conversion
+ } else {
+ return QJSValue::UndefinedValue; // implicit conversion
+ }
+ }
+
+ QHash<QString, QString> m_cache;
+ }
+
+//! [qjs-as-container]
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp
new file mode 100644
index 0000000000..59ee30c25f
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/exampleqjsengine.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![qjs-engine-example]
+
+ QJSEngine engine;
+ // We create an object with a read-only property whose getter throws an exception
+ auto val = engine.evaluate("let o = { get f() {throw 42;} }; o");
+ val.property("f");
+ qDebug() << engine.hasError(); // prints false
+
+ // This time, we construct a QJSManagedValue before accessing the property
+ val = engine.evaluate("let o = { get f() {throw 42;} }; o");
+ QJSManagedValue managed(std::move(val), &engine);
+ managed.property("f");
+ qDebug() << engine.hasError(); // prints true
+
+ QJSValue error = engine.catchError();
+ Q_ASSERT(error.toInt(), 42);
+
+//![qjs-engine-example]
diff --git a/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp
new file mode 100644
index 0000000000..e8622b2c50
--- /dev/null
+++ b/src/qml/doc/snippets/qtjavascript/integratingjswithcpp/qjsengine.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![qjs-engine]
+
+ QJSEngine engine;
+ QJSValue object = engine.newObject();
+ object.setProperty("num", 42);
+ QJSValue function = engine.evaluate("(o) => o.num *= 2 ");
+ QJSValueList args = { object };
+ QJSValue result = function.call(args);
+ QJSValue expected = "84";
+ Q_ASSERT(result.equals(expected) && !result.strictlyEquals(expected));
+
+//![qjs-engine]
+
diff --git a/src/qml/doc/src/cmake/cmake-properties.qdoc b/src/qml/doc/src/cmake/cmake-properties.qdoc
new file mode 100644
index 0000000000..eccc815eca
--- /dev/null
+++ b/src/qml/doc/src/cmake/cmake-properties.qdoc
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\group cmake-source-file-properties-qtqml
+\title CMake Source File Properties in Qt6 Qml
+
+\l{CMake Commands in Qt6 Qml}{CMake Commands} know about the following CMake
+source file properties:
+
+\sa{CMake Property Reference}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_INTERNAL_TYPE.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_INTERNAL_TYPE
+\target cmake-source-file-property-QT_QML_INTERNAL_TYPE
+
+\summary {Marks a QML file as providing an internal type.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to indicate that the \c{.qml} file provides an internal type.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SINGLETON_TYPE.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SINGLETON_TYPE
+\target cmake-source-file-property-QT_QML_SINGLETON_TYPE
+
+\summary {Marks a QML file as providing a singleton type.}
+
+\cmakepropertysince 6.2
+
+A \c{.qml} file that provides a singleton type needs to have its \c QT_QML_SINGLETON_TYPE source
+property set to \c TRUE to ensure that the singleton command is written into the
+\l{Module Definition qmldir Files}{qmldir} file.
+This must be done in addition to the QML file containing the \c {pragma Singleton} statement.
+
+See \l{qt_target_qml_sources_example}{qt_target_qml_sources()} for an example on
+how to set the \c QT_QML_SINGLETON_TYPE property.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SKIP_CACHEGEN.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_CACHEGEN
+\target cmake-source-file-property-QT_QML_SKIP_CACHEGEN
+
+\summary {Excludes a file from being compiled to byte code.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent the \c{.qml} file from being compiled to byte code.
+The file will still be added to the \c target as a resource in uncompiled form
+(see \l{qmlcachegen-auto}{Caching compiled QML sources}).
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SKIP_QMLDIR_ENTRY.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_QMLDIR_ENTRY
+\target cmake-source-file-property-QT_QML_SKIP_QMLDIR_ENTRY
+
+\summary {Excludes a file from being added as a type to the QML module's typeinfo file.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent
+the \c{.qml} file from being added as a type to the QML module's typeinfo file
+(see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and typeinfo files}).
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SKIP_QMLLINT.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SKIP_QMLLINT
+\target cmake-source-file-property-QT_QML_SKIP_QMLLINT
+
+\summary {Prevents a file from being included in automatic qmllint processing.}
+
+\cmakepropertysince 6.2
+
+Set this property to \c TRUE to prevent the file from being included in
+\l{qmllint-auto}{automatic qmllint processing}.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SOURCE_TYPENAME.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SOURCE_TYPENAME
+\target cmake-source-file-property-QT_QML_SOURCE_TYPENAME
+
+\summary {Overrides the type name provided by the file.}
+
+\cmakepropertysince 6.2
+
+Use this property to override the \c QML type name provided by this file.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QML_SOURCE_VERSIONS.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QML_SOURCE_VERSIONS
+\target cmake-source-file-property-QT_QML_SOURCE_VERSIONS
+
+\summary {Specifies a custom set of versions for a type.}
+
+\cmakepropertysince 6.2
+
+When the file needs to provide type entries for a custom set of versions,
+for example when the QML types were first introduced in a minor patch
+version after the \c{.0} release, specify those versions using this property.
+
+\sa{qml-source-file-properties}{qt_target_qml_sources}
+*/
+
+
+/*!
+\page cmake-source-file-property-QT_QMLTC_FILE_BASENAME.html
+\ingroup cmake-source-file-properties-qtqml
+
+\title QT_QMLTC_FILE_BASENAME
+\target cmake-source-file-property-QT_QMLTC_FILE_BASENAME
+
+\summary {Specifies a non-default .h and .cpp file name.}
+
+\cmakepropertysince 6.3
+\preliminarycmakeproperty
+
+Use this property to specify a non-default \c .h and \c .cpp file name, which helps to resolve
+conflicting file names.
+
+\sa{qt_target_compile_qml_to_cpp}
+*/
diff --git a/src/qml/doc/src/cmake/cmake-variables.qdoc b/src/qml/doc/src/cmake/cmake-variables.qdoc
index 901ce26e91..8f5b87b1cb 100644
--- a/src/qml/doc/src/cmake/cmake-variables.qdoc
+++ b/src/qml/doc/src/cmake/cmake-variables.qdoc
@@ -37,18 +37,34 @@
The \l{qt6_add_qml_module}{qt6_add_qml_module()} command accepts an
\c OUTPUT_DIRECTORY argument which specifies where the QML module's \c qmldir
-file, typeinfo file and plugin library will be created. By default, the current
-binary directory (\c CMAKE_CURRENT_BINARY_DIR) is used if that argument is not
-provided. When a set of QML modules are being defined, it may be convenient to
-have them all generated under a common point in the build directory. If the
-source directory structure doesn't match the URI structure of the QML modules,
-or if you just want your QML modules to be collected under a different
-location, the \c QT_QML_OUTPUT_DIRECTORY can be used. When set, the default
-changes to the concatenation of \c QT_QML_OUTPUT_DIRECTORY and the QML module's
-\e{target path}, which is based on the module URI. \c QT_QML_OUTPUT_DIRECTORY
-will also be added to the import path of the \c qmllint and \c qmlcachegen
-tooling targets, allowing them to find other QML modules under the same base
-location.
+file, typeinfo file and plugin library will be created. When that argument is
+not used, the default value is based on the \c QT_QML_OUTPUT_DIRECTORY variable,
+if it is set. If \c QT_QML_OUTPUT_DIRECTORY is not set, the default value
+depends on the type of backing target (see the
+\l{qt6_add_qml_module#OUTPUT_DIRECTORY}{OUTPUT_DIRECTORY} documentation for
+details).
+
+When \c QT_QML_OUTPUT_DIRECTORY is set, the default output directory will be
+formed by appending the QML module's \e{target path} (which is based on the
+module URI) to \c QT_QML_OUTPUT_DIRECTORY.
+The \c QT_QML_OUTPUT_DIRECTORY will also be added to the import path of the
+\c qmllint and \c qmlcachegen tooling targets, allowing them to find other QML
+modules under the same base location. This allows the project to use a source
+directory structure that doesn't exactly match the URI structure of the QML
+modules, or to merge sets of QML modules under a common base point.
+
+When building QML modules for Android, \c QT_QML_OUTPUT_DIRECTORY is set to
+\c{${CMAKE_BINARY_DIR}/android-qml} by default. The Android deployment routine
+uses this directory to locate the required QML modules in the build tree.
+The output directory of a QML module can also be set for a project or for each
+QML module target by the user and it can therefore differ from the Android
+default directory. In this case, to successfully deploy the executable on
+Android, the \e{target path} of the QML module must be based on the module URI.
+Also, the \l{cmake-target-property-QT_QML_IMPORT_PATH}{QT_QML_IMPORT_PATH}
+property of the executable target must contain the import paths of all QML
+modules that are built in the project tree, have a custom output directory,
+and are used by the executable target. This behavior will likely change in
+a future Qt version due to improvements in the build system implementation.
*/
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 4c3655651b..b81a0c80ea 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_module.qdoc
@@ -34,6 +34,8 @@
\brief Defines a QML module.
+\cmakecommandsince 6.2
+
\section1 Synopsis
\badcode
@@ -54,8 +56,10 @@ qt_add_qml_module(
[IMPORT_PATH ...]
[SOURCES ...]
[QML_FILES ...]
+ [RESOURCES ...]
[OUTPUT_TARGETS out_targets_var]
[DESIGNER_SUPPORTED]
+ [NO_PLUGIN]
[NO_PLUGIN_OPTIONAL]
[NO_CREATE_PLUGIN_TARGET]
[NO_GENERATE_PLUGIN_SOURCE]
@@ -63,11 +67,15 @@ qt_add_qml_module(
[NO_GENERATE_QMLDIR]
[NO_LINT]
[NO_CACHEGEN]
+ [NO_RESOURCE_TARGET_PATH]
)
\endcode
-\versionlessNote qt6_add_qml_module()
+\versionlessCMakeCommandsNote qt6_add_qml_module()
+
+See \l {Building a QML application} and \l {Building a reusable QML module}
+for examples that define QML modules.
\section1 Description
@@ -90,6 +98,22 @@ first command argument. C++ sources, \c{.qml} files, and resources should all
be added to the backing target. The backing target is a library that should be
installed in the same location as any other library defined by the project.
+The source directory structure under which the backing target is created should
+match the target path of the QML module (the target path is the module's URI
+with dots replaced by forward slashes). If the source directory structure
+doesn't match the target path, \c{qt_add_qml_module()} will issue a warning.
+
+The following example shows a suitable source directory structure for a QML
+module with a URI of \c{MyThings.Panels}. The call to \c{qt_add_qml_module()}
+would be in the \c{CMakeLists.txt} file shown.
+
+\badcode
+src
+ +-- MyThings
+ +-- Panels
+ +-- CMakeLists.txt
+\endcode
+
A separate \e plugin target is associated with the QML module. It is used at
runtime to load the module dynamically when the application doesn't already
link to the backing target. The plugin target will also be a library and is
@@ -106,6 +130,10 @@ For cases where the QML module needs a custom plugin class implementation, the
\l{NO_GENERATE_PLUGIN_SOURCE} and usually the \l{NO_PLUGIN_OPTIONAL} options
will be needed.
+\note
+When using static linking, it migt be necessary to use
+\c Q_IMPORT_QML_PLUGIN to ensure that the QML plugin is correctly linked.
+
\section3 Plugin target with no backing target
A QML module can be defined with the plugin target serving as its own backing
@@ -128,11 +156,16 @@ load-time performance.
\section3 Executable as a QML module
An executable target can act as a backing target for a QML module. In this case,
-there should be no need for a plugin library, since the QML module will always
-be loaded directly as part of the application. The \c{qt_add_qml_module()}
-command will detect when an executable is used as the backing target and will
-automatically disable the creation of a separate plugin. Do not use any of the
-options with \c{PLUGIN} in their name when using this arrangement.
+there will be no plugin library, since the QML module will always be loaded
+directly as part of the application. The \c{qt_add_qml_module()} command will
+detect when an executable is used as the backing target and will automatically
+disable the creation of a separate plugin. Do not use any of the options with
+\c{PLUGIN} in their name when using this arrangement.
+
+When an executable is used as the backing target, the source directory structure
+is not expected to match the QML module's target path.
+See \l{qmlcachegen-auto}{Caching compiled QML sources} for additional target
+path differences for compiled-in resources.
\target qmldir-autogeneration
@@ -146,19 +179,27 @@ The \l OUTPUT_DIRECTORY argument determines where the \c qmldir and typeinfo
files will be written to. If the QML module has a plugin, that plugin will also
be created in the same directory as the \c qmldir file.
-In static builds, the backing target's \c{.qml} files will be scanned during
-the CMake configure run to determine the imports used by the module and set up
-linking relationships. When a \c{.qml} file is added to or removed from the
-module, CMake will normally re-run automatically and the relevant files will be
-re-scanned, since a \c{CMakeLists.txt} file will have been modified. During the
-course of development, an existing \c{.qml} file may add or remove an import or
-a type. On its own, this would not cause CMake to re-run automatically, so you
-should explicitly re-run CMake to force the \c qmldir file to be regenerated
-and any linking relationships to be updated.
+If using a statically built Qt, the backing target's \c{.qml} files will be
+scanned during the CMake configure run to determine the imports used by the
+module and set up linking relationships. When a \c{.qml} file is added to or
+removed from the module, CMake will normally re-run automatically and the
+relevant files will be re-scanned, since a \c{CMakeLists.txt} file will have
+been modified. During the course of development, an existing \c{.qml} file may
+add or remove an import or a type. On its own, this would not cause CMake to
+re-run automatically, so you should explicitly re-run CMake to force the
+\c qmldir file to be regenerated and any linking relationships to be updated.
The backing target's C++ sources are scanned at build time to generate a
typeinfo file and a C++ file to register the associated types. The generated
C++ file is automatically added to the backing target as a source.
+This requires \c AUTOMOC to be enabled on the target. The project is
+responsible for ensuring this, usually by setting the \c CMAKE_AUTOMOC variable
+to \c TRUE before calling \c qt_add_qml_module(), or by passing in an existing
+target with the \c AUTOMOC target property already set to \c TRUE. It isn't an
+error to have \c AUTOMOC disabled on the target, but the project is then
+responsible for handling the consequences. This may include having to manually
+generate the typeinfo file instead of allowing it to be auto-generated with
+missing details, and adding C++ code to register the types.
Projects should prefer to use the auto-generated typeinfo and \c qmldir files
where possible. They are easier to maintain and they don't suffer from the same
@@ -183,7 +224,7 @@ may still be needed in certain situations by the QML engine.
The resource path of each file is determined by its path relative to the
current source directory (\c CMAKE_CURRENT_SOURCE_DIR). This resource path is
appended to a prefix formed by concatenating the \l{RESOURCE_PREFIX} and
-the target path (which is the URI with dots replaced with forward slashes).
+the target path (but see \l NO_RESOURCE_TARGET_PATH for an exception to this).
Ordinarily, the project should aim to place \c{.qml} files in
the same relative location as they would have in the resources. If the \c{.qml}
file is in a different relative directory to its desired resource path, its
@@ -220,17 +261,39 @@ found at the following resource paths:
A separate linting target will be automatically created if any \c{.qml} files
are added to the module via the \c QML_FILES keyword, or by a later call to
\l{qt6_target_qml_sources}{qt_target_qml_sources()}. The name of the linting
-target will be the \c target followed by \c{_qmllint}. The linting target is
-not part of the default CMake \c ALL target, it is intended for developers to
-execute manually on demand.
+target will be the \c target followed by \c{_qmllint}. An \c{all_qmllint}
+target which depends on all the individual \c{*_qmllint} targets is also
+provided as a convenience.
+
+\target qml-naming-js-files
+\section2 Naming conventions for \c{.js} files
+
+JavaScript file names that are intended to be addressed as components should
+start with an uppercase letter.
+
+Alternatively, you may use lowercase file names and set the source file
+property
+\l{cmake-source-file-property-QT_QML_SOURCE_TYPENAME}{QT_QML_SOURCE_TYPE_NAME}
+to the desired type name.
+
+\target qml-cmake-singletons
+\section2 Singletons
+
+If a QML module has \c{.qml} files which provide singleton types, these files
+need to have their \c QT_QML_SINGLETON_TYPE source property set to \c TRUE, to
+ensure that the \singleton command is written into the
+\l{Module Definition qmldir Files}{qmldir} file. This must be done in addition
+to the QML file containing the \c {pragma Singleton} statement.
+
+See \l{qt_target_qml_sources_example}{qt_target_qml_sources()} for an example on
+how to set the \c QT_QML_SINGLETON_TYPE property.
\section1 Arguments
The \c target specifies the name of the backing target for the QML module.
-By default, it will be created as a shared library if CMake's
-\c BUILD_SHARED_LIBS variable is set to true, or as a static library otherwise.
-This choice can be explicitly overridden with the \c STATIC or \c SHARED
-options.
+By default, it is created as a shared library if Qt was built as shared
+libraries, or as a static library otherwise. This choice can be explicitly
+overridden with the \c STATIC or \c SHARED options.
The plugin target associated with the QML module can be specified using the
\c PLUGIN_TARGET argument. The \c PLUGIN_TARGET can be the same as the backing
@@ -246,18 +309,28 @@ change the plugin's output name by setting target properties like
The backing \c target and the plugin target (if different) will be created by
the command, unless they already exist. Projects should generally let them be
created by the command so that they are created as the appropriate target type.
-If an existing \c target is passed in and it is an executable target, then no
-plugin target will be created or used.
+If the backing \c target is a static library, the plugin will also be created
+as a static library. If the backing \c target is a shared library, the plugin
+will be created as a module library. If an existing \c target is passed in and
+it is an executable target, there will be no plugin. If you intend to always
+link directly to the backing target and do not need a plugin, it can be
+disabled by adding the \c NO_PLUGIN option. Specifying both \c NO_PLUGIN and
+\c PLUGIN_TARGET is an error.
In certain situations, the project may want to delay creating the plugin target
until after the call. The \c NO_CREATE_PLUGIN_TARGET option can be given in
that situation. The project is then expected to call
\l{qt6_add_qml_plugin}{qt_add_qml_plugin()} on the plugin target once it has
-been created.
+been created. When \c NO_CREATE_PLUGIN_TARGET is given, \c PLUGIN_TARGET must
+also be provided to explicitly name the plugin target.
Every QML module must define a \c URI. It should be specified in dotted URI
-notation, such as \c{QtQuick.Layouts}. It must not contain anything other than
-alphanumeric or dot characters. Other QML modules may use this name in
+notation, such as \c{QtQuick.Layouts}. Each segment must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments
+must not start with a number and they must not contain \e{-} (minus)
+characters. As the \c URI will be translated into directory names, you
+should restrict it to alphanumeric characters of the latin alphabet,
+underscores, and dots. Other QML modules may use this name in
\l{qtqml-syntax-imports.html}{import statements} to import the module. The
\c URI will be used in the \c module line of the generated
\l{Module Definition qmldir Files}{qmldir} file. The \c URI is also used to
@@ -267,10 +340,26 @@ A QML module must also define a \c VERSION in the form \c{Major.Minor}, where
both \c Major and \c Minor must be integers. An additional \c{.Patch}
component may be appended, but will be ignored. A list of earlier major
versions the module provides types for can also optionally be given after the
-\c PAST_MAJOR_VERSIONS keyword.
+\c PAST_MAJOR_VERSIONS keyword (see below).
See \l{qtqml-modules-identifiedmodules.html}{Identified Modules} for further
in-depth discussion of the module URI and version numbering.
+A list of additional major versions the module provides may be given using the
+\c PAST_MAJOR_VERSIONS keyword. For each of those versions and each QML file
+without a \c QT_QML_SOURCE_VERSIONS setting an additional entry in the
+\l{Module Definition qmldir Files}{qmldir} file will be generated to specify
+the extra version. Furthermore, the generated module registration code will
+register the past major versions using \l{qmlRegisterModule()} on the C++ side.
+The module registration code is automatically generated for your QML module,
+unless you specify \c{NO_GENERATE_QMLTYPES} (but use of this option is strongly
+discouraged). Usage of \c PAST_MAJOR_VERSIONS adds some overhead when your
+module is imported. You should increment the major version of your module as
+rarely as possible. Once you can rely on all QML files importing this module to
+omit the version in their imports, you can safely omit \c{PAST_MAJOR_VERSIONS}.
+All the QML files will then import the latest version of your module. If you
+have to support versioned imports, consider supporting only a limited number of
+past major versions.
+
\target RESOURCE_PREFIX
\c RESOURCE_PREFIX is intended to encapsulate a namespace for the project and
will often be the same for all QML modules that the project defines. It should
@@ -287,20 +376,37 @@ qt_add_qml_module(someTarget
)
\endcode
+\target NO_RESOURCE_TARGET_PATH
+When various files are added to the compiled-in resources, they are placed
+under a path formed by concatenating the \c RESOURCE_PREFIX and the target path.
+For the special case where the backing target is an executable, it may be
+desirable to place the module's \c{.qml} files and other resources directly
+under the \c RESOURCE_PREFIX instead. This can be achieved by specifying the
+\c NO_RESOURCE_TARGET_PATH option, which may only be used if the backing target
+is an executable.
+
\target OUTPUT_DIRECTORY
\c OUTPUT_DIRECTORY specifies where the plugin library, \c qmldir and typeinfo
files are generated. When this keyword is not given, the default value will be
the target path (formed from the \c URI) appended to the value of the
\l QT_QML_OUTPUT_DIRECTORY variable.
-If that variable is not defined, then the output directory will be
-set to \c{${CMAKE_CURRENT_BINARY_DIR}}. When the structure of the source tree
+If that variable is not defined, the default depends on the type of backing
+target. For executables, the value will be the target path appended to
+\c{${CMAKE_CURRENT_BINARY_DIR}}, whereas for other targets it will be just
+\c{${CMAKE_CURRENT_BINARY_DIR}}. When the structure of the source tree
matches the structure of QML module target paths (which is highly recommended),
-\l QT_QML_OUTPUT_DIRECTORY often isn't needed. The need for specifying the
-\c OUTPUT_DIRECTORY keyword should be rare, but if it is used, it is likely
-that the caller will also need to add to the \l IMPORT_PATH to ensure that
-\l{qmllint-auto}{linting}, \l{qmlcachegen-auto}{cached compilation} of qml
-sources and \l{qt6_import_qml_plugins}{automatic importing} of plugins in
-static builds all work correctly.
+\l QT_QML_OUTPUT_DIRECTORY often isn't needed. In order to match the structure
+of the target paths, you have to call your directories \e exactly like the
+segments of your module URI. For example, if your module URI is
+\c{MyUpperCaseThing.mylowercasething}, you need to put this in a directory
+called \c{MyUpperCaseThing/mylowercasething/}.
+
+The need for specifying the \c OUTPUT_DIRECTORY keyword should be rare, but if
+it is used, it is likely that the caller will also need to add to the
+\l IMPORT_PATH to ensure that \l{qmllint-auto}{linting},
+\l{qmlcachegen-auto}{cached compilation} of qml sources and
+\l{qt6_import_qml_plugins}{automatic importing} of plugins in static builds all
+work correctly.
\target NO_GENERATE_PLUGIN_SOURCE
By default, \c{qt_add_qml_module()} will auto-generate a \c{.cpp} file that
@@ -311,7 +417,21 @@ plugin class, the \c NO_GENERATE_PLUGIN_SOURCE option should be given. Where no
\c CLASS_NAME is provided, it defaults to the \c URI with dots replaced by
underscores, then \c Plugin appended. Unless the QML module has no plugin, the
class name will be recorded as a \c classname line in the generated
-\l{Module Definition qmldir Files}{qmldir} file.
+\l{Module Definition qmldir Files}{qmldir} file. You need to add any C++ files
+with custom plugin code to the plugin target. Since the plugin then likely
+contains functionality that goes beyond simply loading the backing library, you
+will probably want to add \l{NO_PLUGIN_OPTIONAL}, too. Otherwise the QML engine
+may skip loading the plugin if it detects that the backing library is already
+linked.
+
+\target NO_PLUGIN
+If the \c NO_PLUGIN keyword is given, then no plugin will be built. This
+keyword is thus incompatible with all the options that customize the plugin
+target, in particular \l{NO_GENERATE_PLUGIN_SOURCE}, \l{NO_PLUGIN_OPTIONAL},
+\l{PLUGIN_TARGET}, \l{NO_CREATE_PLUGIN_TARGET}, and \l{CLASS_NAME}. If you do
+not provide a plugin for your module, it will only be fully usable if its
+backing library has been linked into the executable. It is generally hard to
+guarantee that a linker preserves the linkage to a library it considers unused.
\target NO_PLUGIN_OPTIONAL
If the \c NO_PLUGIN_OPTIONAL keyword is given, then the plugin is recorded in
@@ -336,13 +456,20 @@ typeinfo file will be generated, but the project will still be expected to
generate a typeinfo file and place it in the same directory as the generated
\c qmldir file.
-\c IMPORTS provides a list of other QML modules that this module imports.
-A version can be specified by appending it after a slash, such as
-\c{QtQuick/2.0}. The minor version may be omitted, as in \c{QtQuick/2}.
-Alternatively, \c auto may be given for the version (\c{QtQuick/auto}), which
-would result in the version that the current module is being imported with
-being used. Each module listed here will be added as an \c{import} entry in the
-generated \l{Module Definition qmldir Files}{qmldir} file.
+\c IMPORTS provides a list of other QML modules that this module imports. Each
+module listed here will be added as an \c{import} entry in the generated
+\l{Module Definition qmldir Files}{qmldir} file. If a QML file imports the
+this module, it also imports all the modules listed under \c{IMPORTS}.
+Optionally, a version can be specified by appending it after a slash, such as
+\c{QtQuick/2.0}. Omitting the version will cause the greatest version available
+to be imported. You may only specify the major version, as in \c{QtQuick/2}. In
+that case the greatest minor version available with the given major version will
+be imported. Finally, \c{auto} may be given as version (\c{QtQuick/auto}). If
+\c{auto} is given, the version that the current module is being imported with is
+propagated to the module to be imported. Given an entry \c{QtQuick/auto} in a
+module \c{YourModule}, if a QML file specifies \c{import YourModule 3.14}, this
+results in importing version \c{3.14} of \c{QtQuick}. For related modules that
+follow a common versioning scheme, you should use \c{auto}.
\c OPTIONAL_IMPORTS provides a list of other QML modules that this module
\e may import at run-time. These are not automatically imported by the QML
@@ -384,7 +511,8 @@ be added to the backing target after this command has been called.
\c RESOURCES lists any other files needed by the module, such as images
referenced from the QML code. These files will be added as compiled-in
-resources under the \l RESOURCE_PREFIX. If needed, their relative location can
+resources (see \l RESOURCE_PREFIX for an explanation of the base point they
+will be located under). If needed, their relative location can
be controlled by setting the \c QT_RESOURCE_ALIAS source property, just as for
\c{.qml} files (see \l{qmlcachegen-auto}{Caching compiled QML sources}).
@@ -400,8 +528,8 @@ and are referenced by the backing target's linking requirements as part of
ensuring that resources are set up and loaded correctly.
The \c DESIGNER_SUPPORTED keyword should be given if the QML module supports
-\l{Qt Quick Designer}. When present, the generated \c qmldir file will contain
+Qt Quick Designer. When present, the generated \c qmldir file will contain
a \c designersupported line. See \l{Module Definition qmldir Files} for how
-this affects the way Quick Designer handles the plugin.
+this affects the way Qt Quick Designer handles the plugin.
*/
diff --git a/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc b/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc
index 01dfc3eb16..fe63d678c7 100644
--- a/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc
+++ b/src/qml/doc/src/cmake/qt_add_qml_plugin.qdoc
@@ -37,17 +37,104 @@
\section1 Synopsis
\badcode
-qt_add_qml_plugin(...)
+qt_add_qml_plugin(
+ target
+ [BACKING_TARGET backing_target]
+ [STATIC | SHARED]
+ [OUTPUT_DIRECTORY]
+ [URI]
+ [CLASS_NAME]
+ [NO_GENERATE_PLUGIN_SOURCE]
+)
\endcode
-\versionlessNote qt6_add_qml_plugin()
+\versionlessCMakeCommandsNote qt6_add_qml_plugin()
\section1 Description
-TBD
+This command creates the plugin target associated with a QML module. It would
+normally be called internally by \l{qt6_add_qml_module}{qt_add_qml_module()} to
+create or update the plugin associated with its backing target. You should not
+call this function directly unless you have special circumstances that require
+you to create the target in a special way.
+
+The documentation for \l{qt6_add_qml_module}{qt_add_qml_module()} describes
+different structural patterns for how the CMake targets associated with a QML
+module can be arranged. Note that even if the QML module has no separate backing
+target and all functionality is implemented directly in the plugin (not the
+recommended arrangement), you should still call
+\l{qt6_add_qml_module}{qt_add_qml_module()} rather than \c{qt_add_qml_plugin()}.
+
\section1 Arguments
-TBD
+The \c target specifies the name of the target to use for the QML plugin. If it
+does not already exist, it will be created.
+
+\c BACKING_TARGET specifies the name of the backing target that the plugin is
+associated with. The backing target can be the same as the plugin \c target, in
+which case there is only the one merged target, but this is not typically
+recommended (see \l{qt6_add_qml_module}{qt_add_qml_module()} for more
+information). \c BACKING_TARGET should always be provided unless there are
+special circumstances that require the plugin target to be created before the
+backing target. If \c BACKING_TARGET is not provided, a \c URI option must be
+given.
+
+By default, the plugin is created with a type that is compatible with the
+backing target. If the backing target is a static library, the plugin will also
+be created as a static library. If the backing target is a shared library, the
+plugin will be created as a module library. Where no backing target is
+provided or the plugin has no separate backing target, the plugin type can be
+specified with either the \c STATIC or \c SHARED keywords. If the plugin type
+is not determined by any of the preceding conditions, a static plugin will be
+created if Qt was built as static libraries, or a module library plugin
+otherwise.
+
+\c OUTPUT_DIRECTORY specifies the directory where the plugin library will be
+created. It should always be the same location as the QML module's
+\l{Module Definition qmldir Files}{qmldir} file. When \c OUTPUT_DIRECTORY is
+not given, it will be obtained from information stored on the
+\c BACKING_TARGET, where available. Note that this could be different to the
+directory of the backing target's own library. If an output directory cannot be
+obtained from the backing target, the \c CMAKE_CURRENT_BINARY_DIR is used by
+default.
+
+\c URI declares the module identifier of the QML module this plugin is
+associated with. The module identifier is the (dotted URI notation) identifier
+for the QML module. If \c URI is not given, a \c BACKING_TARGET must be
+provided and the backing target must have its URI recorded on it (typically by
+an earlier call to \l{qt6_add_qml_module}{qt_add_qml_module()}).
+
+Each plugin should have a C++ class that registers the module with the QML
+engine. By default, \c{qt_add_qml_plugin()} auto-generates the sources for this
+C++ class, and adds them to the \c{target}'s list of sources. The generated
+plugin class satisfies the requirements of the plugin being optional (see
+\l{Module Definition qmldir Files}). The class name is determined as follows:
+
+\list
+ \li If \c CLASS_NAME has been given, it will be used. It must match the name
+ used in the QML module's \c qmldir file.
+ \li If \c CLASS_NAME has not been given, but \c BACKING_TARGET has, the C++
+ class name will be taken from details recorded on that backing target.
+ Those details are usually recorded by an earlier call to
+ \l{qt_add_qml_module}{qt_add_qml_module()}, and they will match the name
+ used in the generated \c qmldir file. This is the recommended way to
+ provide the class name in most scenarios.
+ \li If the class name still cannot be determined, it is set to the module's
+ URI with dots replaced by underscores, and \c Plugin appended.
+\endlist
+
+Some plugins may require the plugin class to be written manually. For example,
+the plugin may need to perform additional initialization or register things
+not implemented by the default plugin class. In such cases, the
+\c NO_GENERATE_PLUGIN_SOURCE option can be given. You are then responsible for
+writing your own C++ plugin class and adding it to the \c target. Note that if
+you need to write your own plugin class, it is very unlikely that the plugin
+can be optional. This in turn means that the \c NO_PLUGIN_OPTIONAL keyword
+should be included in the call to \l{qt_add_qml_module}{qt_add_qml_module()}
+when defining the QML module, or else the generated \c qmldir file will be
+incorrect. Make sure your plugin class uses the same class name as determined
+from the logic just above.
+
*/
diff --git a/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc b/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc
index b2c31123fe..249ae57d79 100644
--- a/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc
+++ b/src/qml/doc/src/cmake/qt_import_qml_plugins.qdoc
@@ -34,20 +34,44 @@
\brief Ensures QML plugins needed by a target are imported for static builds.
+\cmakecommandsince 6.0
+
\section1 Synopsis
\badcode
-qt_import_qml_plugins(...)
-
+qt_import_qml_plugins(target)
\endcode
-\versionlessNote qt6_import_qml_plugins()
+\versionlessCMakeCommandsNote qt6_import_qml_plugins()
\section1 Description
-TBD
+\note This command only has any effect if Qt was built statically. If called
+ using a non-static Qt, it will do nothing and return immediately.
+
+\c{qt_import_qml_plugins()} runs \c{qmlimportscanner} on the \c target
+immediately as part of the call. It finds the static QML plugins used by the
+\c target and links it to those plugins so that they are part of the executable
+or shared library that \c target represents. The search follows QML module
+imports recursively.
+
+Because the call to \c{qmlimportscanner} runs at configure time rather than
+generation or build time, \c{qt_import_qml_plugins()} only knows about the
+information recorded on the \c target (or other targets it links or imports)
+at the time \c{qt_import_qml_plugins()} is called. Any linking or import
+relationships added after this call will not be considered. Therefore, this
+command should be called as late as possible in the \c{target}'s directory
+scope so that all the linking and import relationships are known.
+
+If \c target was created using \l{qt6_add_executable}{qt_add_executable()},
+projects would not normally need to call \c{qt_import_qml_plugins()} directly.
+When Qt is built statically, the command is called automatically as part of
+\l{qt6_add_executable#Finalization}{target finalization} if \c target links to
+the Qml library. By default, this finalization occurs at the end of the same
+directory scope in which the \c target was created. If the \c target was
+created using the standard CMake \c{add_executable()} command instead, the
+project needs to call \c{qt_import_qml_plugins()} itself.
-\section1 Arguments
+\sa Q_IMPORT_QML_PLUGIN
-TBD
*/
diff --git a/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
index 05770b30e0..dc1178be29 100644
--- a/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
+++ b/src/qml/doc/src/cmake/qt_target_qml_sources.qdoc
@@ -32,22 +32,197 @@
\title qt_target_qml_sources
\target qt6_target_qml_sources
-\brief Add qml sources to an existing QML module target.
+\brief Add qml files and resources to an existing QML module target.
+
+\cmakecommandsince 6.2
\section1 Synopsis
\badcode
-qt_target_qml_sources(...)
+qt_target_qml_sources(
+ target
+ [QML_FILES ...]
+ [RESOURCES ...]
+ [PREFIX resource_path]
+ [OUTPUT_TARGETS out_targets_var]
+ [NO_LINT]
+ [NO_CACHEGEN]
+ [NO_QMLDIR_TYPES]
+)
\endcode
-\versionlessNote qt6_target_qml_sources()
+\versionlessCMakeCommandsNote qt6_target_qml_sources()
\section1 Description
-TBD
+\note This command requires CMake 3.19 or later.
+
+\c{qt_target_qml_sources()} provides the ability to add more files to a QML
+module after \l{qt6_add_qml_module}{qt_add_qml_module()} has been called.
+Typically, you pass the set of \c{.qml} files and resources to
+\l{qt6_add_qml_module}{qt_add_qml_module()} directly, but in some cases, it may
+be desirable, or even necessary, to add files after
+\l{qt6_add_qml_module}{qt_add_qml_module()} has been called. For example, you
+may wish to add files conditionally based on an \c{if} statement expression,
+or from subdirectories that will only be added if certain criteria are met.
+You might want to add a set of files with different characteristics to the
+others, such as a different resource prefix, or with linting and bytecode
+compilation disabled. The \c{qt_target_qml_sources()} command enables these
+scenarios.
\section1 Arguments
-TBD
+The \c target must be the backing target of a QML module, or if the QML module
+has no separate backing target, it must be the module's plugin target.
+
+\c QML_FILES is a list of \c{.qml}, \c{.js} and \c{.mjs} files to be added to
+the QML module. This option has exactly the same effect as the \c QML_FILES
+option of the \l{qt6_add_qml_module}{qt_add_qml_module()} command, including
+the automatic compilation to bytecode and lint processing.
+
+The \c NO_CACHEGEN and \c NO_LINT options also have the same effect as they do
+for \l{qt6_add_qml_module}{qt_add_qml_module()}. They disable the bytecode
+compilation and lint processing for the files listed with \c QML_FILES. This
+behavior can also be specified just for individual files using
+\l{qml-source-file-properties}{source file properties}.
+
+\c NO_QMLDIR_TYPES prevents the \c QML_FILES from being added as types to the
+generated \l{qmldir-autogeneration}{qmldir} file.
+
+\c RESOURCES has exactly the same effect as the \c RESOURCES option of the
+\l{qt6_add_qml_module}{qt_add_qml_module()} command. It provides a list of
+files to be added to the \c target as ordinary resources. These files are
+typically things like images, shaders, etc. that the QML code refers to in some
+way.
+
+\target PREFIX
+Files added to the module via \c QML_FILES or \c RESOURCES will be placed under
+the same resource prefix and target path as they would if they were added by the
+\l{qt6_add_qml_module}{qt_add_qml_module()} command. This can be overridden by
+providing a different location with the \c PREFIX option. The value following
+the \c PREFIX keyword will be used directly, without appending any target path.
+The final resource path of each file will be the prefix, plus the path of the
+file below the \c CMAKE_CURRENT_SOURCE_DIR. The \l{QT_RESOURCE_ALIAS} source
+file property can also be used to override that relative path.
+
+\badcode
+qt_add_qml_module(backing
+ URI Example
+ VERSION 1.0
+ RESOURCE_PREFIX /my.company.com/imports
+)
+
+qt_target_qml_sources(backing
+ QML_FILES special/First.qml
+ RESOURCES icons/logo.png
+)
+
+qt_target_qml_sources(backing
+ PREFIX /other.company.com/debugging
+ QML_FILES Inspector.qml
+)
+\endcode
+
+In the above example, the \c backing target's resources will end up with the
+following contents:
+
+\list
+\li \c{/my.company.com/imports/Example/special/First.qml}
+\li \c{/my.company.com/imports/Example/icons/logo.png}
+\li \c{/other.company.com/debugging/Inspector.qml}
+\endlist
+
+\c OUTPUT_TARGETS is also analogous to the same option for
+\l{qt6_add_qml_module}{qt_add_qml_module()}. Use it to specify the name of a
+variable in which to store any additional targets created for static builds.
+If the \c target will be installed, these additional targets will also need to
+be installed to satisfy linking requirements.
+
+\target qml-source-file-properties
+\section1 Source File Properties
+
+A number of source file properties can be used to influence how each individual
+\c{.qml} file is treated at various points in the QML module processing. These
+override any higher level options specified in calls to
+\c{qt_target_qml_sources()} or \l{qt6_add_qml_module}{qt_add_qml_module()}.
+All of these properties need to be set before the files are added with either
+of those two commands.
+
+\c QT_QML_SKIP_QMLLINT can be set to \c TRUE on a source file to prevent it
+from being included in the \l{qmllint-auto}{automatic qmllint processing}.
+By default, all \c{.qml} files will be included in the target's lint run, but
+this option can be used to exclude specific files.
+
+\c QT_QML_SKIP_CACHEGEN does a similar thing, preventing a source file from
+being compiled to byte code when this property is set to \c TRUE. Note that the
+file will still be added to the \c target as a resource in uncompiled form
+(see \l{qmlcachegen-auto}{Caching compiled QML sources}).
+
+Set the \c QT_QML_SKIP_QMLDIR_ENTRY source file property to \c TRUE to prevent
+that \c{.qml} file from being added as a type to the QML module's typeinfo file
+(see \l{qmldir-autogeneration}{Auto-generating \c{qmldir} and typeinfo files}).
+This would normally only be used for a file that does not expose a public type,
+such as a private JS file.
+
+By default, when \l{qmldir-autogeneration}{generating the \c qmldir file}, a
+single type entry will be generated for each \c{.qml} file that provides a type.
+It will be given a version number \c{X.0} where \c{X} is the major version of
+the QML module. If the QML module has any \c PAST_MAJOR_VERSIONS set, the same
+pattern will be applied to those too, appending \c{X.0} for each past major
+version \c{X}. For situations where a file needs to provide type entries for
+a different set of versions instead (e.g. it was first added in a minor patch
+version after the \c{.0} release), specify those versions in the source file's
+\c QT_QML_SOURCE_VERSIONS property. One type entry will be created for each
+version.
+
+If the type that a \c{.qml} file provides is a singleton, set its
+\c QT_QML_SINGLETON_TYPE property to \c TRUE. Similarly, the file's
+\c QT_QML_INTERNAL_TYPE source property can be set to \c TRUE to indicate that
+the type it provides is an internal one. The name of the type itself can also
+be overridden using the \c QT_QML_SOURCE_TYPENAME property. All three of these
+will be reflected in the file's type entries in the
+\l{qmldir-autogeneration}{generated \c qmldir file}.
+
+\target QT_RESOURCE_ALIAS
+All files listed with \c QML_FILES or \c RESOURCES will be added to the
+\c{target}'s resources. Their location in the resources consists of a base point
+and a relative path. The base point defaults to the concatenation of the QML
+module's resource prefix and its target path, but these can be overridden with
+the \l PREFIX argument. The relative path will default to the path of the file
+relative to the \c{target}'s \c SOURCE_DIR target property. This relative path
+can be overridden by setting the \c QT_RESOURCE_ALIAS property on the source
+file. This is commonly used to collect files from different directories and
+have them appear in the resources under a common location.
+
+\target qt_target_qml_sources_example
+\snippet cmake/qt_target_qml_sources/CMakeLists.txt 0
+
+In the above example, the \c qt_target_qml_sources_example target's resources
+will end up with the following contents:
+
+\list
+\li \c{/my.company.com/imports/Example/File.qml}
+\li \c{/my.company.com/imports/Example/FunnySingleton.qml}
+\li \c{/my.company.com/imports/Example/templates/File.qml}
+\li \c{/my.company.com/imports/Example/some_old_thing.qml}
+\li \c{/my.company.com/imports/Example/button-types.png}
+\li \c{/my.company.com/imports/Example/doc/README.txt}
+\endlist
+
+The generated \c qmldir file will contain the following type entries:
+
+\badcode
+File 2.0 File.qml
+singleton FunnySingleton 2.0 FunnySingleton.qml
+OldThing 1.1 some_old_thing.qml
+OldThing 2.0 some_old_thing.qml
+\endcode
+
+\note The source FunnySingleton.qml file must already contain
+the \c {pragma Singleton} statement. Setting the \c QT_QML_SINGLETON_TYPE source
+property does not automatically generate the pragma.
+
+\snippet cmake/qt_target_qml_sources/FunnySingleton.qml 0
+
*/
diff --git a/src/qml/doc/src/cppintegration/definetypes.qdoc b/src/qml/doc/src/cppintegration/definetypes.qdoc
index 969bf4f7c0..d4fe08e37d 100644
--- a/src/qml/doc/src/cppintegration/definetypes.qdoc
+++ b/src/qml/doc/src/cppintegration/definetypes.qdoc
@@ -97,15 +97,18 @@ Types to QML} explains, the properties, methods and signals of any
QObject-derived class are accessible from QML code.
To register a QObject-derived class as an instantiable QML object type, add
-\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration and
+\c QML_ELEMENT or \c QML_NAMED_ELEMENT(<name>) to the class declaration. You
+also need to make adjustments in the build system. For qmake, add
\c {CONFIG += qmltypes}, a \c {QML_IMPORT_NAME}, and a
-\c QML_IMPORT_MAJOR_VERSION to your project file. This will register the class
-into the type namespace under the given major version, using either the class
-name or an explicitly given name as QML type name. The minor version(s) will
-be derived from any revisions attached to properties, methods, or signals. The
-default minor version is \c 0. You can explicitly restrict the type to be
-available only from specific minor versions by adding the
-\c QML_ADDED_IN_MINOR_VERSION() macro to the class declaration. Clients can
+\c QML_IMPORT_MAJOR_VERSION to your project file. For CMake, the file containing
+the class should be part of a target set-up with
+\l{qt_add_qml_module}{qt_add_qml_module()}.
+This will register the class into the type namespace under the given major version,
+using either the class name or an explicitly given name as QML type name. The
+minor version(s) will be derived from any revisions attached to properties,
+methods, or signals. The default minor version is \c 0. You can explicitly
+restrict the type to be available only from specific minor versions by adding
+the \c QML_ADDED_IN_MINOR_VERSION() macro to the class declaration. Clients can
import suitable versions of the namespace in order to use the type.
For example, suppose there is a \c Message class with \c author and
@@ -127,26 +130,52 @@ This type can be registered by adding an appropriate type namespace and version
number to the project file. For example, to make the type available in the
\c com.mycompany.messaging namespace with version 1.0:
-\code
-CONFIG += qmltypes
-QML_IMPORT_NAME = com.mycompany.messaging
-QML_IMPORT_MAJOR_VERSION = 1
-\endcode
+\if defined(onlinedocs)
+ \tab {build-qt-app}{tab-cmake}{CMake}{selected}
+ \tab {build-qt-app}{tab-qmake}{qmake}{}
+ \tabcontent {tab-cmake}
+ \else
+ \section3 Using CMake
+\endif
+ \badcode
+ qt_add_qml_module(messaging
+ URI com.mycompany.messaging
+ VERSION 1.0
+ SOURCES
+ message.cpp message.h
+ )
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+ \tabcontent {tab-qmake}
+\else
+ \section3 Using QMake
+\endif
+ \code
+ CONFIG += qmltypes
+ QML_IMPORT_NAME = com.mycompany.messaging
+ QML_IMPORT_MAJOR_VERSION = 1
+ \endcode
+
+ If the header the class is declared in is not accessible from your project's
+ include path, you may have to amend the include path so that the generated
+ registration code can be compiled.
+
+ \code
+ INCLUDEPATH += com/mycompany/messaging
+ \endcode
+\if defined(onlinedocs)
+ \endtabcontent
+\endif
-If the header the class is declared in is not accessible from your project's
-include path, you may have to amend the include path so that the generated
-registration code can be compiled:
-\code
-INCLUDEPATH += com/mycompany/messaging
-\endcode
The type can be used in an \l{qtqml-syntax-basics.html#object-declarations}
{object declaration} from QML, and its properties can be read and written to,
as per the example below:
\qml
-import com.mycompany.messaging 1.0
+import com.mycompany.messaging
Message {
author: "Amelie"
@@ -334,10 +363,9 @@ classes directly, if this is either not possible or is complicated by some
other concerns, extension objects allow limited extension possibilities
without direct modifications.
-\e{Extension objects} add additional properties to an existing type. Extension
-objects can only add properties, not signals or methods. An extended type
-definition allows the programmer to supply an additional type, known as the
-\e{extension type}, when registering the class. The properties are transparently
+\e{Extension objects} add additional properties to an existing type. An extended
+type definition allows the programmer to supply an additional type, known as the
+\e{extension type}, when registering the class. Its members are transparently
merged with the original target class when used from within QML. For example:
\snippet referenceexamples/extended/example.qml 0
@@ -619,6 +647,8 @@ Item {
}
\endqml
+This is commonly referred to as "on" syntax.
+
Clients can register their own property value source types, but currently not
property value write interceptors.
diff --git a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
index 6e6d067ba6..b5f0676920 100644
--- a/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
+++ b/src/qml/doc/src/cppintegration/extending-tutorial.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -397,13 +397,11 @@ plugin with the Qt meta object system.
Here is the \c ChartsPlugin definition in \c chartsplugin.h:
-\snippet tutorials/extending-qml/chapter6-plugins/import/chartsplugin.h 0
+\snippet tutorials/extending-qml/chapter6-plugins/Charts/chartsplugin.h 0
-Then, we write a \c .pro project file that defines the project as a plugin library
-and specifies with DESTDIR that library files should be built into a \c {../Charts}
-directory.
+Then, we write a \c .pro project file that defines the project as a plugin library.
-\quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro
+\quotefile tutorials/extending-qml/chapter6-plugins/Charts/Charts.pro
When building this example on Windows or Linux, the \c Charts directory will be
located at the same level as the application that uses our new import module.
@@ -413,7 +411,7 @@ plugin binary is copied to \c Contents/PlugIns in the the application bundle;
this path is set in \c {chapter6-plugins/app.pro}:
\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro
-\skipto osx
+\skipto macos
\printuntil }
To account for this, we also need to add this location as a
@@ -432,16 +430,16 @@ to the same location as the plugin binary.
The \c qmldir file declares the module name and the plugin that is made available
by the module:
-\quotefile tutorials/extending-qml/chapter6-plugins/import/qmldir
+\quotefile tutorials/extending-qml/chapter6-plugins/Charts/qmldir
Now we have a QML module that can be imported to any application, provided that the
QML engine knows where to find it. The example contains an executable that loads
\c app.qml, which uses the \c {import Charts 1.0} statement. Alternatively, you can
-load the QML file using the \l{Prototyping with qmlscene}{qmlscene tool}, setting the
-import path to the current directory so that it finds the \c qmldir file:
+load the QML file using the \l {Prototyping with the QML Runtime Tool}{qml tool},
+setting the import path to the current directory so that it finds the \c qmldir file:
\code
- qmlscene -I . app.qml
+ qml -I . app.qml
\endcode
The module "Charts" will be loaded by the QML engine, and the types provided by that
diff --git a/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc b/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc
new file mode 100644
index 0000000000..64342fe1f8
--- /dev/null
+++ b/src/qml/doc/src/cppintegration/integrating-with-js-values-from-cpp.qdoc
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+/*!
+\page qtqml-integrating-with-js-values-from-cpp.html
+\title Integrating with JavaScript values from C++
+\brief Description of how to load and access JavaScript from C++ code.
+
+The following classes can be used to load and access JavaSript from C++ code:
+
+\list
+
+ \li \l QJSValue, which acts as a container for Qt/JavaScript data types.
+ \li \l QJSManagedValue, which represents a value on the JavaScript heap
+ belonging to a \l QJSEngine.
+ \li \l QJSPrimitiveValue, which operates on primitive types in JavaScript semantics.
+\endlist
+
+Use QJSValue to transfer values to and from the engine, and use QJSManagedValue
+to interact with JavaScript values. Only use QJSPrimitiveValues if you have to
+emulate the semantics of JS primitive values in C++.
+
+\table
+ \header
+ \li QJSValue
+ \li QJSManagedValue
+ \li QJSPrimitiveValue
+ \row
+ \li Persistently store values
+ \li Short lived
+ \li Short lived
+ \row
+ \li Transport values to/from engine
+ \li Access properties
+ \li Only Primitives
+ \row
+ \li
+ \li Call methods
+ \li Basic arithmetic and comparison
+\endtable
+
+\section1 QJSValue as a Container Type
+
+\l QJSValue stores the Qt/JavaScript data types supported in ECMAScript including
+function, array and arbitrary object types as well as anything supported by
+QVariant. As a container, it can be used to pass values to and receive values
+from a QJSEngine.
+
+\snippet qtjavascript/integratingjswithcpp/exampleqjsascontainer.cpp qjs-as-container
+
+In case of a cache miss, \c undefined is returned. Otherwise, the cached value is
+returned. Note that implicit conversions (from QString and QJSValue::SpecialValue respectively)
+occur when the value is returned.
+
+QJSValue also has an API to interact with the contained value, but using
+QJSManagedValue is recommended.
+
+\section1 Primitive and Managed Values
+
+QJSValue and QJSManagedValue store values that can be either managed or primitive.
+In QML’s JS engine, a managed value can be thought of as a pointer to some data
+structure on the heap, whose memory is managed by the engine’s garbage collector.
+The actual content of primitive values is stored directly, using a technique
+called NaN-boxing that enables you to represent a NaN-value in multiple ways, even
+though only two are actually needed; one for signalling and one for quiet NaN-value.
+
+\table
+\header
+ \li Primitive Values
+ \li Managed Values
+\row
+ \li int
+ \li Function
+\row
+ \li double
+ \li Array
+\row
+ \li undefined
+ \li QVariant
+\row
+ \li null
+ \li string object
+\row
+ \li QString
+ \li
+\endtable
+
+A pointer to the engine can be obtained from a managed value, but not from a
+primitive one. When using QJSValue for its JavaScript API, you need access
+to the engine to evaluate JavaScript. For example, to run the \c call(args) function,
+you have to interpret it in the engine. This works, as the function is a managed
+value, and you can obtain the engine from it.
+
+Similarly, where the engine is needed when you call a function or
+access a property on a primitive number or string. Whenever you call a method on
+a primitive, an instance of its corresponding non-primitive objects is created.
+This is referred as boxing. When you write \c (42).constructor, that is equivalent
+to \c (new Number(42)).constructor, and it returns the constructor method of the
+global number object. Accordingly, if you write \c QJSValue(42).property("constructor"),
+you would expect to obtain a QJSValue containing that function. However, what you
+get is instead a QJSValue containing \c undefined.
+
+The QJSValue that you constructed contains only a primitive value, and thus you have
+no way to access the engine. You also can’t simply hardcode the property lookup
+for primitive values in QJSEngine, as in one engine you might set
+\e {Number.prototype.constructor.additionalProperty = "the Spanish Inquisition"}
+whereas in another \e {Number.prototype.constructor.additionalProperty = 42}.
+The end result would then clearly be unexpected.
+
+To ensure that property accesses always work, you would need to always store boxed
+values in QJSValue or store an additional pointer to the engine.
+
+However, this would be incompatible with how QJSValue is currently used, lead to
+pointless JS heap allocations when passing around primitives, and increase the
+size needed to store a QJSValue. Therefore, you should use \l QJSValue only for
+storage and \l QJSManagedValue to obtain the engine.
+
+\section1 QJSManagedValue
+
+QJSManagedValue is similar to QJSValue, with a few differences:
+
+\list
+\li The constructors (except for the default and move constructor2) require
+ passing a QJSEngine pointer.
+\li Methods like \c deleteProperty and \l isSymbol are added.
+\li If QJSManagedValue methods encounter an exception, they leave it intact.
+\endlist
+
+To obtain the engine in code, either you are in a scripting context where you’ve
+already got access to an engine to create new objects with \c QJSEngine::newObject
+and to evaluate expressions with \c QJSEngine::evaluate, or you want to evaluate
+some JavaScript in a QObject that has been registered with the engine. In the
+latter case, you can use \c qjsEngine(this) to obtain the currently active
+QJSEngine.
+
+QJSManagedValue also provides a few methods that have no equivalent in QJSEngine.
+
+In the example below, QJSManagedValue methods encounter an exception, and
+QJSEngine::catchError is used to handle the exception.
+
+\snippet qtjavascript/integratingjswithcpp/exampleqjsengine.cpp qjs-engine-example
+
+However, inside a method of a registered object, you might want to instead let
+the exception bubble up the call stack.
+
+QJSManagedValue should be temporarily created on the stack,
+and discarded once you don’t need to work any longer on the contained value.
+Since QJSValue can store primitive values in a more efficient way, QJSManagedValue
+should also not be used as an interface type which is the return or parameter type of
+functions, and the type of properties, as the engine does not treat it in a
+special way, and will not convert values to it (in contrast to QJSValue).
+
+\section1 QJSPrimitiveValue
+
+\l QJSPrimitiveValue can store any of the primitive types, and supports arithmetic
+operations and comparisons according to the ECMA-262 standard. It allows for
+low-overhead operations on primitives in contrast to QJSManagedValue, which always goes
+through the engine, while still yielding results that are indistinguishable
+from what the engine would return. As QJSPrimitiveValue is comparatively large, it
+is not recommended to store values.
+
+*/
diff --git a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
index 0a824bb5b5..6277b01af3 100644
--- a/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
+++ b/src/qml/doc/src/cppintegration/interactqmlfromcpp.qdoc
@@ -105,6 +105,88 @@ You can also connect to any signals or call methods defined in the component
using QMetaObject::invokeMethod() and QObject::connect(). See \l {Invoking QML Methods}
and \l {Connecting to QML Signals} below for further details.
+\section1 Accessing QML Objects via well-defined C++ Interfaces
+
+The best way of interacting with QML from C++ is to define an interface for
+doing so in C++ and accessing it in QML itself. With other methods, refactoring
+your QML code can easily lead to your QML / C++ interaction breaking. It also
+helps to reason about the interaction of QML and C++ code, as having it driven
+via QML can be more easily reasoned about by both users and tooling such as
+qmllint. Accessing QML from C++ will lead to QML code that cannot be understood
+without manually verifying that no outside C++ code is modifying a given QML
+component, and even then the extent of the access might change over time, making
+continued use of this strategy a maintenance burden.
+
+To let QML drive the interaction, first you need to define a C++ interface:
+
+\code
+class CppInterface : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ // ...
+};
+\endcode
+
+Using a QML-driven approach, this interface can be interacted with in two ways:
+
+\section2 Singletons
+
+One option is to register the interface as a singleton by adding the \l
+QML_SINGLETON macro to the interface, exposing it to all components. Following
+that, the interface becomes available via a simple import statement:
+
+\code
+import my.company.module
+
+Item {
+ Component.onCompleted: {
+ CppInterface.foo();
+ }
+}
+\endcode
+
+Use this approach if you need your interface in more places than the root component, as
+simply passing down an object would require explicitly passing it on to other
+components via a property or utilizing the slow and not recommended method of
+using \l {Unqualified access}{unqualified access}.
+
+\section2 Initial properties
+
+Another option is to mark the interface as uncreatable via \l QML_UNCREATABLE
+and supplying it to the root QML Component by using \l
+QQmlComponent::createWithInitialProperties() and a \l {Required
+Properties}{required property} on the QML end.
+
+Your root component may look something like this:
+
+\code
+import QtQuick
+
+Item {
+ required property CppInterface interface
+ Component.onCompleted: {
+ interface.foo();
+ }
+}
+\endcode
+
+Marking the property as required here protects the component against being
+created without the interface property being set.
+
+You can then initialize your component in the same way as outlined in \l
+{Loading QML Objects from C++} except using \c {createWithInitialProperties()}:
+
+\code
+ component.createWithInitialProperties(QVariantMap{{u"interface"_qs, QVariant::fromValue<CppInterface *>(new CppInterface)}});
+\endcode
+
+This method is to be preferred if you know that your interface only needs to be
+available to the root component. It also allows for connecting to signals and
+slots of the interface more easily on the C++ side.
+
+If neither of these methods suit your needs you may want to investigate the usage of
+\l {Using C++ Models with Qt Quick Views}{C++ models} instead.
\section1 Accessing Loaded QML Objects by Object Name
@@ -189,9 +271,9 @@ Notice the parameter and return type specified after the colon. You can use \l
{QML Basic Types}{basic types} and \l {QML Object Types}{object types} as type
names.
-If the type is omitted in QML, then you must specify QVariant as type with
-Q_RETURN_ARG() and Q_ARG() when calling QMetaObject::invokeMethod.
-
+If the type is omitted or specified as \c var in QML, then you must pass
+QVariant as type with Q_RETURN_ARG() and Q_ARG() when calling
+QMetaObject::invokeMethod.
\section2 Connecting to QML Signals
diff --git a/src/qml/doc/src/javascript/finetuning.qdoc b/src/qml/doc/src/javascript/finetuning.qdoc
index 97dc2421c5..61ac7d0c8f 100644
--- a/src/qml/doc/src/javascript/finetuning.qdoc
+++ b/src/qml/doc/src/javascript/finetuning.qdoc
@@ -82,9 +82,12 @@ Running JavaScript code can be influenced by a few environment variables, partic
\li \c{QV4_MAX_CALL_DEPTH}
\li Stack overflows when running (as opposed to compiling) JavaScript are prevented by
controlling the call depth: the number of nested function invocations. By
- default, an exception is generated if the call depth exceeds 1234. If it contains a
- number, this environment variable overrides the maximum call depth. Beware that the
- recursion limit when compiling JavaScript is not affected.
+ default, an exception is generated if the call depth exceeds a maximum number tuned
+ to the platform's default stack size. If the \c{QV4_MAX_CALL_DEPTH} environment
+ variable contains a number, this number is used as maximum call depth. Beware that
+ the recursion limit when compiling JavaScript is not affected. The default maximum
+ call depth is 1234 on most platforms. On QNX it is 640 because on QNX the default
+ stack size is smaller than on most platforms.
\row
\li \c{QV4_MM_AGGRESSIVE_GC}
\li Setting this environment variable runs the garbage collector before each memory
diff --git a/src/qml/doc/src/javascript/hostenvironment.qdoc b/src/qml/doc/src/javascript/hostenvironment.qdoc
index 6f1134a3e2..943da5cbef 100644
--- a/src/qml/doc/src/javascript/hostenvironment.qdoc
+++ b/src/qml/doc/src/javascript/hostenvironment.qdoc
@@ -42,7 +42,8 @@ Like a browser or server-side JavaScript environment, the QML runtime implements
all of the built-in types and functions defined by the standard, such as Object, Array, and Math.
The QML runtime implements the 7th edition of the standard.
-\l{Nullish Coalescing} (since Qt 5.15) and \l{Optional Chaining} (since Qt 6.2) are also implemented in the QML runtime.
+\l{Nullish Coalescing} (\c{??}) (since Qt 5.15) and \l{Optional Chaining} (\c{?.}) (since Qt 6.2)
+are also implemented in the QML runtime.
The standard ECMAScript built-ins are not explicitly documented in the QML documentation. For more
information on their use, please refer to the ECMA-262 7th edition standard or one of the many online
@@ -70,11 +71,10 @@ to use from C++. See
\l {qtqml-cppintegration-interactqmlfromcpp.html}{Interacting with QML Objects from C++}
for more information.
-Type assertions can also be used in order to cast an object to a different
-object type. If the object is actually of the given type, then the type
-assertion returns the same object. If not, it returns \c null. In the following
-snippet we assert that the \c parent object is a \c Rectangle before accessing
-a specific member of it.
+Type assertions (sometimes called \e as-casts) can also be used in order to cast an object to a
+different object type. If the object is actually of the given type, then the type assertion returns
+the same object. If not, it returns \c null. In the following snippet we assert that the \c parent
+object is a \c Rectangle before accessing a specific member of it.
\qml
Item {
diff --git a/src/qml/doc/src/javascript/imports.qdoc b/src/qml/doc/src/javascript/imports.qdoc
index 9227f0e604..8d49c02f62 100644
--- a/src/qml/doc/src/javascript/imports.qdoc
+++ b/src/qml/doc/src/javascript/imports.qdoc
@@ -95,17 +95,18 @@ or modules).
A JavaScript resource may import another in the following fashion:
\code
-.import "filename.js" as Qualifier
+import * as MathFunctions from "factorial.mjs";
\endcode
-For example:
+Or:
\code
-import * as MathFunctions from "factorial.mjs";
+.import "filename.js" as Qualifier
\endcode
-The latter is standard ECMAScript syntax for importing ECMAScript modules, and
+The former is standard ECMAScript syntax for importing ECMAScript modules, and
only works from within ECMAScript modules as denoted by the \c mjs file
-extension. The former is an extension to JavaScript provided by the \c QML
-engine and will work also with non-modules.
+extension. The latter is an extension to JavaScript provided by the \c QML
+engine and will work also with non-modules. As an extension superseded by the
+ECMAScript standard, its usage is discouraged.
When a JavaScript file is imported this way, it is imported with a qualifier.
The functions in that file are then accessible from the importing script via the
diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc
index 3fc4c86f74..cc4f4a2747 100644
--- a/src/qml/doc/src/qmlfunctions.qdoc
+++ b/src/qml/doc/src/qmlfunctions.qdoc
@@ -45,8 +45,8 @@
\endcode
You can use the build system to register the type in the type namespace
- \e {com.mycompany.qmlcomponents} with major version \c 1 by specifying the
- following in your project file:
+ \e {com.mycompany.qmlcomponents} with major version \c 1.
+ For qmake, specify the following in your project file:
\badcode
CONFIG += qmltypes
@@ -54,6 +54,15 @@
QML_IMPORT_MAJOR_VERSION = 1
\endcode
+ With CMake, you pass the URI and version to qt_add_qml_module
+
+ \badcode
+ qt6_add_qml_module(myapp
+ URI com.mycompany.qmlcomponents
+ VERSION 1.0
+ )
+ \endcode
+
Once registered, the type can be used in QML by importing the
same type namespace and version number:
@@ -101,8 +110,9 @@
\relates QQmlEngine
Declares the enclosing type to be available, but anonymous in QML. The type
- cannot be created or used as property type, but when passed from C++, it is
- recognized.
+ cannot be created or used to declare properties in QML, but when passed from
+ C++, it is recognized. In QML, you can use properties of this type if they
+ are declared in C++.
\sa QML_ELEMENT, QML_NAMED_ELEMENT(), QML_UNCREATABLE(), QML_INTERFACE
*/
@@ -274,7 +284,7 @@
// Initialize this using myObject where you would previously
// call qmlRegisterSingletonInstance().
- static MySingleton *s_singletonInstance = nullptr;
+ inline static MySingleton *s_singletonInstance = nullptr;
static MySingleton *create(QQmlEngine *, QJSEngine *engine)
{
@@ -298,7 +308,7 @@
}
private:
- static QJSEngine *s_engine = nullptr;
+ inline static QJSEngine *s_engine = nullptr;
};
\endcode
@@ -1243,20 +1253,25 @@
\fn bool qmlProtectModule(const char* uri, int majVersion);
\relates QQmlEngine
- This function protects a module from having types registered into it. This
- can be used to prevent other plugins from injecting types into your module.
- It can also be a performance improvement, as it allows the engine to skip
- checking for the possibility of new types or plugins when this import is
- reached.
-
- The performance benefit is primarily seen when registering application
- specific types from within the application instead of through a plugin.
- Using qmlProtectModule allows the engine to skip checking for a plugin when
- that uri is imported, which can be noticeable with slow file systems.
-
- After this function is called, any attempt to register C++ types into this
- uri, major version combination will lead to a runtime error. Call this after
- you have registered all of your types with the engine.
+ This function protects a module from further modification. This can be used
+ to prevent other plugins from injecting types into your module. It can also
+ be a performance improvement, as it allows the engine to skip checking for
+ the possibility of new types or plugins when this import is reached.
+
+ Once qmlProtectModule has been called, a QML engine will not search for a new
+ \c qmldir file to load the module anymore. It will re-use any \c qmldir files
+ it has loaded before, though. Therefore, types present at this point continue
+ to work. Mind that different QML engines may load different modules. The
+ module protection, however, is global and affects all engines. The overhead
+ of locating \c qmldir files and loading plugins may be noticeable with slow file
+ systems. Therefore, protecting a module once you are sure you won't need to
+ load it anymore can be a good optimization. Mind also that the module lock
+ not only affects plugins but also any other qmldir directives, like \c import
+ or \c prefer, as well as any composite types or scripts declared in a \c qmldir
+ file.
+
+ In addition, after this function is called, any attempt to register C++ types
+ into this uri, major version combination will lead to a runtime error.
Returns true if the module with \a uri as a \l{Identified Modules}
{module identifier} and \a majVersion as a major version number was found
diff --git a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
index 718b0c25ac..562b262271 100644
--- a/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/definetypes.qdoc
@@ -53,8 +53,12 @@ The type name has the following requirements:
This document is then automatically recognized by the engine as a definition of
a QML type. Additionally, a type defined in this manner is automatically made
-available to other QML files within the same directory as the engine searches
-within the immediate directory when resolving QML type names.
+available to other QML files within the same local directory as the engine
+searches within the immediate directory when resolving QML type names.
+
+\note The QML engine does not automatically search remote directories this way.
+You have to add a qmldir file if your documents are loaded over the network. See
+\l{Importing QML Document Directories}.
\section2 Custom QML Type Definition
diff --git a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
index d762621d6c..8f21a7348c 100644
--- a/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
+++ b/src/qml/doc/src/qmllanguageref/documents/networktransparency.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -51,7 +51,8 @@ Image {
Network transparency is supported throughout QML, for example, both the FontLoader
and Image elements support loading resources from a remote server.
-Even QML types themselves can be on the network - if the \l {Prototyping with qmlscene} is used to load
+Even QML types themselves can be on the network: if the
+\l {Prototyping with the QML Runtime Tool}{qml tool} is used to load
\tt http://example.com/mystuff/Hello.qml and that content refers to a type "World", the engine
will load \tt http://example.com/mystuff/qmldir and resolve the type just as it would for a local file.
For example if the qmldir file contains the line "World World.qml", it will load
diff --git a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
index 303ed6b18c..493b031b60 100644
--- a/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/identifiedmodules.qdoc
@@ -35,8 +35,8 @@ specified by the module in its \c qmldir file. This enables such modules to
be imported with a unique identifier that remains the same no matter where the
module is located on the local file system.
-When importing an identified module, an unquoted identifier is used, with a
-mandatory version number:
+When importing an identified module, an unquoted identifier is used, with an
+optional version number:
\snippet qml/imports/installed-module.qml imports
@@ -44,6 +44,12 @@ Identified modules must be installed into the
\l{qtqml-syntax-imports.html#qml-import-path}{import path} in order to be found
by the QML engine.
+Syntactically, each dot-separated segment of the URI must be a well-formed
+ECMAScript Identifier Name. This means, for example, the segments must not start
+with a number and they must not contain \e{-} (minus) characters. As the URI
+will be translated into directory names, you should restrict it to alphanumeric
+characters of the latin alphabet, underscores, and dots.
+
\section1 Locally Installed Identified Modules
A directory of QML and/or C++ files can be shared as an identified module if it
diff --git a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
index 95e8a179de..4d7ea272ce 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
+++ b/src/qml/doc/src/qmllanguageref/modules/qmldir.qdoc
@@ -43,278 +43,287 @@ module. For more information about the first form of \c qmldir file, see
\section1 Contents of a Module Definition qmldir File
-A \c qmldir file is a plain-text file that contains
-the following commands:
-
-\table 70%
- \header
- \li Syntax
- \li Usage
- \row
- \li
- \code
-module <ModuleIdentifier>
- \endcode
- \li Declares the module identifier of the module.
- The <ModuleIdentifier> is the (dotted URI notation) identifier
- for the module, which must match the module's install path.
-
- The \l{Identified Modules#Semantics of Identified Modules}
- {module identifier directive} must be the first line of the file.
- Exactly one module identifier directive may exist in the \c qmldir
- file.
-
- Example:
- \code
-module ExampleModule
- \endcode
-
- \row
- \li
- \code
-[singleton] <TypeName> <InitialVersion> <File>
- \endcode
- \li Declares a \l{qtqml-typesystem-objecttypes.html}{QML object type}
- to be made available by the module.
- \list
- \li \c [singleton] Optional. Used to declare a singleton type.
- \li \c <TypeName> is the type being made available
- \li \c <InitialVersion> is the module version for which the type is to be made available
- \li \c <File> is the (relative) file name of the QML file that defines the type
- \endlist
-
- Zero or more object type declarations may exist in the \c qmldir
- file, however each object type must have a unique type name within
- any particular version of the module.
- \note To declare a \c singleton type, the QML file defining the
- type must include the \c {pragma Singleton} statement.
-
- Example:
- \code
-//Style.qml with custom singleton type definition
-pragma Singleton
-import QtQuick 2.0
+A \c qmldir file is a plain-text file that contains the following commands:
-QtObject {
- property int textSize: 20
- property color textColor: "green"
-}
+\list
+ \li \l {Module Identifier Declaration}
+ \li \l {Object Type Declaration}
+ \li \l {Internal Object Type Declaration}
+ \li \l {JavaScript Resource Declaration}
+ \li \l {Plugin Declaration}
+ \li \l {Plugin Classname Declaration}
+ \li \l {Type Description File Declaration}
+ \li \l {Module Dependencies Declaration}
+ \li \l {Module Import Declaration}
+ \li \l {Designer Support Declaration}
+ \li \l {Preferred Path Declaration}
+\endlist
-// qmldir declaring the singleton type
-module CustomStyles
-singleton Style 1.0 Style.qml
+\note Each command in a \c qmldir file must be on a separate line.
-// singleton type in use
-import QtQuick 2.0
-import CustomStyles 1.0
+In addition to commands, you can also add comments, which are lines starting
+with \c {#}.
-Text {
- font.pixelSize: Style.textSize
- color: Style.textColor
- text: "Hello World"
-}
- \endcode
-
- \row
- \li
- \code
-internal <TypeName> <File>
- \endcode
- \li Declares an object type that is in the module but should not be
- made available to users of the module.
-
- Zero or more internal object type declarations may exist in the
- \c qmldir file.
-
- Example:
- \code
-internal MyPrivateType MyPrivateType.qml
- \endcode
-
- This is necessary if the module may be imported remotely (see
- \l{Identified Modules#Remotely Installed Identified Modules}
- {Remotely Installed Identified Modules}) because if an exported type depends
- on an non-exported type within the module, the engine must also
- load the non-exported type.
-
- \row
- \li
- \code
-<ResourceIdentifier> <InitialVersion> <File>
- \endcode
- \li Declares a JavaScript file to be made available by the module.
- The resource will be made available via the specified identifier
- with the specified version number.
-
- Zero or more JavaScript resource declarations may exist in the
- \c qmldir file, however each JavaScript resource must have a unique
- identifier within any particular version of the module.
-
- Example:
- \code
-MyScript 1.0 MyScript.js
- \endcode
-
- See the documentation about \l{qtqml-javascript-resources.html}
- {defining JavaScript resources} and
- \l{qtqml-javascript-imports.html}
- {Importing JavaScript Resources In QML} for more information.
-
- \row
- \li
- \code
-[optional] plugin <Name> [<Path>]
- \endcode
- \li Declares a plugin to be made available by the module.
-
- \list
- \li \c optional denotes that the plugin itself does not contain
- any relevant code and only serves to load a library it links
- to. If given, and if any types for the module are already
- available, indicating that the library has been loaded by some
- other means, QML will not load the plugin.
- \li \c <Name> is the plugin library name. This is usually not the
- same as the file name of the plugin binary, which is platform
- dependent; e.g. the library \c MyAppTypes would produce
- \c libMyAppTypes.so on Linux and \c MyAppTypes.dll on Windows.
- \li \c <Path> (optional) specifies either:
- \list
- \li an absolute path to the directory containing the plugin
- file, or
- \li a relative path from the directory containing the \c qmldir
- file to the directory containing the plugin file.
- \endlist
-
- By default the engine searches for the plugin library in the
- directory that contains the \c qmldir file. (The plugin search
- path can be queried with QQmlEngine::pluginPathList() and
- modified using QQmlEngine::addPluginPath().)
- \endlist
-
- Zero or more C++ plugin declarations may exist in the \c qmldir
- file, however since plugin loading is a relatively expensive
- operation, clients are advised to specify at most a single plugin.
-
- Example:
- \code
-plugin MyPluginLibrary
- \endcode
- \row
- \li
- \code
-classname <C++ plugin class>
- \endcode
- \li Provides the class name of the C++ plugin used by the module.
-
- This information is required for all the QML modules that depend
- on a C++ plugin for additional functionality. Qt Quick applications
- built with static linking cannot resolve the module imports without
- this information.
-
- \row
- \li
- \code
-typeinfo <File>
- \endcode
- \li Declares a \l{Type Description Files}{type description file} for
- the module that can be read by QML tools such as Qt Creator to
- access information about the types defined by the module's plugins.
- \c <File> is the (relative) file name of a \c .qmltypes file.
-
- Example:
- \code
-typeinfo mymodule.qmltypes
- \endcode
-
- Without such a file, QML tools may be unable to offer features such
- as code completion for the types defined in your plugins.
-
- \row
- \li
- \code
-depends <ModuleIdentifier> <InitialVersion>
- \endcode
- \li Declares that this module depends on another.
-
- Example:
- \code
-depends MyOtherModule 1.0
- \endcode
-
- This declaration is necessary only in cases when the dependency is
- hidden: for example, when the C++ code for one module is used to
- load QML (perhaps conditionally) which then depends on other
- modules. In such cases, the \c depends declaration is necessary
- to include the other modules in application packages.
- \row
- \li
- \code
-import <ModuleIdentifier> [<Version>]
- \endcode
- \li Declares that this module imports another.
-
- Example:
- \code
-import MyOtherModule 1.0
- \endcode
-
- The types from the other module are made available in the same type
- namespace as this module is imported into. Omitting the version
- imports the latest version available of the other module, specifying
- \c auto as version imports the same version as the version of this
- module specified in the QML \c import statement.
-
- \row
- \li
- \code
-# <Comment>
- \endcode
- \li Declares a comment. These are ignored by the engine.
-
- Example:
- \code
-# this is a comment
- \endcode
-
- \row
- \li
- \code
-designersupported
- \endcode
-
- \li Set this property if the plugin is supported by Qt Quick Designer.
- By default, the plugin will not be supported.
-
- A plugin that is supported by Qt Quick Designer has to be properly
- tested. This means that the plugin does not crash when running inside
- the qml2puppet that is used by Qt Quick Designer to execute QML.
- Generally the plugin should work well in the Qt Quick Designer
- and not cause any show stoppers, like taking huge amounts of memory,
- slowing down the qml2puppet heavily or anything else that renders
- the plugin effectively unusable in the Qt Quick Designer.
-
- The items of an unsupported plugin are not painted in the Qt Quick Designer,
- but they are still available as empty boxes and the properties can be edited.
-
- \row
- \li
- \code
-prefer <Path>
- \endcode
-
- \li This property directs the QML engine to load any further files for this
- module from <path>, rather than the current directory. This can be used
- to load files compiled with qmlcachegen.
-
- For example, you can add a module's QML files as resources to a resource
- path \c{:/my/path/MyModule/}. Then, add \c{prefer :/my/path/MyModule} to
- the qmldir file in order to use the files in the resource system, rather
- than the ones in the file system. If you then use qmlcachegen for those,
- the pre-compiled files will be available to any clients of the module.
-
-\endtable
-
-Each command in a \c qmldir file must be on a separate line.
+\section2 Module Identifier Declaration
+
+\code
+ module <ModuleIdentifier>
+\endcode
+
+Declares the module identifier of the module. The <ModuleIdentifier> is the
+(dotted URI notation) identifier for the module, which must match the module's
+install path.
+
+The \l{Identified Modules#Semantics of Identified Modules}
+{module identifier directive} must be the first line of the file. Exactly one
+module identifier directive may exist in the \c qmldir file.
+
+Example:
+\code
+ module ExampleModule
+\endcode
+
+\section2 Object Type Declaration
+\code
+ [singleton] <TypeName> <InitialVersion> <File>
+\endcode
+
+Declares a \l{qtqml-typesystem-objecttypes.html}{QML object type}
+to be made available by the module.
+\list
+ \li \c [singleton] Optional. Used to declare a singleton type.
+ \li \c <TypeName> is the type being made available
+ \li \c <InitialVersion> is the module version for which the type is to be
+ made available
+ \li \c <File> is the (relative) file name of the QML file that defines
+ the type
+\endlist
+
+Zero or more object type declarations may exist in the \c qmldir
+file. However, each object type must have a unique type name within
+any particular version of the module.
+\note To declare a \c singleton type, the QML file defining the
+type must include the \c {pragma Singleton} statement.
+
+Example:
+\code
+ //Style.qml with custom singleton type definition
+ pragma Singleton
+ import QtQuick 2.0
+
+ QtObject {
+ property int textSize: 20
+ property color textColor: "green"
+ }
+
+ // qmldir declaring the singleton type
+ module CustomStyles
+ singleton Style 1.0 Style.qml
+
+ // singleton type in use
+ import QtQuick 2.0
+ import CustomStyles 1.0
+
+ Text {
+ font.pixelSize: Style.textSize
+ color: Style.textColor
+ text: "Hello World"
+ }
+\endcode
+
+\section2 Internal Object Type Declaration
+
+\code
+ internal <TypeName> <File>
+\endcode
+
+Declares an object type that is in the module but should not be
+made available to users of the module.
+
+Zero or more internal object type declarations may exist in the
+\c qmldir file.
+
+Example:
+\code
+ internal MyPrivateType MyPrivateType.qml
+\endcode
+
+This is necessary if the module is imported remotely
+(see \l{Identified Modules#Remotely Installed Identified Modules}
+{Remotely Installed Identified Modules}) because if an exported type depends
+on a non-exported type within the module, the engine must also
+load the non-exported type.
+
+\section2 JavaScript Resource Declaration
+
+\code
+ <ResourceIdentifier> <InitialVersion> <File>
+\endcode
+
+Declares a JavaScript file to be made available by the module.
+The resource will be made available via the specified identifier
+with the specified version number.
+
+Zero or more JavaScript resource declarations may exist in the
+\c qmldir file. However, each JavaScript resource must have a unique
+identifier within any particular version of the module.
+
+Example:
+\code
+ MyScript 1.0 MyScript.js
+\endcode
+
+See the documentation about \l{qtqml-javascript-resources.html}
+{defining JavaScript resources} and
+\l{qtqml-javascript-imports.html}
+{Importing JavaScript Resources In QML} for more information.
+
+\section2 Plugin Declaration
+
+\code
+ [optional] plugin <Name> [<Path>]
+\endcode
+
+Declares a plugin to be made available by the module.
+
+\list
+ \li \c optional denotes that the plugin itself does not contain
+ any relevant code and only serves to load a library it links
+ to. If given, and if any types for the module are already
+ available, indicating that the library has been loaded by some
+ other means, QML will not load the plugin.
+ \li \c <Name> is the plugin library name. This is usually not the
+ same as the file name of the plugin binary, which is platform
+ dependent. For example, the library \c MyAppTypes would produce
+ \c libMyAppTypes.so on Linux and \c MyAppTypes.dll on Windows.
+ \li \c <Path> (optional) specifies either:
+ \list
+ \li an absolute path to the directory containing the plugin
+ file, or
+ \li a relative path from the directory containing the \c qmldir
+ file to the directory containing the plugin file.
+ \endlist
+\endlist
+
+By default, the engine searches for the plugin library in the
+directory that contains the \c qmldir file. (The plugin search
+path can be queried with QQmlEngine::pluginPathList() and
+modified using QQmlEngine::addPluginPath().)
+
+Zero or more C++ plugin declarations may exist in the \c qmldir
+file. However, since plugin loading is a relatively expensive
+operation, clients are advised to specify at most a single plugin.
+
+Example:
+\code
+ plugin MyPluginLibrary
+\endcode
+
+\section2 Plugin Classname Declaration
+
+\code
+ classname <C++ plugin class>
+\endcode
+
+Provides the class name of the C++ plugin used by the module.
+
+This information is required for all the QML modules that depend
+on a C++ plugin for additional functionality. Qt Quick applications
+built with static linking cannot resolve the module imports without
+this information.
+
+\section2 Type Description File Declaration
+
+\code
+ typeinfo <File>
+\endcode
+
+Declares a \l{Type Description Files}{type description file} for
+the module that can be read by QML tools such as Qt Creator to
+access information about the types defined by the module's plugins.
+\c <File> is the (relative) file name of a \c .qmltypes file.
+
+Example:
+\code
+ typeinfo mymodule.qmltypes
+\endcode
+
+Without such a file, QML tools may be unable to offer features such
+as code completion for the types defined in your plugins.
+
+\section2 Module Dependencies Declaration
+
+\code
+ depends <ModuleIdentifier> <InitialVersion>
+\endcode
+
+Declares that this module depends on another.
+
+Example:
+\code
+ depends MyOtherModule 1.0
+\endcode
+
+This declaration is necessary only in cases when the dependency is
+hidden: for example, when the C++ code for one module is used to
+load QML (perhaps conditionally), which then depends on other
+modules. In such cases, the \c depends declaration is necessary
+to include the other modules in application packages.
+
+\section2 Module Import Declaration
+
+\code
+ import <ModuleIdentifier> [<Version>]
+\endcode
+
+Declares that this module imports another.
+
+Example:
+\code
+ import MyOtherModule 1.0
+\endcode
+
+The types from the other module are made available in the same type
+namespace as this module is imported into. Omitting the version
+imports the latest version available of the other module. Specifying
+\c auto as version imports the same version as the version of this
+module specified in the QML \c import statement.
+
+\section2 Designer Support Declaration
+
+\code
+ designersupported
+\endcode
+
+Set this property if the plugin is supported by Qt Quick Designer.
+By default, the plugin will not be supported.
+
+A plugin that is supported by Qt Quick Designer has to be properly
+tested. This means that the plugin does not crash when running inside
+the qml2puppet that is used by Qt Quick Designer to execute QML.
+Generally, the plugin should work well in the Qt Quick Designer
+and not cause any show stoppers, like taking excessive amounts of memory,
+slowing down the qml2puppet heavily, or anything else that renders
+the plugin effectively unusable in the Qt Quick Designer.
+
+The items of an unsupported plugin are not painted in the Qt Quick Designer,
+but they are still available as empty boxes and the properties can be edited.
+
+\section2 Preferred Path Declaration
+
+\code
+ prefer <Path>
+\endcode
+
+This property directs the QML engine to load any further files for this
+module from <path>, rather than the current directory. This can be used
+to load files compiled with qmlcachegen.
+
+For example, you can add a module's QML files as resources to a resource
+path \c{:/my/path/MyModule/}. Then, add \c{prefer :/my/path/MyModule} to
+the qmldir file in order to use the files in the resource system, rather
+than the ones in the file system. If you then use qmlcachegen for those,
+the pre-compiled files will be available to any clients of the module.
\section1 Versioning Semantics
@@ -434,7 +443,7 @@ documentation on this, no further action is needed. qmltyperegistrar will
automatically generate the \c .qmltypes files.
Example:
-If your module is in \c /tmp/imports/My/Module, a file caled \c plugins.qmltypes
+If your module is in \c /tmp/imports/My/Module, a file called \c plugins.qmltypes
should be generated alongside the actual plugin binary.
Add the line
diff --git a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
index b1fce12dc3..834977994f 100644
--- a/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
+++ b/src/qml/doc/src/qmllanguageref/modules/qqmlextensionplugin.qdocinc
@@ -26,6 +26,14 @@ plugins. Library plugins should limit themselves to registering types, as
any manipulation of the engine's root context may cause conflicts or other
issues in the library user's code.
+\note When using the CMake \l qt_add_qml_module API, a plugin will be generated
+automatically for you. It will take care of type registration.
+You only need to write a custom plugin if you have special
+requirements, such as registering custom image
+providers. In that case, pass
+\l{NO_GENERATE_PLUGIN_SOURCE} to the \c qt_add_qml_module
+call to disable the generation of the default plugin.
+
The linker might erroneously remove the generated type registration
function as an optimization. You can prevent that by declaring a synthetic
volatile pointer to the function somewhere in your code. If your module is
diff --git a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
index 7ec8a4ff34..0623dd9934 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/directoryimports.qdoc
@@ -109,6 +109,11 @@ a file system path.
A directory of QML files can also be imported from a remote location if the
directory contains a directory listing \c qmldir file.
+\note This also holds for the implicit import of the directory a QML document
+resides in. If your QML documents are loaded from a remote location, you need
+to add qmldir files even if they don't contain any explicit directory import
+statements. Otherwise your QML documents won't see each other.
+
For example, if the \c myapp directory in the previous example was hosted at
"http://www.my-example-server.com", and the \c mycomponents directory
contained a \c qmldir file defined as follows:
diff --git a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
index ee104af29a..c17ced3601 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/imports.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -305,8 +305,8 @@ default locations to be searched by the engine. By default, this list contains:
Additional import paths can be added through QQmlEngine::addImportPath() or the
\c QML_IMPORT_PATH environment variable. When running the
-\l{Prototyping with qmlscene}{qmlscene} tool, you can also use the \c -I option
-to add an import path.
+\l {Prototyping with the QML Runtime Tool}{qml tool}, you can also use the
+\c -I option to add an import path.
You can specify multiple import paths in the \c QML_IMPORT_PATH environment
variable by joining them using the path separator. On Windows the path separator
diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
index 787e7b920b..8b3ff59ecc 100644
--- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc
@@ -56,6 +56,7 @@ The set of QML object-type attribute types is as follows:
These attributes are discussed in detail below.
\section2 The \e id Attribute
+\keyword QML.id
Every QML object type has exactly one \e id attribute. This attribute is
provided by the language itself, and cannot be redefined or overridden by any
@@ -686,8 +687,8 @@ the role names of the view's model, then those properties will be initialized
with the model's corresponding values.
For more information, visit the \l{Models and Views in Qt Quick} page.
-\sa {QQmlComponent::createWithInitialProperties}, {QQmlApplicationEngine::setInitialProperties}
-and {QQuickView::setInitialProperties} for ways to initialize required properties from C++.
+See \l{QQmlComponent::createWithInitialProperties}, \l{QQmlApplicationEngine::setInitialProperties}
+and \l{QQuickView::setInitialProperties} for ways to initialize required properties from C++.
\section3 Read-Only Properties
@@ -730,6 +731,8 @@ with a particular property is as follows:
}
\endcode
+This is commonly referred to as "on" syntax.
+
It is important to note that the above syntax is in fact an
\l{qtqml-syntax-basics.html#object-declarations}{object declaration} which
will instantiate an object which acts on a pre-existing property.
diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
index 5716f6c386..6e94af6e41 100644
--- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
+++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc
@@ -267,38 +267,18 @@ property is only invoked when the property is reassigned to a different object v
var urlObject = new URL(url);
\endqml
- \section1 Using the url Type
-
- When a relative URL is written to a \c url type property, it is converted
- into a URL object, so \b {matching the URL value against the input string
- value will fail}. Instead, convert the string to a URL using Qt.resolvedUrl()
- for means of comparison, and use \c toString() to get the contents of the URL:
-
- \qml
- Image {
- source: "pics/logo.png"
-
- Component.onCompleted: {
- // This prints 'false'. Although "pics/logo.png" was the input string,
- // it's been converted from a string to a URL, so these two are not the same.
- console.log(source == "pics/logo.png")
-
- // This prints 'true' as Qt.resovledUrl() converts the string into a
- // URL with the correctly resolved path
- console.log(source == Qt.resolvedUrl("pics/logo.png"))
-
- // This prints the absolute path, e.g. "file:///path/to/pics/logo.png"
- console.log(source.toString())
- }
- }
- \endqml
+ \note In Qt 5, URLs were automatically resolved based on the current context
+ when assigning them to any \c url property. This made it impossible to
+ work with relative URLs and it created inconsistent behavior when reading
+ back a URL previously written to a property. Therefore, the behavior was
+ changed in Qt 6.
\note When referring to files stored with the \l{resources.html}{Qt Resource System}
from within QML, you should use "qrc:///" instead of ":/" as QML requires URL paths.
Relative URLs resolved from within that file will use the same protocol.
Additionally, URLs may contain encoded characters using the 'percent-encoding' scheme
- specified by \l {http://tools.ietf.org/html/rfc3986}{RFC 3986}. These characters
+ specified by \l {https://datatracker.ietf.org/doc/html/rfc3986}{RFC 3986}. These characters
will be preserved within properties of type \c url, to allow QML code to
construct precise URL values.
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index 83544b1a66..a3df68b29b 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
-\qmlmodule QtQml 2.\QtMinorVersion
+\qmlmodule QtQml
\title Qt QML QML Types
\ingroup qmlmodules
\brief List of QML types provided by the Qt QML module
diff --git a/src/qml/doc/src/qt6-changes.qdoc b/src/qml/doc/src/qt6-changes.qdoc
index 70c61849e7..9798718b96 100644
--- a/src/qml/doc/src/qt6-changes.qdoc
+++ b/src/qml/doc/src/qt6-changes.qdoc
@@ -213,8 +213,8 @@
engine.installTranslatorFunctions();
\newcode
QJSEngine engine;
- engine.installExtensions(QJSEngine::TranslationExtension
- \endcode;
+ engine.installExtensions(QJSEngine::TranslationExtension);
+ \endcode
\endlist
diff --git a/src/qml/doc/src/qtqml-writing-a-module.qdoc b/src/qml/doc/src/qtqml-writing-a-module.qdoc
new file mode 100644
index 0000000000..6ad820552e
--- /dev/null
+++ b/src/qml/doc/src/qtqml-writing-a-module.qdoc
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+\page qtqml-writing-a-module.html
+\title Writing QML Modules
+\brief How to write a custom QML module.
+
+You can declare a QML module using the \l{qt_add_qml_module}
+{CMake QML Module API} to:
+
+\list
+\li Generate \l {Module Definition qmldir Files}{qmldir} and
+ \l {Type Description Files}{*.qmltypes files}.
+\li Register C++ types annotated with \l QML_ELEMENT.
+\li Invoke \l {Ahead-of-Time-Compilation}{qmlcachegen}.
+\li Provide modules both in the physical and in \l{The Qt Resource System}
+ {resource file system}.
+\li Use the pre-compiled versions of QML files.
+\li Bundle the module's files in the resource file system.
+\li Combine QML files and C++-based types in the same module.
+\li Create a backing library and an optional plugin. Link the backing library
+ into the application to avoid loading the plugin at run time.
+\endlist
+
+All the above actions can also be configured separately.
+For more information, see \l {qt_add_qml_module}{CMake QML Module API}.
+
+\section1 Multiple QML Modules in One Binary
+
+You can add multiple QML modules into the same binary. Define a CMake target for
+each module and then link the targets to the executable.
+If the extra targets are all static libraries, the result will be one binary,
+which contains multiple QML modules. In short you can create an application
+like this:
+
+\badcode
+myProject
+ | - CMakeLists.txt
+ | - main.cpp
+ | - main.qml
+ | - onething.h
+ | - onething.cpp
+ | - ExtraModule
+ | - CMakeLists.txt
+ | - Extra.qml
+ | - extrathing.h
+ | - extrathing.cpp
+\endcode
+
+To begin, let's assume main.qml contains an instantiation of Extra.qml:
+
+ \badcode
+ import ExtraModule
+ Extra { ... }
+ \endcode
+
+The extra module has to be a static library so that you can link it
+into the main program. Therefore, state as much in ExtraModule/CMakeLists.txt:
+
+\quotefromfile qml/CMakeLists.txt
+\printuntil extrathing.h
+\printuntil )
+
+This generates two targets: \c extra_module for the backing library, and
+\c extra_moduleplugin for the plugin. Being a static library too, the plugin cannot
+be loaded at runtime.
+
+In myProject/CMakeLists.txt you need to specify the QML module that main.qml
+and any types declared in onething.h are part of:
+
+\quotefromfile qml/myProject-CMakeLists.txt
+\printuntil onething.h
+\printuntil )
+
+
+From there, you add the subdirectory for the extra module:
+
+\quotefromfile qml/CMakeLists.txt
+\skipto add_subdirectory
+\printuntil )
+
+To ensure that linking the extra module works correctly, you need to:
+
+\list
+\li Define a symbol in the extra module.
+\li Create a reference to the symbol from the main program.
+\endlist
+
+QML plugins contain a symbol you can use for this purpose.
+You can use the \l Q_IMPORT_QML_PLUGIN macro to create a reference to this symbol.
+Add the following code to the main.cpp:
+
+\badcode
+#include <QtQml/qqmlextensionplugin.h>
+Q_IMPORT_QML_PLUGIN(ExtraModulePlugin)
+\endcode
+
+\c ExtraModulePlugin is the name of the generated plugin class. It's composed
+of the module URI with \c Plugin appended to it. Then, in the main program's
+CMakeLists.txt, link the plugin, not the backing library, into the main program:
+
+\quotefromfile qml/myProject-CMakeLists.txt
+\skipto target_link_libraries
+\printuntil )
+
+\section1 Exporting Multiple Major Versions from The Same Module
+
+\l qt_add_qml_module by default considers the major version given in its
+URI argument, even if the individual types declare other versions in their
+added specific version via \l QT_QML_SOURCE_VERSIONS or \l Q_REVISION.
+If a module is available under more than one version, you also need to decide
+what versions the individual QML files are available under. To declare further
+major versions, you can use the \c PAST_MAJOR_VERSIONS option to
+\c qt_add_qml_module as well as the \c {QT_QML_SOURCE_VERSIONS} property on
+individual QML files.
+
+\quotefile qml/MajorProject-CMakeLists.txt
+
+\c MyModule is available in major versions 1, 2, and 3. The maximum version
+available is 3.2. You can import any version 1.x or 2.x with a positive x. For
+Thing.qml and OtherThing.qml we have added explicit version information.
+Thing.qml is available from version 1.4, and OtherThing.qml is available from
+version 2.2. You have to specify the later versions, too, in each
+\c set_source_files_properties() because you may remove QML files
+from a module when bumping the major version. There is no explicit version
+information for OneMoreThing.qml. This means that OneMoreThing.qml is available
+in all major versions, from minor version 0.
+
+With this setup, the generated registration code will register the module
+\c versionsqmlRegisterModule() for each of the major versions. This way, all
+versions can be imported.
+
+
+\section1 Custom Directory Layouts
+
+The easiest way to structure QML modules is to keep them in directories named by
+their URIs. For example, a module My.Extra.Module would live in a directory
+My/Extra/Module relative to the application that uses it. This way, they can
+easily be found at run time and by any tools.
+
+In more complex projects, this convention can be too limiting. You might for
+instance want to group all QML modules in one place to avoid polluting the
+project's root directory. Or you want to reuse a single module in multiple
+applications. For those cases, \c QT_QML_OUTPUT_DIRECTORY in combination with
+\c RESOURCE_PREFIX and \l IMPORT_PATH can be used.
+
+To collect QML modules into a specific output directory, for example a
+subdirectory "qml" in the build directory \l QT_QML_OUTPUT_DIRECTORY, set the
+following in the top-level CMakeLists.txt:
+
+\badcode
+set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)
+\endcode
+
+The output directories of QML modules move to the new location.
+Likewise, the \c qmllint and \c qmlcachegen invocations are automatically
+adapted to use the new output directory as an \l {QML Import Path}{import path}.
+Because the new output directory is not part of the default QML import path,
+you have to add it explicitly at run time, so that the QML modules can be found.
+
+
+Now that the physical file system is taken care of, you may still want to move
+the QML modules into a different place in the resource file system. This is what
+the RESOURCE_PREFIX option is for. You have to specify it separately in
+each \l qt_add_qml_module. The QML module will then be placed under the specified
+prefix, with a target path generated from the URI appended. For example,
+consider the following module:
+
+\code
+qt_add_qml_module(
+ URI My.Great.Module
+ VERSION 1.0
+ RESOURCE_PREFIX /example.com/qml
+ QML_FILES
+ A.qml
+ B.qml
+)
+\endcode
+
+This will add a directory \c example.com/qml/My/Great/Module to the resource file
+system and place the QML module defined above in it. You don't strictly need to
+add the resource prefix to the QML import path as the module can still be found
+in the physical file system. However, it generally is a good idea to add the
+resource prefix to the QML import path because loading from the resource file
+system is faster than loading from the physical file system for most modules.
+
+If the QML modules are meant to be used in a larger project with multiple import
+paths, you'll have to do an additional step: Even if you add the import paths at
+run time, tooling like \c qmllint does not have access to it, and might fail to
+find the correct dependencies. Use \c IMPORT_PATH to tell tooling about the
+additional paths it has to consider. For example:
+
+\badcode
+qt_add_qml_module(
+ URI My.Dependent.Module
+ VERSION 1.0
+ QML_FILES
+ C.qml
+ IMPORT_PATH "/some/where/else"
+)
+\endcode
+
+\section1 Eliminating Run Time File System Access
+
+If all QML modules are always loaded from the resource
+file system, you can deploy the application as a single binary. Let's first
+consider the simple case:
+
+\badcode
+QQmlEngine qmlEngine;
+qmlEngine.addImportPath(QStringLiteral(":/"));
+// Use qmlEngine to load the main.qml file.
+\endcode
+
+\note ":/" is used for simplicity here. See \l {Custom Directory Layouts}
+for more complex cases.
+
+If all the modules are linked into the application and if you're following
+the default resource directory structure, do not add any further import paths as
+those might override the one you added.
+
+If you have specified a custom \c RESOURCE_PREFIX, you have to add the custom
+resource prefix to the import path instead. You can also add multiple resource
+prefixes.
+
+The path \c :/qt-project.org/imports/ is part of the default QML import path. If
+you use it, you don't have to specially add it. Qt's own QML modules are placed
+there, though. You have to be careful not to overwrite them. For modules that are
+heavily re-used across different projects \c :/qt-project.org/imports/ is
+acceptable. By using it you can avoid forcing all the users to add custom
+import paths.
+
+\section1 Integrating custom QML plugins
+
+If you bundle an \l {QQuickImageProvider}{image provider} in the QML module, you
+need to implement the \l {QQmlEngineExtensionPlugin::initializeEngine()}
+method. This, in turn, makes it necessary to write the own plugin. To support
+this use case, \l NO_GENERATE_PLUGIN_SOURCE can be used.
+
+Let's consider a module that provides its own plugin source:
+
+\quotefile qml/myimageprovider.txt
+
+You may declare an image provider in myimageprovider.h, like this:
+
+\badcode
+class MyImageProvider : public QQuickImageProvider
+{
+ [...]
+};
+\endcode
+
+In plugin.cpp you can then define the QQmlEngineExtensionPlugin:
+
+\quotefile qml/plugin.cpp.txt
+
+This will make the image provider available. The plugin and the backing library
+both are in the same CMake target imageproviderplugin. This is done so that the
+linker does not drop parts of the module in various scenarios.
+
+As the plugin creates an image provider, it no longer has a trivial
+\c initializeEngine function. Therefore, the plugin is no longer optional.
+
+*/
diff --git a/src/qml/doc/src/qtqml.qdoc b/src/qml/doc/src/qtqml.qdoc
index e1ff693195..9f26c9328b 100644
--- a/src/qml/doc/src/qtqml.qdoc
+++ b/src/qml/doc/src/qtqml.qdoc
@@ -132,8 +132,14 @@ The QML framework allows QML code to contain JavaScript expressions and for
the QML code to interact with C++ code.
\list
-\li \l{Important C++ Classes Provided By The Qt QML Module}
-\li \l{Integrating QML and C++}
+ \li \l {Overview - QML and C++ Integration}
+ \li \l {Data Type Conversion Between QML and C++}
+ \li \l {Integrating with JavaScript values from C++}
+ \li \l {Exposing Attributes of C++ Types to QML}
+ \li \l {Defining QML Types from C++}
+ \li \l {Writing QML Modules}
+ \li \l {Important C++ Classes Provided By The Qt QML Module}
+ \li \l {Integrating QML and C++}
\endlist
\omit
diff --git a/src/qml/inlinecomponentutils_p.h b/src/qml/inlinecomponentutils_p.h
index ae436d53b0..56794779a6 100644
--- a/src/qml/inlinecomponentutils_p.h
+++ b/src/qml/inlinecomponentutils_p.h
@@ -55,24 +55,38 @@
namespace icutils {
struct Node {
+private:
+ using IndexType = std::vector<QV4::CompiledData::InlineComponent>::size_type;
+ using IndexField = quint32_le_bitfield_member<0, 30, IndexType>;
+ using TemporaryMarkField = quint32_le_bitfield_member<30, 1>;
+ using PermanentMarkField = quint32_le_bitfield_member<31, 1>;
+ quint32_le_bitfield_union<IndexField, TemporaryMarkField, PermanentMarkField> m_data;
+
+public:
Node() = default;
Node(const Node &) = default;
Node(Node &&) = default;
Node& operator=(Node const &) = default;
Node& operator=(Node &&) = default;
- bool operator==(Node const &other) const {return index == other.index;}
+ bool operator==(Node const &other) const {return m_data.data() == other.m_data.data(); }
+
+ Node(IndexType s) : m_data(QSpecialIntegerBitfieldZero) { m_data.set<IndexField>(s); }
+
+ bool hasPermanentMark() const { return m_data.get<PermanentMarkField>(); }
+ bool hasTemporaryMark() const { return m_data.get<TemporaryMarkField>(); }
+
+ void setPermanentMark()
+ {
+ m_data.set<TemporaryMarkField>(0);
+ m_data.set<PermanentMarkField>(1);
+ }
- Node(std::vector<QV4::CompiledData::InlineComponent>::size_type s) {
- index = quint32(s);
- temporaryMark = 0;
- permanentMark = 0;
+ void setTemporaryMark()
+ {
+ m_data.set<TemporaryMarkField>(1);
}
- union {
- quint32_le_bitfield<0, 30> index;
- quint32_le_bitfield<30, 1> temporaryMark;
- quint32_le_bitfield<31, 1> permanentMark;
- };
+ IndexType index() const { return m_data.get<IndexField>(); }
};
using AdjacencyList = std::vector<std::vector<Node*>>;
@@ -109,8 +123,11 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja
auto referencedInICObjectIndex = ic.objectIndex + 1;
while (int(referencedInICObjectIndex) < objectContainer->objectCount()) {
auto potentiallyReferencedInICObject = objectContainer->objectAt(referencedInICObjectIndex);
- bool stillInIC = !(potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::IsInlineComponentRoot)
- && (potentiallyReferencedInICObject-> flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ bool stillInIC
+ = !potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::IsInlineComponentRoot)
+ && potentiallyReferencedInICObject->hasFlag(
+ QV4::CompiledData::Object::InPartOfInlineComponent);
if (!stillInIC)
break;
createEdgeFromTypeRef(objectContainer->resolvedType(potentiallyReferencedInICObject->inheritedTypeNameIndex));
@@ -120,21 +137,20 @@ void fillAdjacencyListForInlineComponents(ObjectContainer *objectContainer, Adja
};
inline void topoVisit(Node *node, AdjacencyList &adjacencyList, bool &hasCycle, std::vector<Node> &nodesSorted) {
- if (node->permanentMark)
+ if (node->hasPermanentMark())
return;
- if (node->temporaryMark) {
+ if (node->hasTemporaryMark()) {
hasCycle = true;
return;
}
- node->temporaryMark = 1;
+ node->setTemporaryMark();
- auto const &edges = adjacencyList[node->index];
+ auto const &edges = adjacencyList[node->index()];
for (auto edgeTarget =edges.begin(); edgeTarget != edges.end(); ++edgeTarget) {
topoVisit(*edgeTarget, adjacencyList, hasCycle, nodesSorted);
}
- node->temporaryMark = 0;
- node->permanentMark = 1;
+ node->setPermanentMark();
nodesSorted.push_back(*node);
};
@@ -145,7 +161,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac
hasCycle = false;
auto currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
- return node.permanentMark == 0;
+ return !node.hasPermanentMark();
});
// Do a topological sort of all inline components
// afterwards, nodesSorted contains the nodes for the inline components in reverse topological order
@@ -153,7 +169,7 @@ inline std::vector<Node> topoSort(std::vector<Node> &nodes, AdjacencyList &adjac
Node& currentNode = *currentNodeIt;
topoVisit(&currentNode, adjacencyList, hasCycle, nodesSorted);
currentNodeIt = std::find_if(nodes.begin(), nodes.end(), [](const Node& node) {
- return node.permanentMark == 0;
+ return !node.hasPermanentMark();
});
}
return nodesSorted;
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index b21acf93c7..ced4c3e057 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -554,6 +554,8 @@ void BaselineJIT::generate_ThrowException()
as->passEngineAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(ThrowException, CallResultDestination::Ignore);
as->gotoCatchException();
+
+ // LOAD_ACC(); <- not needed here since it would be unreachable.
}
void BaselineJIT::generate_GetException() { as->getException(); }
@@ -561,9 +563,11 @@ void BaselineJIT::generate_SetException() { as->setException(); }
void BaselineJIT::generate_CreateCallContext()
{
+ STORE_ACC();
as->prepareCallWithArgCount(1);
as->passCppFrameAsArg(0);
BASELINEJIT_GENERATE_RUNTIME_CALL(PushCallContext, CallResultDestination::Ignore);
+ LOAD_ACC();
}
void BaselineJIT::generate_PushCatchContext(int index, int name) { as->pushCatchContext(index, name); }
diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp
index a61e2829eb..2c6c579e4f 100644
--- a/src/qml/jsapi/qjsengine.cpp
+++ b/src/qml/jsapi/qjsengine.cpp
@@ -1105,13 +1105,9 @@ QJSValue QJSEngine::catchError()
after installing translators in your application. By convention, an empty string
means no translation from the language used in the source code is intended to occur.
*/
-void QJSEngine::setUiLanguage(const QString &language)
-{
+void QJSEngine::setUiLanguage(const QString &language) {
Q_D(QJSEngine);
- if (language == d->uiLanguage)
- return;
- d->uiLanguage = language;
- emit uiLanguageChanged();
+ d->uiLanguage = language; // property takes care of signal emission if necessary
}
QString QJSEngine::uiLanguage() const
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index fb88781852..aa846bb246 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -107,8 +107,8 @@ public:
// Shared by QQmlEngine
mutable QRecursiveMutex mutex;
-
- QProperty<QString> uiLanguage;
+ void uiLanguageChanged() { Q_Q(QJSEngine); if (q) q->uiLanguageChanged(); }
+ Q_OBJECT_BINDABLE_PROPERTY(QJSEnginePrivate, QString, uiLanguage, &QJSEnginePrivate::uiLanguageChanged);
// These methods may be called from the QML loader thread
inline QQmlPropertyCache *cache(QObject *obj, QTypeRevision version = QTypeRevision(), bool doRef = false);
diff --git a/src/qml/jsapi/qjsmanagedvalue.cpp b/src/qml/jsapi/qjsmanagedvalue.cpp
index f248e12398..ce43b958cf 100644
--- a/src/qml/jsapi/qjsmanagedvalue.cpp
+++ b/src/qml/jsapi/qjsmanagedvalue.cpp
@@ -909,7 +909,7 @@ QJSValue QJSManagedValue::property(quint32 arrayIndex) const
if (QV4::String *string = d->as<QV4::String>()) {
const QString qString = string->toQString();
- if (arrayIndex < qString.size())
+ if (arrayIndex < quint32(qString.size()))
return qString.sliced(arrayIndex, 1);
return QJSValue();
}
diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp
index 03cd1e9aa9..832eaca8da 100644
--- a/src/qml/jsapi/qjsvalue.cpp
+++ b/src/qml/jsapi/qjsvalue.cpp
@@ -142,6 +142,16 @@
integers.append(jsArray.property(i).toInt());
}
\endcode
+
+ \section2 Converting to JSON
+
+ It's possible to convert a QJSValue to a JSON type. For example,
+ to convert to an array, use \l QJSEngine::fromScriptValue():
+
+ \code
+ const QJsonValue jsonValue = engine.fromScriptValue<QJsonValue>(jsValue);
+ const QJsonArray jsonArray = jsonValue.toArray();
+ \endcode
*/
/*!
diff --git a/src/qml/jsapi/qjsvalue_p.h b/src/qml/jsapi/qjsvalue_p.h
index cea48fd9e2..69837d6575 100644
--- a/src/qml/jsapi/qjsvalue_p.h
+++ b/src/qml/jsapi/qjsvalue_p.h
@@ -75,7 +75,7 @@ enum PointerMask: quintptr {
IsString = 0x1
};
-class Q_AUTOTEST_EXPORT QJSValuePrivate
+class QJSValuePrivate
{
static const QV4::Value *managedValue(const QV4::Value &v)
{
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index 1873c41261..4000deaeab 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -72,7 +72,7 @@ struct Q_QML_PRIVATE_EXPORT SharedArrayBuffer : Object {
void init(size_t length);
void init(const QByteArray& array);
void destroy();
- std::aligned_storage_t<sizeof(QArrayDataPointer<char>), alignof(QArrayDataPointer<char>)> d;
+ struct { alignas(QArrayDataPointer<char>) unsigned char data[sizeof(QArrayDataPointer<char>)]; } d;
const QArrayDataPointer<char> &data() const { return *reinterpret_cast<const QArrayDataPointer<char> *>(&d); }
QArrayDataPointer<char> &data() { return *reinterpret_cast<QArrayDataPointer<char> *>(&d); }
bool isShared;
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index 577cc11cf4..20501f9d03 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -563,7 +563,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
ScopedValue v(scope);
for (uint i = 0; i < n; ++i)
obj->arraySet(oldSize + i, (v = otherObj->get(i)));
- } else if (other && other->isSparse()) {
+ } else if (other->isSparse()) {
Heap::SparseArrayData *os = static_cast<Heap::SparseArrayData *>(other->d());
if (other->hasAttributes()) {
ScopedValue v(scope);
@@ -586,7 +586,7 @@ uint ArrayData::append(Object *obj, ArrayObject *otherObj, uint n)
obj->arrayPut(oldSize, os->values.data() + os->offset, chunk);
toCopy -= chunk;
if (toCopy)
- obj->setArrayLength(oldSize + chunk + toCopy);
+ obj->arrayPut(oldSize + chunk, os->values.data(), toCopy);
}
return oldSize + n;
diff --git a/src/qml/jsruntime/qv4arrayiterator.cpp b/src/qml/jsruntime/qv4arrayiterator.cpp
index 199b1a728a..51387edf6e 100644
--- a/src/qml/jsruntime/qv4arrayiterator.cpp
+++ b/src/qml/jsruntime/qv4arrayiterator.cpp
@@ -86,18 +86,18 @@ ReturnedValue ArrayIteratorPrototype::method_next(const FunctionObject *b, const
return IteratorPrototype::createIterResultObject(scope.engine, Value::fromInt32(index), false);
}
- ReturnedValue elementValue = a->get(index);
+ QV4::ScopedValue elementValue(scope, a->get(index));
CHECK_EXCEPTION();
if (itemKind == ValueIteratorKind) {
- return IteratorPrototype::createIterResultObject(scope.engine, Value::fromReturnedValue(elementValue), false);
+ return IteratorPrototype::createIterResultObject(scope.engine, elementValue, false);
} else {
Q_ASSERT(itemKind == KeyValueIteratorKind);
ScopedArrayObject resultArray(scope, scope.engine->newArrayObject());
resultArray->arrayReserve(2);
resultArray->arrayPut(0, Value::fromInt32(index));
- resultArray->arrayPut(1, Value::fromReturnedValue(elementValue));
+ resultArray->arrayPut(1, elementValue);
resultArray->setArrayLengthUnchecked(2);
return IteratorPrototype::createIterResultObject(scope.engine, resultArray, false);
diff --git a/src/qml/jsruntime/qv4compilationunitmapper.cpp b/src/qml/jsruntime/qv4compilationunitmapper.cpp
index f3e2b445d1..6cff8d3c9b 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper.cpp
+++ b/src/qml/jsruntime/qv4compilationunitmapper.cpp
@@ -65,6 +65,11 @@ public:
s_staticUnits.insert(file, staticUnit);
}
+ void remove(const QString &file)
+ {
+ s_staticUnits.remove(file);
+ }
+
private:
QMutexLocker<QMutex> m_lock;
@@ -105,4 +110,10 @@ CompiledData::Unit *CompilationUnitMapper::get(
return data;
}
+void CompilationUnitMapper::invalidate(const QString &cacheFilePath)
+{
+ StaticUnitCache cache;
+ cache.remove(cacheFilePath);
+}
+
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4compilationunitmapper_p.h b/src/qml/jsruntime/qv4compilationunitmapper_p.h
index 10ad0a6ede..c6773fdd0e 100644
--- a/src/qml/jsruntime/qv4compilationunitmapper_p.h
+++ b/src/qml/jsruntime/qv4compilationunitmapper_p.h
@@ -69,6 +69,7 @@ public:
CompiledData::Unit *get(
const QString &cacheFilePath, const QDateTime &sourceTimeStamp, QString *errorString);
+ static void invalidate(const QString &cacheFilePath);
private:
CompiledData::Unit *open(
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 9ab0bb5628..12225d3866 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -78,10 +78,21 @@
QTBUG-75585 for an explanation and possible workarounds.
*/
#define USE_QTZ_SYSTEM_ZONE
+#elif defined(Q_OS_WASM)
+/*
+ TODO: evaluate using this version of the code more generally, rather than
+ the #else branches of the various USE_QTZ_SYSTEM_ZONE choices. It might even
+ work better than the timezone variant; experiments needed.
+*/
+// Kludge around the lack of time-zone info using QDateTime.
+// It uses localtime() and friends to determine offsets from UTC.
+#define USE_QDT_LOCAL_TIME
#endif
#ifdef USE_QTZ_SYSTEM_ZONE
#include <QtCore/QTimeZone>
+#elif defined(USE_QDT_LOCAL_TIME)
+// QDateTime already included above
#else
# ifdef Q_OS_WIN
# include <windows.h>
@@ -356,6 +367,7 @@ static inline double MakeDate(double day, double time)
mean a whole day of DST offset for some zones, that have crossed the
international date line. This shall confuse client code.) The bug report
against the ECMAScript spec is https://github.com/tc39/ecma262/issues/725
+ and they've now changed the spec so that the following conforms to it ;^>
*/
static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time
@@ -363,6 +375,12 @@ static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC t
return QTimeZone::systemTimeZone().offsetFromUtc(
QDateTime::fromMSecsSinceEpoch(qint64(t), Qt::UTC)) * 1e3 - localTZA;
}
+#elif defined(USE_QDT_LOCAL_TIME)
+static inline double DaylightSavingTA(double t, double localTZA) // t is a UTC time
+{
+ return QDateTime::fromMSecsSinceEpoch(qint64(t), Qt::UTC
+ ).toLocalTime().offsetFromUtc() * 1e3 - localTZA;
+}
#else
// This implementation fails to take account of past changes in standard offset.
static inline double DaylightSavingTA(double t, double /*localTZA*/)
@@ -632,7 +650,9 @@ static inline double ParseString(const QString &s, double localTZA)
QStringLiteral("d MMMM, yyyy hh:mm"),
QStringLiteral("d MMMM, yyyy hh:mm:ss"),
+ // ISO 8601 and RFC 2822 with a GMT as prefix on its offset, or GMT as zone.
QStringLiteral("yyyy-MM-dd hh:mm:ss t"),
+ QStringLiteral("ddd, d MMM yyyy hh:mm:ss t"),
};
for (const QString &format : formats) {
@@ -722,6 +742,26 @@ static double getLocalTZA()
// TODO: QTimeZone::resetSystemTimeZone(), see QTBUG-56899 and comment above.
// Standard offset, with no daylight-savings adjustment, in ms:
return QTimeZone::systemTimeZone().standardTimeOffset(QDateTime::currentDateTime()) * 1e3;
+#elif defined(USE_QDT_LOCAL_TIME)
+ QDate today = QDate::currentDate();
+ QDateTime near = today.startOfDay(Qt::LocalTime);
+ // Early out if we're in standard time anyway:
+ if (!near.isDaylightTime())
+ return near.offsetFromUtc() * 1000;
+ int year, month;
+ today.getDate(&year, &month, nullptr);
+ // One of the solstices is probably in standard time:
+ QDate summer(year, 6, 21), winter(year - (month < 7 ? 1 : 0), 12, 21);
+ // But check the one closest to the present by preference, in case there's a
+ // standard time offset change between them:
+ QDateTime far = summer.startOfDay(Qt::LocalTime);
+ near = winter.startOfDay(Qt::LocalTime);
+ if (month > 3 && month < 10)
+ near.swap(far);
+ bool isDst = near.isDaylightTime();
+ if (isDst && far.isDaylightTime()) // Permanent DST, probably an hour west:
+ return (qMin(near.offsetFromUtc(), far.offsetFromUtc()) - 3600) * 1000;
+ return (isDst ? far : near).offsetFromUtc() * 1000;
#else
# ifdef Q_OS_WIN
TIME_ZONE_INFORMATION tzInfo;
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 6883c219bc..c047298aba 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -356,6 +356,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
if (ok && envMaxGCStackSize > 0)
m_maxGCStackSize = envMaxGCStackSize;
+ // We allocate guard pages around our stacks.
+ const size_t guardPages = 2 * WTF::pageSize();
+
memoryManager = new QV4::MemoryManager(this);
if (maxCallDepth == -1) {
@@ -366,7 +369,13 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
maxCallDepth = qEnvironmentVariableIntValue("QV4_MAX_CALL_DEPTH", &ok);
if (!ok || maxCallDepth <= 0) {
#if defined(QT_NO_DEBUG) && !defined(__SANITIZE_ADDRESS__) && !__has_feature(address_sanitizer)
+#ifdef Q_OS_QNX
+ maxCallDepth = 640; // QNX's stack is only 512k by default
+#elif defined(Q_OS_WIN)
+ maxCallDepth = 640; // We've seen crashes around 750.
+#else
maxCallDepth = 1234;
+#endif
#else
// no (tail call) optimization is done, so there'll be a lot mare stack frames active
maxCallDepth = 200;
@@ -379,9 +388,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
// reserve space for the JS stack
// we allow it to grow to a bit more than m_maxJSStackSize, as we can overshoot due to ScopedValues
// allocated outside of JIT'ed methods.
- *jsStack = WTF::PageAllocation::allocate(m_maxJSStackSize + 256*1024, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *jsStack = WTF::PageAllocation::allocate(
+ m_maxJSStackSize + 256*1024 + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
jsStackBase = (Value *)jsStack->base();
#ifdef V4_USE_VALGRIND
VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, m_maxJSStackSize + 256*1024);
@@ -389,9 +398,9 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine)
jsStackTop = jsStackBase;
- *gcStack = WTF::PageAllocation::allocate(m_maxGCStackSize, WTF::OSAllocator::JSVMStackPages,
- /* writable */ true, /* executable */ false,
- /* includesGuardPages */ true);
+ *gcStack = WTF::PageAllocation::allocate(
+ m_maxGCStackSize + guardPages, WTF::OSAllocator::JSVMStackPages,
+ /* writable */ true, /* executable */ false, /* includesGuardPages */ true);
{
ok = false;
@@ -1521,6 +1530,12 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, QMet
if (typeHint == QMetaType::Bool)
return QVariant(value.toBoolean());
+ if (typeHint == QMetaType::Double)
+ return QVariant(value.toNumber());
+
+ if (typeHint == QMetaType::Float)
+ return QVariant(float(value.toNumber()));
+
if (typeHint == QMetaType::QJsonValue)
return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
@@ -1996,6 +2011,25 @@ int ExecutionEngine::maxGCStackSize() const
return m_maxGCStackSize;
}
+/*!
+ \internal
+ Returns \a length converted to int if its safe to
+ pass to \c Scope::alloc.
+ Otherwise it throws a RangeError, and returns 0.
+ */
+int ExecutionEngine::safeForAllocLength(qint64 len64)
+{
+ if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max())) {
+ this->throwRangeError(QStringLiteral("Invalid array length."));
+ return 0;
+ }
+ if (len64 > qint64(this->jsStackLimit - this->jsStackTop)) {
+ this->throwRangeError(QStringLiteral("Array too large for apply()."));
+ return 0;
+ }
+ return len64;
+}
+
ReturnedValue ExecutionEngine::global()
{
return globalObject->asReturnedValue();
@@ -2188,7 +2222,7 @@ void ExecutionEngine::setQmlEngine(QQmlEngine *engine)
static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object)
{
- if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen)
+ if (object->as<QV4::QObjectWrapper>() || object->internalClass()->isFrozen())
return;
QV4::Scope scope(v4);
@@ -2297,6 +2331,8 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
case QMetaType::QByteArray:
if (const ArrayBuffer *ab = value.as<ArrayBuffer>())
*reinterpret_cast<QByteArray*>(data) = ab->asByteArray();
+ else if (const String *string = value.as<String>())
+ *reinterpret_cast<QByteArray*>(data) = string->toQString().toUtf8();
else
*reinterpret_cast<QByteArray*>(data) = QByteArray();
return true;
@@ -2462,25 +2498,6 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
}
}
-#if 0
- if (isQtVariant(value)) {
- const QVariant &var = variantValue(value);
- // ### Enable once constructInPlace() is in qt master.
- if (var.userType() == type) {
- QMetaType::constructInPlace(type, data, var.constData());
- return true;
- }
- if (var.canConvert(type)) {
- QVariant vv = var;
- vv.convert(type);
- Q_ASSERT(vv.userType() == type);
- QMetaType::constructInPlace(type, data, vv.constData());
- return true;
- }
-
- }
-#endif
-
// Try to use magic; for compatibility with qjsvalue_cast.
if (convertToNativeQObject(value, metaType, reinterpret_cast<void **>(data)))
@@ -2531,6 +2548,15 @@ bool ExecutionEngine::metaTypeFromJS(const Value &value, QMetaType metaType, voi
} else if (metaType == QMetaType::fromType<QJSValue>()) {
QJSValuePrivate::setValue(reinterpret_cast<QJSValue*>(data), value.asReturnedValue());
return true;
+ } else if (!isPointer) {
+ QVariant val;
+ if (QQml_valueTypeProvider()->createValueType(
+ metaType.id(), QJSValuePrivate::fromReturnedValue(value.asReturnedValue()), val)) {
+ Q_ASSERT(val.metaType() == metaType);
+ metaType.destruct(data);
+ metaType.construct(data, val.constData());
+ return true;
+ }
}
return false;
diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h
index db6bfcc84b..0d3b279377 100644
--- a/src/qml/jsruntime/qv4engine_p.h
+++ b/src/qml/jsruntime/qv4engine_p.h
@@ -694,6 +694,7 @@ public:
int maxGCStackSize() const;
bool checkStackLimits();
+ int safeForAllocLength(qint64 len64);
bool canJIT(Function *f = nullptr)
{
@@ -778,6 +779,9 @@ public:
int argc, void **args, QMetaType *types);
private:
+ template<int Frames>
+ friend struct ExecutionEngineCallDepthRecorder;
+
QV4::ReturnedValue fromData(
const QMetaType &type, const void *ptr, const QVariant *variant = nullptr);
@@ -813,12 +817,15 @@ private:
#define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
+template<int Frames = 1>
struct ExecutionEngineCallDepthRecorder
{
ExecutionEngine *ee;
- ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
- ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
+ ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ee->callDepth += Frames; }
+ ~ExecutionEngineCallDepthRecorder() { ee->callDepth -= Frames; }
+
+ bool hasOverflow() const { return ee->callDepth >= ExecutionEngine::maxCallDepth; }
};
inline bool ExecutionEngine::checkStackLimits()
diff --git a/src/qml/jsruntime/qv4executablecompilationunit.cpp b/src/qml/jsruntime/qv4executablecompilationunit.cpp
index ade5204f9e..7fe3862172 100644
--- a/src/qml/jsruntime/qv4executablecompilationunit.cpp
+++ b/src/qml/jsruntime/qv4executablecompilationunit.cpp
@@ -69,14 +69,16 @@
#include <QtCore/qcryptographichash.h>
#include <QtCore/QScopedValueRollback>
-#if defined(QML_COMPILE_HASH)
+static_assert(QV4::CompiledData::QmlCompileHashSpace > QML_COMPILE_HASH_LENGTH);
+
+#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0
# ifdef Q_OS_LINUX
// Place on a separate section on Linux so it's easier to check from outside
// what the hash version is.
__attribute__((section(".qml_compile_hash")))
# endif
-const char qml_compile_hash[48 + 1] = QML_COMPILE_HASH;
-static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) >= QML_COMPILE_HASH_LENGTH + 1,
+const char qml_compile_hash[QV4::CompiledData::QmlCompileHashSpace] = QML_COMPILE_HASH;
+static_assert(sizeof(QV4::CompiledData::Unit::libraryVersionHash) > QML_COMPILE_HASH_LENGTH,
"Compile hash length exceeds reserved size in data structure. Please adjust and bump the format version");
#else
# error "QML_COMPILE_HASH must be defined for the build of QtDeclarative to ensure version checking for cache files"
@@ -159,10 +161,10 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
data->regexpTableSize * sizeof(QV4::Value));
for (uint i = 0; i < data->regexpTableSize; ++i) {
const CompiledData::RegExp *re = data->regexpAt(i);
- uint f = re->flags;
+ uint f = re->flags();
const CompiledData::RegExp::Flags flags = static_cast<CompiledData::RegExp::Flags>(f);
runtimeRegularExpressions[i] = QV4::RegExp::create(
- engine, stringAt(re->stringIndex), flags);
+ engine, stringAt(re->stringIndex()), flags);
}
if (data->lookupTableSize) {
@@ -173,7 +175,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
QV4::Lookup *l = runtimeLookups + i;
CompiledData::Lookup::Type type
- = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags));
+ = CompiledData::Lookup::Type(uint(compiledLookups[i].typeAndFlags()));
if (type == CompiledData::Lookup::Type_Getter)
l->getter = QV4::Lookup::getterGeneric;
else if (type == CompiledData::Lookup::Type_Setter)
@@ -182,7 +184,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
l->globalGetter = QV4::Lookup::globalGetterGeneric;
else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter)
l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter;
- l->nameIndex = compiledLookups[i].nameIndex;
+ l->nameIndex = compiledLookups[i].nameIndex();
}
}
@@ -203,8 +205,8 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine)
runtimeClasses[i]
= runtimeClasses[i]->addMember(
engine->identifierTable->asPropertyKey(
- runtimeStrings[member->nameOffset]),
- member->isAccessor
+ runtimeStrings[member->nameOffset()]),
+ member->isAccessor()
? QV4::Attr_Accessor
: QV4::Attr_Data);
}
@@ -316,20 +318,8 @@ void ExecutableCompilationUnit::unlink()
propertyCaches.clear();
if (runtimeLookups) {
- for (uint i = 0; i < data->lookupTableSize; ++i) {
- QV4::Lookup &l = runtimeLookups[i];
- if (l.getter == QV4::QObjectWrapper::lookupGetter
- || l.setter == QV4::QObjectWrapper::lookupSetter
- || l.getter == QQmlTypeWrapper::lookupSingletonProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
- || l.qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
- if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache)
- pc->release();
- }
- }
+ for (uint i = 0; i < data->lookupTableSize; ++i)
+ runtimeLookups[i].releasePropertyCache();
}
dependentScripts.clear();
@@ -400,7 +390,7 @@ IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int com
const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable();
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr);
- namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
+ namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->objectId());
}
Q_ASSERT(!namedObjectCache.isEmpty());
return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
@@ -452,13 +442,14 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
// We need to first iterate over all inline components, as the containing component might create instances of them
// and in that case we need to add its object count
for (auto nodeIt = nodesSorted.rbegin(); nodeIt != nodesSorted.rend(); ++nodeIt) {
- const auto &ic = allICs.at(nodeIt->index);
+ const auto &ic = allICs.at(nodeIt->index());
int lastICRoot = ic.objectIndex;
for (int i = ic.objectIndex; i<objectCount(); ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
bool leftCurrentInlineComponent =
- (i != lastICRoot && obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
- || !(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent);
+ (i != lastICRoot
+ && obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot))
+ || !obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent);
if (leftCurrentInlineComponent)
break;
inlineComponentData[lastICRoot].totalBindingCount += obj->nBindings;
@@ -488,9 +479,9 @@ void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngi
int objectCount = 0;
for (quint32 i = 0, count = this->objectCount(); i < count; ++i) {
const QV4::CompiledData::Object *obj = objectAt(i);
- if (obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::InPartOfInlineComponent))
continue;
- }
+
bindingCount += obj->nBindings;
if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) {
const auto type = typeRef->type();
@@ -632,7 +623,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
referenceErrorMessage += QStringLiteral(" because ");
referenceErrorMessage += url.toString(QUrl::RemoveFragment);
referenceErrorMessage += QStringLiteral(" is not an object");
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
return nullptr;
}
@@ -651,7 +644,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
if (!valuePtr) {
QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference ");
referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
return nullptr;
}
imports[i] = valuePtr;
@@ -668,7 +663,9 @@ Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine)
if (!dependentModuleUnit->resolveExport(importName)) {
QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference ");
referenceErrorMessage += importName->toQString();
- engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column);
+ engine->throwReferenceError(
+ referenceErrorMessage, fileName(),
+ entry.location.line(), entry.location.column());
return nullptr;
}
}
@@ -860,8 +857,14 @@ bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorSt
return CompiledData::SaveableUnitPointer(unitData()).saveToDisk<char>(
[&unitUrl, errorString](const char *data, quint32 size) {
- return CompiledData::SaveableUnitPointer::writeDataToFile(localCacheFilePath(unitUrl), data,
- size, errorString);
+ const QString cachePath = localCacheFilePath(unitUrl);
+ if (CompiledData::SaveableUnitPointer::writeDataToFile(
+ cachePath, data, size, errorString)) {
+ CompilationUnitMapper::invalidate(cachePath);
+ return true;
+ }
+
+ return false;
});
}
@@ -891,7 +894,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind
{
using namespace CompiledData;
#if QT_CONFIG(translation)
- switch (binding->type) {
+ switch (binding->type()) {
case Binding::Type_TranslationById: {
const TranslationData &translation
= data->translations()[binding->value.translationDataIndex];
@@ -952,9 +955,15 @@ bool ExecutableCompilationUnit::verifyHeader(
}
}
-#if defined(QML_COMPILE_HASH)
- if (qstrcmp(qml_compile_hash, unit->libraryVersionHash) != 0) {
- *errorString = QStringLiteral("QML library version mismatch. Expected compile hash does not match");
+#if defined(QML_COMPILE_HASH) && defined(QML_COMPILE_HASH_LENGTH) && QML_COMPILE_HASH_LENGTH > 0
+ if (qstrncmp(qml_compile_hash, unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH) != 0) {
+ *errorString = QStringLiteral("QML compile hashes don't match. Found %1 expected %2")
+ .arg(QString::fromLatin1(
+ QByteArray(unit->libraryVersionHash, QML_COMPILE_HASH_LENGTH)
+ .toPercentEncoding()),
+ QString::fromLatin1(
+ QByteArray(qml_compile_hash, QML_COMPILE_HASH_LENGTH)
+ .toPercentEncoding()));
return false;
}
#else
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 6ab9a87ec0..d92714a9e2 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -208,7 +208,8 @@ QString Function::prettyName(const Function *function, const void *code)
QQmlSourceLocation Function::sourceLocation() const
{
- return QQmlSourceLocation(sourceFile(), compiledFunction->location.line, compiledFunction->location.column);
+ return QQmlSourceLocation(
+ sourceFile(), compiledFunction->location.line(), compiledFunction->location.column());
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 7577161c01..20afeff140 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -138,6 +138,7 @@ public:
inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; }
inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; }
inline bool isGenerator() const { return compiledFunction->flags & CompiledData::Function::IsGenerator; }
+ inline bool isClosureWrapper() const { return compiledFunction->flags & CompiledData::Function::IsClosureWrapper; }
QQmlSourceLocation sourceLocation() const;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index d3bafbe055..798cfc131d 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -387,15 +387,10 @@ ReturnedValue FunctionPrototype::method_apply(const QV4::FunctionObject *b, cons
if (!arr)
return v4->throwTypeError();
- const qint64 len64 = arr->getLength();
- if (len64 < 0ll || len64 > qint64(std::numeric_limits<int>::max()))
- return v4->throwRangeError(QStringLiteral("Invalid array length."));
- if (len64 > qint64(v4->jsStackLimit - v4->jsStackTop))
- return v4->throwRangeError(QStringLiteral("Array too large for apply()."));
-
- const uint len = uint(len64);
-
Scope scope(v4);
+ const uint len = v4->safeForAllocLength(arr->getLength());
+ CHECK_EXCEPTION();
+
Value *arguments = scope.alloc<Scope::Uninitialized>(len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 6eb7b306e0..3dd2870e5b 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -87,7 +87,6 @@ struct GeneratorPrototype : FunctionObject {
#define GeneratorObjectMembers(class, Member) \
Member(class, Pointer, ExecutionContext *, context) \
- Member(class, Pointer, GeneratorFunction *, function) \
Member(class, NoMark, GeneratorState, state) \
Member(class, NoMark, JSTypesStackFrame, cppFrame) \
Member(class, Pointer, ArrayObject *, values) \
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1493456853..0abdd76c96 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -307,7 +307,6 @@ struct PropertyAttributes
void clear() { m_all = 0; }
bool isEmpty() const { return !m_all; }
- uint flags() const { return m_flags; }
uint all() const { return m_all; }
bool operator==(PropertyAttributes other) {
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index 4287563c94..eabb220c50 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -178,7 +178,7 @@ void SharedInternalClassDataPrivate<PropertyKey>::setSize(uint s)
data->values.size = s;
}
-PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i)
+PropertyKey SharedInternalClassDataPrivate<PropertyKey>::at(uint i) const
{
Q_ASSERT(data && i < size());
return PropertyKey::fromId(data->values.values[i].rawValue());
@@ -265,6 +265,13 @@ namespace Heap {
void InternalClass::init(ExecutionEngine *engine)
{
+// InternalClass is automatically zeroed during allocation:
+// prototype = nullptr;
+// parent = nullptr;
+// size = 0;
+// numRedundantTransitions = 0;
+// flags = 0;
+
Base::init();
new (&propertyTable) PropertyHash();
new (&nameMap) SharedInternalClassData<PropertyKey>(engine);
@@ -273,13 +280,6 @@ void InternalClass::init(ExecutionEngine *engine)
this->engine = engine;
vtable = QV4::InternalClass::staticVTable();
-// prototype = nullptr;
-// parent = nullptr;
-// size = 0;
- extensible = true;
- isFrozen = false;
- isSealed = false;
- isUsedAsProto = false;
protoId = engine->newProtoId();
// Also internal classes need an internal class pointer. Simply make it point to itself
@@ -300,10 +300,8 @@ void InternalClass::init(Heap::InternalClass *other)
prototype = other->prototype;
parent = other;
size = other->size;
- extensible = other->extensible;
- isSealed = other->isSealed;
- isFrozen = other->isFrozen;
- isUsedAsProto = other->isUsedAsProto;
+ numRedundantTransitions = other->numRedundantTransitions;
+ flags = other->flags;
protoId = engine->newProtoId();
internalClass.set(engine, other->internalClass);
@@ -365,7 +363,99 @@ static void addDummyEntry(InternalClass *newClass, PropertyHash::Entry e)
++newClass->size;
}
-Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
+static PropertyAttributes attributesFromFlags(int flags)
+{
+ PropertyAttributes attributes;
+ attributes.m_all = uchar(flags);
+ return attributes;
+}
+
+static Heap::InternalClass *cleanInternalClass(Heap::InternalClass *orig)
+{
+ if (++orig->numRedundantTransitions < Heap::InternalClass::MaxRedundantTransitions)
+ return orig;
+
+ // We will generally add quite a few transitions here. We have 255 redundant ones.
+ // We can expect at least as many significant ones in addition.
+ std::vector<InternalClassTransition> transitions;
+
+ Scope scope(orig->engine);
+ Scoped<QV4::InternalClass> child(scope, orig);
+
+ {
+ quint8 remainingRedundantTransitions = orig->numRedundantTransitions;
+ QSet<PropertyKey> properties;
+ int structureChanges = 0;
+
+ Scoped<QV4::InternalClass> parent(scope, orig->parent);
+ while (parent && remainingRedundantTransitions > 0) {
+ Q_ASSERT(child->d() != scope.engine->classes[ExecutionEngine::Class_Empty]);
+ const auto it = std::find_if(
+ parent->d()->transitions.begin(), parent->d()->transitions.end(),
+ [&child](const InternalClassTransition &t) {
+ return child->d() == t.lookup;
+ });
+ Q_ASSERT(it != parent->d()->transitions.end());
+
+ if (it->flags & InternalClassTransition::StructureChange) {
+ // A structural change. Each kind of structural change has to be recorded only once.
+ if ((structureChanges & it->flags) != it->flags) {
+ transitions.push_back(*it);
+ structureChanges |= it->flags;
+ } else {
+ --remainingRedundantTransitions;
+ }
+ } else if (!properties.contains(it->id)) {
+ // We only need the final state of the property.
+ properties.insert(it->id);
+
+ // Property removal creates _two_ redundant transitions.
+ // We don't have to replay either, but numRedundantTransitions only records one.
+ if (it->flags != 0)
+ transitions.push_back(*it);
+ } else {
+ --remainingRedundantTransitions;
+ }
+
+ child = parent->d();
+ parent = child->d()->parent;
+ Q_ASSERT(child->d() != parent->d());
+ }
+ }
+
+ for (auto it = transitions.rbegin(); it != transitions.rend(); ++it) {
+ switch (it->flags) {
+ case InternalClassTransition::NotExtensible:
+ child = child->d()->nonExtensible();
+ continue;
+ case InternalClassTransition::VTableChange:
+ child = child->d()->changeVTable(it->vtable);
+ continue;
+ case InternalClassTransition::PrototypeChange:
+ child = child->d()->changePrototype(it->prototype);
+ continue;
+ case InternalClassTransition::ProtoClass:
+ child = child->d()->asProtoClass();
+ continue;
+ case InternalClassTransition::Sealed:
+ child = child->d()->sealed();
+ continue;
+ case InternalClassTransition::Frozen:
+ child = child->d()->frozen();
+ continue;
+ default:
+ Q_ASSERT(it->flags != 0);
+ Q_ASSERT(it->flags < InternalClassTransition::StructureChange);
+ child = child->addMember(it->id, attributesFromFlags(it->flags));
+ continue;
+ }
+ }
+
+ return child->d();
+}
+
+Heap::InternalClass *InternalClass::changeMember(
+ PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
if (!data.isEmpty())
data.resolve();
@@ -381,7 +471,7 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
}
if (data == propertyData.at(idx))
- return static_cast<Heap::InternalClass *>(this);
+ return this;
Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
@@ -394,7 +484,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
Q_ASSERT(!propertyData.at(idx).isAccessor());
// add a dummy entry for the accessor
- entry->setterIndex = newClass->size;
+ if (entry)
+ entry->setterIndex = newClass->size;
e->setterIndex = newClass->size;
addDummyEntry(newClass, *e);
}
@@ -403,7 +494,8 @@ Heap::InternalClass *InternalClass::changeMember(PropertyKey identifier, Propert
t.lookup = newClass;
Q_ASSERT(t.lookup);
- return newClass;
+
+ return cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
@@ -413,7 +505,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
if (proto)
proto->setUsedAsProto();
Q_ASSERT(prototype != proto);
- Q_ASSERT(!proto || proto->internalClass->isUsedAsProto);
+ Q_ASSERT(!proto || proto->internalClass->isUsedAsProto());
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::PrototypeChange };
temp.prototype = proto;
@@ -427,8 +519,7 @@ Heap::InternalClass *InternalClass::changePrototypeImpl(Heap::Object *proto)
newClass->prototype = proto;
t.lookup = newClass;
-
- return newClass;
+ return prototype ? cleanInternalClass(newClass) : newClass;
}
Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
@@ -449,12 +540,14 @@ Heap::InternalClass *InternalClass::changeVTableImpl(const VTable *vt)
t.lookup = newClass;
Q_ASSERT(t.lookup);
Q_ASSERT(newClass->vtable);
- return newClass;
+ return vtable == QV4::InternalClass::staticVTable()
+ ? newClass
+ : cleanInternalClass(newClass);
}
Heap::InternalClass *InternalClass::nonExtensible()
{
- if (!extensible)
+ if (!isExtensible())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::NotExtensible};
@@ -463,7 +556,7 @@ Heap::InternalClass *InternalClass::nonExtensible()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->extensible = false;
+ newClass->flags |= NotExtensible;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -500,7 +593,7 @@ Heap::InternalClass *InternalClass::addMember(PropertyKey identifier, PropertyAt
Heap::InternalClass *InternalClass::addMemberImpl(PropertyKey identifier, PropertyAttributes data, InternalClassEntry *entry)
{
- Transition temp = { { identifier }, nullptr, (int)data.flags() };
+ Transition temp = { { identifier }, nullptr, int(data.all()) };
Transition &t = lookupOrInsertTransition(temp);
if (entry) {
@@ -553,21 +646,23 @@ void InternalClass::removeMember(QV4::Object *object, PropertyKey identifier)
changeMember(object, identifier, Attr_Invalid);
#ifndef QT_NO_DEBUG
- // we didn't remove the data slot, just made it inaccessible
- Q_ASSERT(object->internalClass()->size == oldClass->size);
+ // We didn't remove the data slot, just made it inaccessible.
+ // ... unless we've rebuilt the whole class. Then all the deleted properties are gone.
+ Q_ASSERT(object->internalClass()->numRedundantTransitions == 0
+ || object->internalClass()->size == oldClass->size);
#endif
}
Heap::InternalClass *InternalClass::sealed()
{
- if (isSealed)
+ if (isSealed())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Sealed };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isSealed);
+ Q_ASSERT(t.lookup && t.lookup->isSealed());
return t.lookup;
}
@@ -575,7 +670,7 @@ Heap::InternalClass *InternalClass::sealed()
Scoped<QV4::InternalClass> ic(scope, engine->newClass(this));
Heap::InternalClass *s = ic->d();
- if (!isFrozen) { // freezing also makes all properties non-configurable
+ if (!isFrozen()) { // freezing also makes all properties non-configurable
for (uint i = 0; i < size; ++i) {
PropertyAttributes attrs = propertyData.at(i);
if (attrs.isEmpty())
@@ -584,7 +679,7 @@ Heap::InternalClass *InternalClass::sealed()
s->propertyData.set(i, attrs);
}
}
- s->isSealed = true;
+ s->flags |= Sealed;
t.lookup = s;
return s;
@@ -592,14 +687,14 @@ Heap::InternalClass *InternalClass::sealed()
Heap::InternalClass *InternalClass::frozen()
{
- if (isFrozen)
+ if (isFrozen())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, InternalClassTransition::Frozen };
Transition &t = lookupOrInsertTransition(temp);
if (t.lookup) {
- Q_ASSERT(t.lookup && t.lookup->isFrozen);
+ Q_ASSERT(t.lookup && t.lookup->isFrozen());
return t.lookup;
}
@@ -616,7 +711,7 @@ Heap::InternalClass *InternalClass::frozen()
attrs.setConfigurable(false);
f->propertyData.set(i, attrs);
}
- f->isFrozen = true;
+ f->flags |= Frozen;
t.lookup = f;
return f;
@@ -640,7 +735,7 @@ InternalClass *InternalClass::cryopreserved()
bool InternalClass::isImplicitlyFrozen() const
{
- if (isFrozen)
+ if (isFrozen())
return true;
for (uint i = 0; i < size; ++i) {
@@ -656,7 +751,7 @@ bool InternalClass::isImplicitlyFrozen() const
Heap::InternalClass *InternalClass::asProtoClass()
{
- if (isUsedAsProto)
+ if (isUsedAsProto())
return this;
Transition temp = { { PropertyKey::invalid() }, nullptr, Transition::ProtoClass };
@@ -665,7 +760,7 @@ Heap::InternalClass *InternalClass::asProtoClass()
return t.lookup;
Heap::InternalClass *newClass = engine->newClass(this);
- newClass->isUsedAsProto = true;
+ newClass->flags |= UsedAsProto;
t.lookup = newClass;
Q_ASSERT(t.lookup);
@@ -685,7 +780,7 @@ static void updateProtoUsage(Heap::Object *o, Heap::InternalClass *ic)
void InternalClass::updateProtoUsage(Heap::Object *o)
{
- Q_ASSERT(isUsedAsProto);
+ Q_ASSERT(isUsedAsProto());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_Empty);
Q_ASSERT(!ic->prototype);
@@ -698,6 +793,9 @@ void InternalClass::markObjects(Heap::Base *b, MarkStack *stack)
if (ic->prototype)
ic->prototype->mark(stack);
+ if (ic->parent)
+ ic->parent->mark(stack);
+
ic->nameMap.mark(stack);
}
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index c18133f4cd..37dbeded6f 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -173,7 +173,7 @@ struct SharedInternalClassDataPrivate<PropertyAttributes> {
uint size() const { return m_size; }
void setSize(uint s) { m_size = s; }
- PropertyAttributes at(uint i) { Q_ASSERT(data && i < m_alloc); return data[i]; }
+ PropertyAttributes at(uint i) const { Q_ASSERT(data && i < m_alloc); return data[i]; }
void set(uint i, PropertyAttributes t) { Q_ASSERT(data && i < m_alloc); data[i] = t; }
void mark(MarkStack *) {}
@@ -198,7 +198,7 @@ struct SharedInternalClassDataPrivate<PropertyKey> {
uint size() const;
void setSize(uint s);
- PropertyKey at(uint i);
+ PropertyKey at(uint i) const;
void set(uint i, PropertyKey t);
void mark(MarkStack *s);
@@ -289,24 +289,33 @@ struct InternalClassTransition
int flags;
enum {
// range 0-0xff is reserved for attribute changes
- NotExtensible = 0x100,
- VTableChange = 0x200,
- PrototypeChange = 0x201,
- ProtoClass = 0x202,
- Sealed = 0x203,
- Frozen = 0x204
+ StructureChange = 0x100,
+ NotExtensible = StructureChange | (1 << 0),
+ VTableChange = StructureChange | (1 << 1),
+ PrototypeChange = StructureChange | (1 << 2),
+ ProtoClass = StructureChange | (1 << 3),
+ Sealed = StructureChange | (1 << 4),
+ Frozen = StructureChange | (1 << 5),
};
bool operator==(const InternalClassTransition &other) const
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id || (id == other.id && flags < other.flags); }
+ { return flags < other.flags || (flags == other.flags && id < other.id); }
};
namespace Heap {
struct InternalClass : Base {
+ enum Flag {
+ NotExtensible = 1 << 0,
+ Sealed = 1 << 1,
+ Frozen = 1 << 2,
+ UsedAsProto = 1 << 3,
+ };
+ enum { MaxRedundantTransitions = 255 };
+
ExecutionEngine *engine;
const VTable *vtable;
quintptr protoId; // unique across the engine, gets changed whenever the proto chain changes
@@ -322,10 +331,13 @@ struct InternalClass : Base {
InternalClassTransition &lookupOrInsertTransition(const InternalClassTransition &t);
uint size;
- bool extensible;
- bool isSealed;
- bool isFrozen;
- bool isUsedAsProto;
+ quint8 numRedundantTransitions;
+ quint8 flags;
+
+ bool isExtensible() const { return !(flags & NotExtensible); }
+ bool isSealed() const { return flags & Sealed; }
+ bool isFrozen() const { return flags & Frozen; }
+ bool isUsedAsProto() const { return flags & UsedAsProto; }
void init(ExecutionEngine *engine);
void init(InternalClass *other);
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index c6d320ac20..70ddaf59c5 100644
--- a/src/qml/jsruntime/qv4jscall_p.h
+++ b/src/qml/jsruntime/qv4jscall_p.h
@@ -146,10 +146,12 @@ struct ScopedStackFrame {
return;
frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value)));
frame.jsFrame->context = context;
- if (auto *parent = frame.parentFrame())
+ if (auto *parent = frame.parentFrame()) {
frame.v4Function = parent->v4Function;
- else
+ frame.instructionPointer = parent->instructionPointer;
+ } else {
frame.v4Function = nullptr;
+ }
scope.engine->currentStackFrame = &frame;
}
~ScopedStackFrame() {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index a3ffdb5431..ad9760bfd6 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -646,6 +646,28 @@ struct Stringify
QString makeMember(const QString &key, const Value &v);
};
+class [[nodiscard]] CallDepthAndCycleChecker
+{
+ Q_DISABLE_COPY_MOVE(CallDepthAndCycleChecker);
+
+public:
+ CallDepthAndCycleChecker(Stringify *stringify, Object *o)
+ : m_callDepthRecorder(stringify->v4)
+ {
+ if (stringify->stackContains(o)) {
+ stringify->v4->throwTypeError(
+ QStringLiteral("Cannot convert circular structure to JSON"));
+ }
+
+ stringify->v4->checkStackLimits();
+ }
+
+ bool foundProblem() const { return m_callDepthRecorder.ee->hasException; }
+
+private:
+ ExecutionEngineCallDepthRecorder<1> m_callDepthRecorder;
+};
+
static QString quote(const QString &str)
{
QString product;
@@ -776,10 +798,9 @@ QString Stringify::makeMember(const QString &key, const Value &v)
QString Stringify::JO(Object *o)
{
- if (stackContains(o)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, o);
+ if (check.foundProblem())
return QString();
- }
Scope scope(v4);
@@ -836,10 +857,9 @@ QString Stringify::JO(Object *o)
QString Stringify::JA(Object *a)
{
- if (stackContains(a)) {
- v4->throwTypeError();
+ CallDepthAndCycleChecker check(this, a);
+ if (check.foundProblem())
return QString();
- }
Scope scope(a->engine());
diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp
index d3ea50867a..61c0d3daa7 100644
--- a/src/qml/jsruntime/qv4lookup.cpp
+++ b/src/qml/jsruntime/qv4lookup.cpp
@@ -41,6 +41,7 @@
#include "qv4jscall_p.h"
#include "qv4string_p.h"
#include <private/qv4identifiertable_p.h>
+#include <private/qv4qobjectwrapper_p.h>
QT_BEGIN_NAMESPACE
@@ -144,47 +145,76 @@ ReturnedValue Lookup::getterGeneric(Lookup *l, ExecutionEngine *engine, const Va
return l->resolvePrimitiveGetter(engine, object);
}
+static inline void setupObjectLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ Heap::InternalClass *ic1 = first.objectLookup.ic;
+ const uint offset1 = first.objectLookup.offset;
+ Heap::InternalClass *ic2 = second.objectLookup.ic;
+ const uint offset2 = second.objectLookup.offset;
+
+ l->objectLookupTwoClasses.ic = ic1;
+ l->objectLookupTwoClasses.ic2 = ic2;
+ l->objectLookupTwoClasses.offset = offset1;
+ l->objectLookupTwoClasses.offset2 = offset2;
+}
+
+static inline void setupProtoLookupTwoClasses(Lookup *l, const Lookup &first, const Lookup &second)
+{
+ const quintptr protoId1 = first.protoLookup.protoId;
+ const Value *data1 = first.protoLookup.data;
+ const quintptr protoId2 = second.protoLookup.protoId;
+ const Value *data2 = second.protoLookup.data;
+
+ l->protoLookupTwoClasses.protoId = protoId1;
+ l->protoLookupTwoClasses.protoId2 = protoId2;
+ l->protoLookupTwoClasses.data = data1;
+ l->protoLookupTwoClasses.data2 = data2;
+}
+
ReturnedValue Lookup::getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object)
{
if (const Object *o = object.as<Object>()) {
- Lookup first = *l;
- Lookup second = *l;
-
- ReturnedValue result = second.resolveGetter(engine, o);
- if (first.getter == getter0Inline && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0Inline : getter0Inlinegetter0MemberData;
+ // Do the resolution on a second lookup, then merge.
+ Lookup second;
+ memset(&second, 0, sizeof(Lookup));
+ second.nameIndex = l->nameIndex;
+ second.getter = getterGeneric;
+ const ReturnedValue result = second.resolveGetter(engine, o);
+
+ if (l->getter == getter0Inline
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, *l, second);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0Inline
+ : getter0Inlinegetter0MemberData;
return result;
}
- if (first.getter == getter0MemberData && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
- l->objectLookupTwoClasses.ic = second.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = first.objectLookup.ic;
- l->objectLookupTwoClasses.offset = second.objectLookup.offset;
- l->objectLookupTwoClasses.offset2 = first.objectLookup.offset;
- l->getter = second.getter == getter0Inline ? getter0Inlinegetter0MemberData : getter0MemberDatagetter0MemberData;
+
+ if (l->getter == getter0MemberData
+ && (second.getter == getter0Inline || second.getter == getter0MemberData)) {
+ setupObjectLookupTwoClasses(l, second, *l);
+ l->getter = (second.getter == getter0Inline)
+ ? getter0Inlinegetter0MemberData
+ : getter0MemberDatagetter0MemberData;
return result;
}
- if (first.getter == getterProto && second.getter == getterProto) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+
+ if (l->getter == getterProto && second.getter == getterProto) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoTwoClasses;
return result;
}
- if (first.getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
- l->protoLookupTwoClasses.protoId = first.protoLookup.protoId;
- l->protoLookupTwoClasses.protoId2 = second.protoLookup.protoId;
- l->protoLookupTwoClasses.data = first.protoLookup.data;
- l->protoLookupTwoClasses.data2 = second.protoLookup.data;
+
+ if (l->getter == getterProtoAccessor && second.getter == getterProtoAccessor) {
+ setupProtoLookupTwoClasses(l, *l, second);
l->getter = getterProtoAccessorTwoClasses;
return result;
}
+ // If any of the above options were true, the propertyCache was inactive.
+ second.releasePropertyCache();
}
l->getter = getterFallback;
@@ -371,7 +401,19 @@ ReturnedValue Lookup::getterIndexed(Lookup *l, ExecutionEngine *engine, const Va
}
l->getter = getterFallback;
return getterFallback(l, engine, object);
+}
+ReturnedValue Lookup::getterQObject(Lookup *lookup, ExecutionEngine *engine, const Value &object)
+{
+ const auto revertLookup = [lookup, engine, &object]() {
+ lookup->qobjectLookup.propertyCache->release();
+ lookup->qobjectLookup.propertyCache = nullptr;
+ lookup->getter = Lookup::getterGeneric;
+ return Lookup::getterGeneric(lookup, engine, object);
+ };
+
+ return QObjectWrapper::lookupGetterImpl(
+ lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
}
ReturnedValue Lookup::primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object)
@@ -463,23 +505,30 @@ bool Lookup::setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, co
bool Lookup::setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value)
{
- Lookup first = *l;
- Lookup second = *l;
+ // A precondition of this method is that l->objectLookup is the active variant of the union.
+ Q_ASSERT(l->setter == setter0MemberData || l->setter == setter0Inline);
if (object.isObject()) {
+
+ // As l->objectLookup is active, we can stash some members here, before resolving.
+ Heap::InternalClass *ic = l->objectLookup.ic;
+ const uint index = l->objectLookup.index;
+
if (!l->resolveSetter(engine, static_cast<Object *>(&object), value)) {
l->setter = setterFallback;
return false;
}
if (l->setter == Lookup::setter0MemberData || l->setter == Lookup::setter0Inline) {
- l->objectLookupTwoClasses.ic = first.objectLookup.ic;
- l->objectLookupTwoClasses.ic2 = second.objectLookup.ic;
- l->objectLookupTwoClasses.offset = first.objectLookup.index;
- l->objectLookupTwoClasses.offset2 = second.objectLookup.index;
+ l->objectLookupTwoClasses.ic = ic;
+ l->objectLookupTwoClasses.ic2 = ic;
+ l->objectLookupTwoClasses.offset = index;
+ l->objectLookupTwoClasses.offset2 = index;
l->setter = setter0setter0;
return true;
}
+
+ l->releasePropertyCache();
}
l->setter = setterFallback;
@@ -550,6 +599,13 @@ bool Lookup::setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, con
return setterFallback(l, engine, object, value);
}
+bool Lookup::setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v)
+{
+ // This setter just marks the presence of a qobjectlookup. It only does anything with it when
+ // running AOT-compiled code, though.
+ return QV4::Lookup::setterFallback(l, engine, object, v);
+}
+
bool Lookup::arrayLengthSetter(Lookup *, ExecutionEngine *engine, Value &object, const Value &value)
{
Q_ASSERT(object.isObject() && static_cast<Object &>(object).isArrayObject());
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index aab6b66597..301dad38fd 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -56,11 +56,16 @@
#include "qv4context_p.h"
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#include "qv4qmlcontext_p.h"
+#include <private/qqmltypewrapper_p.h>
QT_BEGIN_NAMESPACE
namespace QV4 {
+// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to
+// be trivially copyable. But you should never ever copy it. There are refcounted members
+// in there.
struct Q_QML_PRIVATE_EXPORT Lookup {
union {
ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -126,6 +131,12 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
QQmlPropertyData *propertyData;
} qobjectLookup;
struct {
+ quintptr isConstant; // This is a bool, encoded as 0 or 1. Both values are ignored by gc
+ quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
+ int coreIndex;
+ int notifyIndex;
+ } qobjectFallbackLookup;
+ struct {
Heap::InternalClass *ic;
quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
const QtPrivate::QMetaTypeInterface *metaType; // cannot use QMetaType; class must be trivial
@@ -191,6 +202,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
+ static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
@@ -208,6 +220,7 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
+ static bool setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
void markObjects(MarkStack *stack) {
@@ -220,6 +233,18 @@ struct Q_QML_PRIVATE_EXPORT Lookup {
void clear() {
memset(&markDef, 0, sizeof(markDef));
}
+
+ void releasePropertyCache()
+ {
+ if (getter == getterQObject
+ || getter == QQmlTypeWrapper::lookupSingletonProperty
+ || setter == setterQObject
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
+ || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty) {
+ if (QQmlPropertyCache *pc = qobjectLookup.propertyCache)
+ pc->release();
+ }
+ }
};
Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
@@ -227,6 +252,33 @@ Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
// across 32-bit and 64-bit (matters when cross-compiling).
Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData)
+{
+ lookup->releasePropertyCache();
+ Q_ASSERT(ddata->propertyCache != nullptr);
+ lookup->qobjectLookup.propertyCache = ddata->propertyCache;
+ lookup->qobjectLookup.propertyCache->addref();
+ lookup->qobjectLookup.propertyData = propertyData;
+}
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData,
+ const Object *self)
+{
+ lookup->qobjectLookup.ic = self->internalClass();
+ setupQObjectLookup(lookup, ddata, propertyData);
+}
+
+
+inline void setupQObjectLookup(
+ Lookup *lookup, const QQmlData *ddata, QQmlPropertyData *propertyData,
+ const Object *self, const Object *qmlType)
+{
+ lookup->qobjectLookup.qmlTypeIc = qmlType->internalClass();
+ setupQObjectLookup(lookup, ddata, propertyData, self);
+}
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 2ad1ecb6e3..564cd47203 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,17 +61,52 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(Heap::InternalClass *ic)
{
- d()->internalClass.set(engine(), ic);
- if (ic->isUsedAsProto)
- ic->updateProtoUsage(d());
Q_ASSERT(ic && ic->vtable);
- uint nInline = d()->vtable()->nInlineProperties;
- if (ic->size <= nInline)
- return;
- bool hasMD = d()->memberData != nullptr;
- uint requiredSize = ic->size - nInline;
- if (!(hasMD && requiredSize) || (hasMD && d()->memberData->values.size < requiredSize))
- d()->memberData.set(ic->engine, MemberData::allocate(ic->engine, requiredSize, d()->memberData));
+ Heap::Object *p = d();
+
+ if (ic->numRedundantTransitions < p->internalClass.get()->numRedundantTransitions) {
+ // IC was rebuilt. The indices are different now. We need to move everything.
+
+ Scope scope(engine());
+
+ // We allocate before setting the new IC. Protect it from GC.
+ Scoped<InternalClass> newIC(scope, ic);
+
+ // Pick the members of the old IC that are still valid in the new IC.
+ // Order them by index in memberData (or inline data).
+ Scoped<MemberData> newMembers(scope, MemberData::allocate(scope.engine, ic->size));
+ for (uint i = 0; i < ic->size; ++i)
+ newMembers->set(scope.engine, i, get(ic->nameMap.at(i)));
+
+ p->internalClass.set(scope.engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+
+ if (ic->size > nInline)
+ p->memberData.set(scope.engine, MemberData::allocate(ic->engine, ic->size - nInline));
+ else
+ p->memberData.set(scope.engine, nullptr);
+
+ const auto &memberValues = newMembers->d()->values;
+ for (uint i = 0; i < ic->size; ++i)
+ setProperty(i, memberValues[i]);
+ } else {
+ // The old indices are still the same. No need to move any values.
+ // We may need to re-allocate, though.
+
+ p->internalClass.set(ic->engine, ic);
+ const uint nInline = p->vtable()->nInlineProperties;
+ if (ic->size > nInline) {
+ const uint requiredSize = ic->size - nInline;
+ if ((p->memberData ? p->memberData->values.size : 0) < requiredSize) {
+ p->memberData.set(ic->engine, MemberData::allocate(
+ ic->engine, requiredSize, p->memberData));
+ }
+ }
+ }
+
+ if (ic->isUsedAsProto())
+ ic->updateProtoUsage(p);
+
}
void Object::getProperty(const InternalClassEntry &entry, Property *p) const
@@ -958,7 +993,7 @@ bool Object::virtualDefineOwnProperty(Managed *m, PropertyKey id, const Property
bool Object::virtualIsExtensible(const Managed *m)
{
- return m->d()->internalClass->extensible;
+ return m->d()->internalClass->isExtensible();
}
bool Object::virtualPreventExtensions(Managed *m)
@@ -982,7 +1017,7 @@ bool Object::virtualSetPrototypeOf(Managed *m, const Object *proto)
Heap::Object *protod = proto ? proto->d() : nullptr;
if (current == protod)
return true;
- if (!o->internalClass()->extensible)
+ if (!o->internalClass()->isExtensible())
return false;
Heap::Object *p = protod;
while (p) {
@@ -1013,6 +1048,8 @@ bool Object::setArrayLength(uint newLen)
} else {
if (newLen >= 0x100000)
initSparseArray();
+ else
+ ArrayData::realloc(this, arrayType(), newLen, false);
}
setArrayLengthUnchecked(newLen);
return ok;
diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp
index 26e1074fe3..1f518966d6 100644
--- a/src/qml/jsruntime/qv4profiling.cpp
+++ b/src/qml/jsruntime/qv4profiling.cpp
@@ -50,8 +50,8 @@ FunctionLocation FunctionCall::resolveLocation() const
{
return FunctionLocation(m_function->name()->toQString(),
m_function->executableCompilationUnit()->fileName(),
- m_function->compiledFunction->location.line,
- m_function->compiledFunction->location.column);
+ m_function->compiledFunction->location.line(),
+ m_function->compiledFunction->location.column());
}
FunctionCallProperties FunctionCall::properties() const
diff --git a/src/qml/jsruntime/qv4promiseobject.cpp b/src/qml/jsruntime/qv4promiseobject.cpp
index 83bfba9b11..e155f2c3ba 100644
--- a/src/qml/jsruntime/qv4promiseobject.cpp
+++ b/src/qml/jsruntime/qv4promiseobject.cpp
@@ -116,6 +116,8 @@ struct ResolveThenableEvent : public QEvent
} // namespace QV4
QT_END_NAMESPACE
+#include "moc_qv4promiseobject_p.cpp"
+
ReactionHandler::ReactionHandler(QObject *parent)
: QObject(parent)
{}
diff --git a/src/qml/jsruntime/qv4propertykey_p.h b/src/qml/jsruntime/qv4propertykey_p.h
index b5dca2d2ac..bb93dc518d 100644
--- a/src/qml/jsruntime/qv4propertykey_p.h
+++ b/src/qml/jsruntime/qv4propertykey_p.h
@@ -51,6 +51,7 @@
//
#include <private/qv4global_p.h>
+#include <QtCore/qhashfunctions.h>
QT_BEGIN_NAMESPACE
@@ -145,6 +146,7 @@ public:
bool operator ==(const PropertyKey &other) const { return val == other.val; }
bool operator !=(const PropertyKey &other) const { return val != other.val; }
bool operator <(const PropertyKey &other) const { return val < other.val; }
+ friend size_t qHash(const PropertyKey &key, size_t seed = 0) { return qHash(key.val, seed); }
};
}
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 65481e4539..21a91342fb 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -215,7 +215,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
if (context->imports() && name->startsWithUpper()) {
// Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports()->query(name, QQmlImport::AllowRecursion);
+ QQmlTypeNameCache::Result r = context->imports()->query<QQmlImport::AllowRecursion>(name);
if (r.isValid()) {
if (hasProperty)
@@ -306,11 +306,7 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
QQmlData *ddata = QQmlData::get(scopeObject, false);
if (ddata && ddata->propertyCache) {
ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, scopeObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
+ QV4::setupQObjectLookup(lookup, ddata, propertyData, val->objectValue());
lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupScopeObjectProperty;
}
}
@@ -337,14 +333,12 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r
if (propertyData) {
if (lookup) {
QQmlData *ddata = QQmlData::get(contextObject, false);
- if (ddata && ddata->propertyCache) {
+ if (ddata && ddata->propertyCache
+ && lookup->qmlContextPropertyGetter != contextGetterFunction) {
ScopedValue val(scope, base ? *base
: Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, contextObject)));
- const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue());
- lookup->qobjectLookup.ic = That->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = propertyData;
+ QV4::setupQObjectLookup(lookup, ddata, propertyData,
+ val->objectValue());
lookup->qmlContextPropertyGetter = contextGetterFunction;
}
} else if (originalLookup) {
@@ -643,6 +637,11 @@ ReturnedValue QQmlContextWrapper::lookupContextObjectProperty(Lookup *l, Executi
return QObjectWrapper::lookupGetterImpl(l, engine, obj, /*useOriginalProperty*/ true, revertLookup);
}
+ReturnedValue QQmlContextWrapper::lookupScopeFallbackProperty(Lookup *l, ExecutionEngine *engine, Value *base)
+{
+ return resolveQmlContextPropertyLookupGetter(l, engine, base);
+}
+
ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base)
{
Q_UNUSED(base);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 19324b8803..253df6536d 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -112,6 +112,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object
static ReturnedValue lookupIdObject(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupIdObjectInParentContext(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
+ static ReturnedValue lookupScopeFallbackProperty(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base);
static ReturnedValue lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 20ccb00093..8be952571a 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -250,7 +250,7 @@ QQmlPropertyData *QObjectWrapper::findProperty(
ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property)
{
- QQmlData::flushPendingBinding(object, QQmlPropertyIndex(property->coreIndex()));
+ QQmlData::flushPendingBinding(object, property->coreIndex());
if (property->isFunction() && !property->isVarProperty()) {
if (property->isVMEFunction()) {
@@ -275,7 +275,8 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje
QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : nullptr;
if (ep && ep->propertyCapture && !property->isConstant())
- ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
+ if (!property->isBindable() || ep->propertyCapture->expression->mustCaptureBindableProperty())
+ ep->propertyCapture->captureProperty(object, property->coreIndex(), property->notifyIndex());
if (property->isVarProperty()) {
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
@@ -776,7 +777,7 @@ bool QObjectWrapper::virtualPut(Managed *m, PropertyKey id, const Value &value,
QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
ScopedString name(scope, id.asStringOrSymbol());
- if (that->internalClass()->isFrozen) {
+ if (that->internalClass()->isFrozen()) {
QString error = QLatin1String("Cannot assign to property \"") +
name->toQString() + QLatin1String("\" of read-only object");
scope.engine->throwError(error);
@@ -944,37 +945,17 @@ ReturnedValue QObjectWrapper::virtualResolveLookupGetter(const Object *object, E
return QV4::Object::virtualResolveLookupGetter(object, engine, lookup);
}
- lookup->qobjectLookup.ic = This->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
- lookup->getter = QV4::QObjectWrapper::lookupGetter;
+ QV4::setupQObjectLookup(lookup, ddata, property, This);
+ lookup->getter = QV4::Lookup::getterQObject;
return lookup->getter(lookup, engine, *object);
}
-ReturnedValue QObjectWrapper::lookupGetter(Lookup *lookup, ExecutionEngine *engine, const Value &object)
-{
- const auto revertLookup = [lookup, engine, &object]() {
- lookup->qobjectLookup.propertyCache->release();
- lookup->qobjectLookup.propertyCache = nullptr;
- lookup->getter = Lookup::getterGeneric;
- return Lookup::getterGeneric(lookup, engine, object);
- };
-
- return lookupGetterImpl(lookup, engine, object, /*useOriginalProperty*/ false, revertLookup);
-}
-
ReturnedValue QObjectWrapper::lookupAttached(
Lookup *l, ExecutionEngine *engine, const Value &object)
{
return QV4::Lookup::getterGeneric(l, engine, object);
}
-bool QObjectWrapper::lookupSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v)
-{
- return QV4::Lookup::setterFallback(l, engine, object, v);
-}
-
bool QObjectWrapper::virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup,
const Value &value)
{
@@ -1256,8 +1237,7 @@ void Heap::QObjectWrapper::markObjects(Heap::Base *that, QV4::MarkStack *markSta
void QObjectWrapper::destroyObject(bool lastCall)
{
Heap::QObjectWrapper *h = d();
- if (!h->internalClass)
- return; // destroyObject already got called
+ Q_ASSERT(h->internalClass);
if (h->object()) {
QQmlData *ddata = QQmlData::get(h->object(), false);
@@ -1287,7 +1267,7 @@ void QObjectWrapper::destroyObject(bool lastCall)
}
}
- h->~Data();
+ h->destroy();
}
@@ -2012,7 +1992,7 @@ bool CallArgument::fromValue(QMetaType metaType, QV4::ExecutionEngine *engine, c
qvariantPtr->convert(callMetaType);
} else {
QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
- if (!mo.isNull()) {
+ if (!mo.isNull() && v.metaType().flags().testFlag(QMetaType::PointerToQObject)) {
QObject *obj = QQmlMetaType::toQObject(v);
if (obj != nullptr && !QQmlMetaObject::canConvert(obj, mo)) {
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index 37cb4d3cac..f7bdda5f6f 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -189,10 +189,7 @@ struct Q_QML_EXPORT QObjectWrapper : public Object
static ReturnedValue getProperty(ExecutionEngine *engine, QObject *object, QQmlPropertyData *property);
static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
- static ReturnedValue lookupGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
static ReturnedValue lookupAttached(Lookup *l, ExecutionEngine *engine, const Value &object);
- static bool lookupSetter(QV4::Lookup *l, QV4::ExecutionEngine *engine,
- QV4::Value &object, const QV4::Value &value);
template <typename ReversalFunctor> static ReturnedValue lookupGetterImpl(Lookup *l, ExecutionEngine *engine, const Value &object, bool useOriginalProperty, ReversalFunctor revert);
static bool virtualResolveLookupSetter(Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
diff --git a/src/qml/jsruntime/qv4reflect.cpp b/src/qml/jsruntime/qv4reflect.cpp
index 2a6c61f044..39a0b03dec 100644
--- a/src/qml/jsruntime/qv4reflect.cpp
+++ b/src/qml/jsruntime/qv4reflect.cpp
@@ -76,7 +76,10 @@ struct CallArgs {
static CallArgs createListFromArrayLike(Scope &scope, const Object *o)
{
- int len = o->getLength();
+ int len = scope.engine->safeForAllocLength(o->getLength());
+ if (scope.engine->hasException)
+ return {nullptr, 0};
+
Value *arguments = scope.alloc(len);
for (int i = 0; i < len; ++i) {
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 01a7878dae..f27754f4a3 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -2440,6 +2440,7 @@ QHash<const void *, const char *> Runtime::symbolTable()
{symbol<UMinus>(), "UMinus" },
{symbol<Instanceof>(), "Instanceof" },
+ {symbol<As>(), "As" },
{symbol<In>(), "In" },
{symbol<Add>(), "Add" },
{symbol<Sub>(), "Sub" },
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 0523d740fb..b0268afedd 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -219,7 +219,7 @@ public:
}
loadReference();
}
- if (index < size()) {
+ if (index < quint32(size())) {
if (hasProperty)
*hasProperty = true;
return engine()->fromVariant(at(index));
@@ -251,7 +251,7 @@ public:
loadReference();
}
- qsizetype count = size();
+ quint32 count = quint32(size());
const QMetaType valueMetaType = meta(d())->valueMetaType();
const QVariant element = engine()->toVariant(value, valueMetaType, false);
@@ -284,7 +284,7 @@ public:
return QV4::Attr_Invalid;
loadReference();
}
- return (index < size()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ return (index < quint32(size())) ? QV4::Attr_Data : QV4::Attr_Invalid;
}
struct OwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator
@@ -300,7 +300,7 @@ public:
s->loadReference();
}
- if (arrayIndex < s->size()) {
+ if (arrayIndex < quint32(s->size())) {
uint index = arrayIndex;
++arrayIndex;
if (attrs)
@@ -333,7 +333,7 @@ public:
loadReference();
}
- if (index >= size())
+ if (index >= quint32(size()))
return false;
/* according to ECMA262r3 it should be Undefined, */
@@ -709,3 +709,5 @@ int SequencePrototype::metaTypeForSequence(const QV4::Object *object)
}
QT_END_NAMESPACE
+
+#include "moc_qv4sequenceobject_p.cpp"
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index 603d33d6d8..48e4b5ff18 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -61,8 +61,8 @@
#include "qv4string_p.h"
#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qitemselectionmodel.h>
#endif
QT_REQUIRE_CONFIG(qml_sequence_object);
diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp
index a716c53aea..0a060e81a7 100644
--- a/src/qml/jsruntime/qv4stackframe.cpp
+++ b/src/qml/jsruntime/qv4stackframe.cpp
@@ -53,7 +53,7 @@ QString CppStackFrame::function() const
int CppStackFrame::lineNumber() const
{
- if (!v4Function)
+ if (!v4Function || instructionPointer <= 0)
return -1;
auto findLine = [](const CompiledData::CodeOffsetToLine &entry, uint offset) {
@@ -61,9 +61,9 @@ int CppStackFrame::lineNumber() const
};
const QV4::CompiledData::Function *cf = v4Function->compiledFunction;
- uint offset = instructionPointer;
+ const uint offset = instructionPointer;
const CompiledData::CodeOffsetToLine *lineNumbers = cf->lineNumberTable();
- uint nLineNumbers = cf->nLineNumbers;
+ const uint nLineNumbers = cf->nLineNumbers;
const CompiledData::CodeOffsetToLine *line = std::lower_bound(lineNumbers, lineNumbers + nLineNumbers, offset, findLine) - 1;
return line->line;
}
diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h
index d5d11ef660..a55f72e241 100644
--- a/src/qml/jsruntime/qv4string_p.h
+++ b/src/qml/jsruntime/qv4string_p.h
@@ -88,7 +88,7 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base
new (&textStorage) QStringPrivate(std::move(text));
}
- mutable std::aligned_storage<sizeof(QStringPrivate), alignof(QStringPrivate)>::type textStorage;
+ mutable struct { alignas(QStringPrivate) unsigned char data[sizeof(QStringPrivate)]; } textStorage;
mutable PropertyKey identifier;
mutable uint subtype;
mutable uint stringHash;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 94225ff0c7..ab07fe58a6 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -442,8 +442,8 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
Q_ASSERT(function->aotFunction);
Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
function->executableCompilationUnit()->fileName(),
- function->compiledFunction->location.line,
- function->compiledFunction->location.column);
+ function->compiledFunction->location.line(),
+ function->compiledFunction->location.column());
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
const qsizetype numFunctionArguments = function->aotFunction->argumentTypes.size();
@@ -461,9 +461,17 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
Q_ASSERT(argumentType.sizeOf() > 0);
Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
- argumentType.construct(arg);
- if (frame->argc() > i)
- QMetaType::convert(frame->argTypes()[i], frame->argv()[i], argumentType, arg);
+
+ if (argumentType == QMetaType::fromType<QVariant>()) {
+ if (frame->argc() > i)
+ new (arg) QVariant(frame->argTypes()[i], frame->argv()[i]);
+ else
+ new (arg) QVariant();
+ } else {
+ argumentType.construct(arg);
+ if (frame->argc() > i)
+ QMetaType::convert(frame->argTypes()[i], frame->argv()[i], argumentType, arg);
+ }
transformedArguments[i] = arg;
}
@@ -472,8 +480,10 @@ void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
const QMetaType frameReturn = frame->returnType();
Q_ALLOCA_DECLARE(void, transformedResult);
if (frame->returnValue() && returnType != frameReturn) {
- Q_ASSERT(returnType.sizeOf() > 0);
- Q_ALLOCA_ASSIGN(void, transformedResult, returnType.sizeOf());
+ if (returnType.sizeOf() > 0)
+ Q_ALLOCA_ASSIGN(void, transformedResult, returnType.sizeOf());
+ else
+ transformedResult = frame; // Some non-null marker value
}
QQmlPrivate::AOTCompiledContext aotContext;
@@ -523,8 +533,8 @@ ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine)
Function *function = frame->v4Function;
Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(),
function->executableCompilationUnit()->fileName(),
- function->compiledFunction->location.line,
- function->compiledFunction->location.column);
+ function->compiledFunction->location.line(),
+ function->compiledFunction->location.column());
Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling
QV4::Debugging::Debugger *debugger = engine->debugger();
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 0aeeb0ec5b..b9f06e4133 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -995,7 +995,7 @@ void MemoryManager::sweep(bool lastSweep, ClassDestroyStatsCallback classCountPt
if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = engine->m_multiplyWrappedQObjects) {
for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
- if (!it.value().isNullOrUndefined())
+ if (it.value().isNullOrUndefined())
it = multiplyWrappedQObjects->erase(it);
else
++it;
diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g
index 670564fea5..43d8474cee 100644
--- a/src/qml/parser/qqmljs.g
+++ b/src/qml/parser/qqmljs.g
@@ -1722,6 +1722,18 @@ Type: UiQualifiedId;
} break;
./
+Type: T_VAR;
+/. case $rule_number: Q_FALLTHROUGH(); ./
+
+Type: T_VOID;
+/.
+ case $rule_number: {
+ AST::UiQualifiedId *id = new (pool) AST::UiQualifiedId(stringRef(1));
+ id->identifierToken = loc(1);
+ sym(1).Type = new (pool) AST::Type(id->finish());
+ } break;
+./
+
TypeAnnotation: T_COLON Type;
/.
case $rule_number: {
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index 03955e0563..6bef117646 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -144,7 +144,7 @@ private:
mutable quint32 m_hash = 0;
};
-class Q_AUTOTEST_EXPORT QHashedCStringRef
+class QHashedCStringRef
{
public:
inline QHashedCStringRef();
@@ -157,7 +157,7 @@ public:
inline const char *constData() const;
inline int length() const;
- QString toUtf16() const;
+ Q_AUTOTEST_EXPORT QString toUtf16() const;
inline int utf16length() const;
inline void writeUtf16(QChar *) const;
inline void writeUtf16(quint16 *) const;
diff --git a/src/qml/qml/ftw/qintrusivelist_p.h b/src/qml/qml/ftw/qintrusivelist_p.h
index 8992be9f93..40dc45095f 100644
--- a/src/qml/qml/ftw/qintrusivelist_p.h
+++ b/src/qml/qml/ftw/qintrusivelist_p.h
@@ -241,7 +241,12 @@ typename QIntrusiveList<N, member>::iterator QIntrusiveList<N, member>::end()
template<class N, QIntrusiveListNode N::*member>
N *QIntrusiveList<N, member>::nodeToN(QIntrusiveListNode *node)
{
+ QT_WARNING_PUSH
+#if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1300
+ QT_WARNING_DISABLE_CLANG("-Wnull-pointer-subtraction")
+#endif
return (N *)((char *)node - ((char *)&(((N *)nullptr)->*member) - (char *)nullptr));
+ QT_WARNING_POP
}
QIntrusiveListNode::QIntrusiveListNode()
diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp
index ccc90cabbf..1b737ee308 100644
--- a/src/qml/qml/qqml.cpp
+++ b/src/qml/qml/qqml.cpp
@@ -344,9 +344,9 @@ static QVector<QTypeRevision> availableRevisions(const QMetaObject *metaObject)
return revisions;
const int propertyOffset = metaObject->propertyOffset();
const int propertyCount = metaObject->propertyCount();
- for (int propertyIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
- propertyIndex < propertyEnd; ++propertyIndex) {
- const QMetaProperty property = metaObject->property(propertyIndex);
+ for (int coreIndex = propertyOffset, propertyEnd = propertyOffset + propertyCount;
+ coreIndex < propertyEnd; ++coreIndex) {
+ const QMetaProperty property = metaObject->property(coreIndex);
if (int revision = property.revision())
revisions.append(QTypeRevision::fromEncodedVersion(revision));
}
@@ -720,6 +720,21 @@ void AOTCompiledContext::setReturnValueUndefined() const
}
}
+static void captureFallbackProperty(
+ QObject *object, int coreIndex, int notifyIndex, bool isConstant,
+ QQmlContextData *qmlContext)
+{
+ if (!qmlContext || isConstant)
+ return;
+
+ QQmlEngine *engine = qmlContext->engine();
+ Q_ASSERT(engine);
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ Q_ASSERT(ep);
+ if (QQmlPropertyCapture *capture = ep->propertyCapture)
+ capture->captureProperty(object, coreIndex, notifyIndex);
+}
+
static void captureObjectProperty(
QObject *object, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *property, QQmlContextData *qmlContext)
@@ -746,10 +761,10 @@ static bool inherits(const QQmlPropertyCache *descendent, const QQmlPropertyCach
enum class ObjectPropertyResult { OK, NeedsInit, Deleted };
-static ObjectPropertyResult loadObjectProperty(QV4::Lookup *l, QObject *object, void *target,
- QQmlContextData *qmlContext)
+static ObjectPropertyResult loadObjectProperty(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
{
- const QQmlData *qmlData = QQmlData::get(object);
+ QQmlData *qmlData = QQmlData::get(object);
if (!qmlData)
return ObjectPropertyResult::NeedsInit;
if (qmlData->isQueuedForDeletion)
@@ -759,11 +774,43 @@ static ObjectPropertyResult loadObjectProperty(QV4::Lookup *l, QObject *object,
if (!inherits(qmlData->propertyCache, propertyCache))
return ObjectPropertyResult::NeedsInit;
const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+
+ const int coreIndex = property->coreIndex();
+ if (qmlData->hasPendingBindingBit(coreIndex))
+ qmlData->flushPendingBinding(coreIndex);
+
captureObjectProperty(object, propertyCache, property, qmlContext);
property->readProperty(object, target);
return ObjectPropertyResult::OK;
}
+static ObjectPropertyResult loadFallbackProperty(
+ QV4::Lookup *l, QObject *object, void *target, QQmlContextData *qmlContext)
+{
+ QQmlData *qmlData = QQmlData::get(object);
+ if (qmlData && qmlData->isQueuedForDeletion)
+ return ObjectPropertyResult::Deleted;
+
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ if (!metaObject || metaObject != object->metaObject())
+ return ObjectPropertyResult::NeedsInit;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ if (qmlData && qmlData->hasPendingBindingBit(coreIndex))
+ qmlData->flushPendingBinding(coreIndex);
+
+ captureFallbackProperty(object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, qmlContext);
+
+ void *a[] = { target, nullptr };
+ metaObject->metacall(object, QMetaObject::ReadProperty, coreIndex, a);
+
+ return ObjectPropertyResult::OK;
+}
+
static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object, void *value)
{
const QQmlData *qmlData = QQmlData::get(object);
@@ -780,7 +827,67 @@ static ObjectPropertyResult storeObjectProperty(QV4::Lookup *l, QObject *object,
return ObjectPropertyResult::OK;
}
-static bool initObjectLookup(
+static ObjectPropertyResult storeFallbackProperty(QV4::Lookup *l, QObject *object, void *value)
+{
+ const QQmlData *qmlData = QQmlData::get(object);
+ if (qmlData && qmlData->isQueuedForDeletion)
+ return ObjectPropertyResult::Deleted;
+ Q_ASSERT(!QQmlData::wasDeleted(object));
+
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ if (!metaObject || metaObject != object->metaObject())
+ return ObjectPropertyResult::NeedsInit;
+
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlPropertyPrivate::removeBinding(object, QQmlPropertyIndex(coreIndex));
+
+ void *args[] = { value, nullptr };
+ metaObject->metacall(object, QMetaObject::WriteProperty, coreIndex, args);
+ return ObjectPropertyResult::OK;
+}
+
+static bool isTypeCompatible(QMetaType lookupType, QMetaType propertyType,
+ const AOTCompiledContext *aotContext)
+{
+ if (!lookupType.isValid()) {
+ // If type is invalid, then the calling code depends on the lookup
+ // to be set up in order to query the type, via lookupResultMetaType.
+ // We cannot verify the type in this case.
+ } else if ((lookupType.flags() & QMetaType::IsQmlList)
+ && (propertyType.flags() & QMetaType::IsQmlList)) {
+ // We want to check the value types here, but we cannot easily do it.
+ // Internally those are all QObject* lists, though.
+ } else if (lookupType.flags() & QMetaType::PointerToQObject) {
+ // We accept any base class as type, too
+
+ const QMetaObject *typeMetaObject = lookupType.metaObject();
+ const QMetaObject *foundMetaObject = propertyType.metaObject();
+ if (!foundMetaObject) {
+ if (QQmlEngine *engine = aotContext->qmlEngine()) {
+ foundMetaObject = QQmlEnginePrivate::get(engine)->metaObjectForType(
+ propertyType.id()).metaObject();
+ }
+ }
+
+ while (foundMetaObject && foundMetaObject != typeMetaObject)
+ foundMetaObject = foundMetaObject->superClass();
+
+ if (!foundMetaObject)
+ return false;
+ } else if (propertyType != lookupType) {
+ return false;
+ }
+ return true;
+}
+
+enum class ObjectLookupResult {
+ Failure,
+ Object,
+ Fallback
+};
+
+static ObjectLookupResult initObjectLookup(
const AOTCompiledContext *aotContext, QV4::Lookup *l, QObject *object, QMetaType type)
{
QV4::Scope scope(aotContext->engine->handle());
@@ -797,7 +904,7 @@ static bool initObjectLookup(
QQmlData *ddata = QQmlData::get(object, true);
Q_ASSERT(ddata);
if (ddata->isQueuedForDeletion)
- return false;
+ return ObjectLookupResult::Failure;
QQmlPropertyData *property;
if (!ddata->propertyCache) {
@@ -808,50 +915,36 @@ static bool initObjectLookup(
name.getPointer(), object, aotContext->qmlContext);
}
- if (!property)
- return false;
-
- const QMetaType propType = property->propType();
- if (!type.isValid()) {
- // If type is invalid, then the calling code depends on the lookup
- // to be set up in order to query the type, via lookupResultMetaType.
- // We cannot verify the type in this case.
- } else if ((type.flags() & QMetaType::IsQmlList) && (propType.flags() & QMetaType::IsQmlList)) {
- // We want to check the value types here, but we cannot easily do it.
- // Internally those are all QObject* lists, though.
- } else if (type.flags() & QMetaType::PointerToQObject) {
- // We accept any base class as type, too
-
- const QMetaObject *typeMetaObject = type.metaObject();
- const QMetaObject *foundMetaObject = propType.metaObject();
- if (!foundMetaObject) {
- if (QQmlEngine *engine = aotContext->qmlEngine()) {
- foundMetaObject = QQmlEnginePrivate::get(engine)->metaObjectForType(
- propType.id()).metaObject();
- }
- }
-
- while (foundMetaObject) {
- if (foundMetaObject == typeMetaObject)
- break;
- foundMetaObject = foundMetaObject->superClass();
- }
-
- if (!foundMetaObject)
- return false;
- } else if (propType != type) {
- return false;
+ if (!property) {
+ const QMetaObject *metaObject = object->metaObject();
+ if (!metaObject)
+ return ObjectLookupResult::Failure;
+
+ const int coreIndex = metaObject->indexOfProperty(
+ name->toQStringNoThrow().toUtf8().constData());
+ if (coreIndex < 0)
+ return ObjectLookupResult::Failure;
+
+ const QMetaProperty property = metaObject->property(coreIndex);
+ if (!isTypeCompatible(type, property.metaType(), aotContext))
+ return ObjectLookupResult::Failure;
+
+ l->releasePropertyCache();
+ // & 1 to tell the gc that this is not heap allocated; see markObjects in qv4lookup_p.h
+ l->qobjectFallbackLookup.metaObject = quintptr(metaObject) + 1;
+ l->qobjectFallbackLookup.coreIndex = coreIndex;
+ l->qobjectFallbackLookup.notifyIndex = property.notifySignalIndex();
+ l->qobjectFallbackLookup.isConstant = property.isConstant() ? 1 : 0;
+ return ObjectLookupResult::Fallback;
}
- Q_ASSERT(ddata->propertyCache);
+ if (!isTypeCompatible(type, property->propType(), aotContext))
+ return ObjectLookupResult::Failure;
- if (l->qobjectLookup.propertyCache)
- l->qobjectLookup.propertyCache->release();
+ Q_ASSERT(ddata->propertyCache);
- l->qobjectLookup.propertyCache = ddata->propertyCache;
- l->qobjectLookup.propertyCache->addref();
- l->qobjectLookup.propertyData = property;
- return true;
+ QV4::setupQObjectLookup(l, ddata, property);
+ return ObjectLookupResult::Object;
}
static bool initValueLookup(QV4::Lookup *l, QV4::ExecutableCompilationUnit *compilationUnit,
@@ -887,27 +980,46 @@ bool AOTCompiledContext::captureLookup(uint index, QObject *object) const
return false;
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->getter != QV4::QQmlTypeWrapper::lookupSingletonProperty
- && l->getter != QV4::QObjectWrapper::lookupGetter) {
- return false;
+ if (l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
+ || l->getter == QV4::Lookup::getterQObject) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(object, property->coreIndex());
+ captureObjectProperty(object, l->qobjectLookup.propertyCache, property, qmlContext);
+ return true;
}
- captureObjectProperty(
- object, l->qobjectLookup.propertyCache, l->qobjectLookup.propertyData, qmlContext);
- return true;
+ if (l->getter == QV4::Lookup::getterFallback) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(object, coreIndex);
+ captureFallbackProperty(
+ object, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, qmlContext);
+ return true;
+ }
+
+ return false;
}
bool AOTCompiledContext::captureQmlContextPropertyLookup(uint index) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupScopeObjectProperty
- && l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupContextObjectProperty) {
- return false;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
+ && l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty) {
+ const QQmlPropertyData *property = l->qobjectLookup.propertyData;
+ QQmlData::flushPendingBinding(qmlScopeObject, property->coreIndex());
+ captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache, property, qmlContext);
+ return true;
}
- captureObjectProperty(qmlScopeObject, l->qobjectLookup.propertyCache,
- l->qobjectLookup.propertyData, qmlContext);
- return true;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ QQmlData::flushPendingBinding(qmlScopeObject, coreIndex);
+ captureFallbackProperty(qmlScopeObject, coreIndex, l->qobjectFallbackLookup.notifyIndex,
+ l->qobjectFallbackLookup.isConstant, qmlContext);
+ return true;
+ }
+
+ return false;
}
QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
@@ -916,7 +1028,8 @@ QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty
|| l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupContextObjectProperty
|| l->getter == QV4::QQmlTypeWrapper::lookupSingletonProperty
- || l->getter == QV4::QObjectWrapper::lookupGetter) {
+ || l->getter == QV4::Lookup::getterQObject
+ || l->setter == QV4::Lookup::setterQObject) {
return l->qobjectLookup.propertyData->propType();
} else if (l->getter == QV4::QQmlValueTypeWrapper::lookupGetter) {
return QMetaType(l->qgadgetLookup.metaType);
@@ -927,6 +1040,14 @@ QMetaType AOTCompiledContext::lookupResultMetaType(uint index) const
|| l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupSingleton
|| l->getter == QV4::QObjectWrapper::lookupAttached) {
return QMetaType::fromType<QObject *>();
+ } else if (l->getter == QV4::Lookup::getterFallback
+ || l->setter == QV4::Lookup::setterFallback
+ || l->qmlContextPropertyGetter
+ == QV4::QQmlContextWrapper::lookupScopeFallbackProperty) {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l->qobjectFallbackLookup.metaObject - 1);
+ const int coreIndex = l->qobjectFallbackLookup.coreIndex;
+ return metaObject->property(coreIndex).metaType();
}
return QMetaType();
}
@@ -940,21 +1061,50 @@ void AOTCompiledContext::storeNameSloppy(uint nameIndex, void *value, QMetaType
QV4::Lookup l;
l.clear();
l.nameIndex = nameIndex;
- if (initObjectLookup(this, &l, qmlScopeObject, type)) {
- switch (storeObjectProperty(&l, qmlScopeObject, value)) {
- case ObjectPropertyResult::NeedsInit:
- engine->handle()->throwTypeError();
- break;
- case ObjectPropertyResult::Deleted:
- engine->handle()->throwTypeError(
- QStringLiteral("Value is null and could not be converted to an object"));
- break;
- case ObjectPropertyResult::OK:
- break;
+ ObjectPropertyResult storeResult = ObjectPropertyResult::NeedsInit;
+ switch (initObjectLookup(this, &l, qmlScopeObject, QMetaType())) {
+ case ObjectLookupResult::Object: {
+ const QMetaType propType = l.qobjectLookup.propertyData->propType();
+ if (type == propType) {
+ storeResult = storeObjectProperty(&l, qmlScopeObject, value);
+ } else {
+ QVariant var(propType);
+ propType.convert(type, value, propType, var.data());
+ storeResult = storeObjectProperty(&l, qmlScopeObject, var.data());
}
+
l.qobjectLookup.propertyCache->release();
- } else {
+ break;
+ }
+ case ObjectLookupResult::Fallback: {
+ const QMetaObject *metaObject
+ = reinterpret_cast<const QMetaObject *>(l.qobjectFallbackLookup.metaObject - 1);
+ const QMetaType propType
+ = metaObject->property(l.qobjectFallbackLookup.coreIndex).metaType();
+ if (type == propType) {
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, value);
+ } else {
+ QVariant var(propType);
+ propType.convert(type, value, propType, var.data());
+ storeResult = storeFallbackProperty(&l, qmlScopeObject, var.data());
+ }
+ break;
+ }
+ case ObjectLookupResult::Failure:
+ engine->handle()->throwTypeError();
+ return;
+ }
+
+ switch (storeResult) {
+ case ObjectPropertyResult::NeedsInit:
engine->handle()->throwTypeError();
+ break;
+ case ObjectPropertyResult::Deleted:
+ engine->handle()->throwTypeError(
+ QStringLiteral("Value is null and could not be converted to an object"));
+ break;
+ case ObjectPropertyResult::OK:
+ break;
}
}
@@ -1112,10 +1262,16 @@ void AOTCompiledContext::initLoadGlobalLookup(uint index) const
bool AOTCompiledContext::loadScopeObjectPropertyLookup(uint index, void *target) const
{
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->qmlContextPropertyGetter != QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeObjectProperty)
+ result = loadObjectProperty(l, qmlScopeObject, target, qmlContext);
+ else if (l->qmlContextPropertyGetter == QV4::QQmlContextWrapper::lookupScopeFallbackProperty)
+ result = loadFallbackProperty(l, qmlScopeObject, target, qmlContext);
+ else
return false;
- switch (loadObjectProperty(l, qmlScopeObject, target, qmlContext)) {
+ switch (result) {
case ObjectPropertyResult::NeedsInit:
return false;
case ObjectPropertyResult::Deleted:
@@ -1136,12 +1292,22 @@ void AOTCompiledContext::initLoadScopeObjectPropertyLookup(uint index, QMetaType
QV4::ExecutionEngine *v4 = engine->handle();
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (v4->hasException)
+ if (v4->hasException) {
amendException(v4);
- else if (initObjectLookup(this, l, qmlScopeObject, type))
+ return;
+ }
+
+ switch (initObjectLookup(this, l, qmlScopeObject, type)) {
+ case ObjectLookupResult::Object:
l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeObjectProperty;
- else
+ break;
+ case ObjectLookupResult::Fallback:
+ l->qmlContextPropertyGetter = QV4::QQmlContextWrapper::lookupScopeFallbackProperty;
+ break;
+ case ObjectLookupResult::Failure:
v4->throwTypeError();
+ break;
+ }
}
bool AOTCompiledContext::loadTypeLookup(uint index, void *target) const
@@ -1206,7 +1372,7 @@ void AOTCompiledContext::initLoadAttachedLookup(uint index, QObject *object) con
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
QV4::Scope scope(engine->handle());
QV4::ScopedString name(scope, compilationUnit->runtimeStrings[l->nameIndex]);
- QQmlTypeNameCache::Result r = qmlContext->imports()->query(name);
+ QQmlTypeNameCache::Result r = qmlContext->imports()->query<QQmlImport::AllowRecursion>(name);
if (!r.isValid() || !r.type.isValid()) {
scope.engine->throwTypeError();
@@ -1235,10 +1401,15 @@ bool AOTCompiledContext::getObjectLookup(uint index, QObject *object, void *targ
if (!object)
return doThrow();
- if (l->getter != QV4::QObjectWrapper::lookupGetter)
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->getter == QV4::Lookup::getterQObject)
+ result = loadObjectProperty(l, object, target, qmlContext);
+ else if (l->getter == QV4::Lookup::getterFallback)
+ result = loadFallbackProperty(l, object, target, qmlContext);
+ else
return false;
- switch (loadObjectProperty(l, object, target, qmlContext)) {
+ switch (result) {
case ObjectPropertyResult::Deleted:
return doThrow();
case ObjectPropertyResult::NeedsInit:
@@ -1258,10 +1429,17 @@ void AOTCompiledContext::initGetObjectLookup(uint index, QObject *object, QMetaT
amendException(v4);
} else {
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (initObjectLookup(this, l, object, type))
- l->getter = QV4::QObjectWrapper::lookupGetter;
- else
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->getter = QV4::Lookup::getterQObject;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->getter = QV4::Lookup::getterFallback;
+ break;
+ case ObjectLookupResult::Failure:
engine->handle()->throwTypeError();
+ break;
+ }
}
}
@@ -1310,7 +1488,12 @@ void AOTCompiledContext::initGetEnumLookup(
{
Q_ASSERT(!engine->hasError());
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- Q_ASSERT(metaObject);
+ if (!metaObject) {
+ engine->handle()->throwTypeError(
+ QStringLiteral("Cannot read property '%1' of undefined")
+ .arg(QString::fromUtf8(enumValue)));
+ return;
+ }
const int enumIndex = metaObject->indexOfEnumerator(enumerator);
const int value = metaObject->enumerator(enumIndex).keyToValue(enumValue);
l->qmlEnumValueLookup.encodedEnumValue = value;
@@ -1329,10 +1512,15 @@ bool AOTCompiledContext::setObjectLookup(uint index, QObject *object, void *valu
return doThrow();
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (l->setter != QV4::QObjectWrapper::lookupSetter)
+ ObjectPropertyResult result = ObjectPropertyResult::NeedsInit;
+ if (l->setter == QV4::Lookup::setterQObject)
+ result = storeObjectProperty(l, object, value);
+ else if (l->setter == QV4::Lookup::setterFallback)
+ result = storeFallbackProperty(l, object, value);
+ else
return false;
- switch (storeObjectProperty(l, object, value)) {
+ switch (result) {
case ObjectPropertyResult::Deleted:
return doThrow();
case ObjectPropertyResult::NeedsInit:
@@ -1352,10 +1540,17 @@ void AOTCompiledContext::initSetObjectLookup(uint index, QObject *object, QMetaT
amendException(v4);
} else {
QV4::Lookup *l = compilationUnit->runtimeLookups + index;
- if (initObjectLookup(this, l, object, type))
- l->setter = QV4::QObjectWrapper::lookupSetter;
- else
+ switch (initObjectLookup(this, l, object, type)) {
+ case ObjectLookupResult::Object:
+ l->setter = QV4::Lookup::setterQObject;
+ break;
+ case ObjectLookupResult::Fallback:
+ l->setter = QV4::Lookup::setterFallback;
+ break;
+ case ObjectLookupResult::Failure:
engine->handle()->throwTypeError();
+ break;
+ }
}
}
diff --git a/src/qml/qml/qqmlanybinding_p.h b/src/qml/qml/qqmlanybinding_p.h
index c999b9dce7..a83d4f3752 100644
--- a/src/qml/qml/qqmlanybinding_p.h
+++ b/src/qml/qml/qqmlanybinding_p.h
@@ -149,6 +149,30 @@ public:
/*!
\internal
+ Creates a binding for property \a prop from \a script.
+ \a obj is the scope object which shall be used for the function and \a ctxt its QML scope.
+ The binding is not installed on the property (but if a QQmlBinding is created, it has its
+ target set to \a prop).
+ */
+ static QQmlAnyBinding createFromScriptString(const QQmlProperty &prop, const QQmlScriptString &script,
+ QObject *obj, QQmlContext *ctxt)
+ {
+ QQmlAnyBinding binding;
+ auto propPriv = QQmlPropertyPrivate::get(prop);
+ if (prop.isBindable()) {
+ auto index = QQmlPropertyIndex(propPriv->core.coreIndex(), -1);
+ binding = QQmlPropertyBinding::createFromScriptString(&propPriv->core, script, obj, ctxt, prop.object(), index);
+ } else {
+ auto qmlBinding = QQmlBinding::create(&propPriv->core, script, obj, ctxt);
+ qmlBinding->setTarget(prop);
+ binding = qmlBinding;
+ }
+ return binding;
+ }
+
+
+ /*!
+ \internal
Removes the binding from \a prop if there is any.
*/
static void removeBindingFrom(QQmlProperty &prop)
diff --git a/src/qml/qml/qqmlapplicationengine.cpp b/src/qml/qml/qqmlapplicationengine.cpp
index e0ab25892f..83323a7087 100644
--- a/src/qml/qml/qqmlapplicationengine.cpp
+++ b/src/qml/qml/qqmlapplicationengine.cpp
@@ -73,7 +73,9 @@ void QQmlApplicationEnginePrivate::init()
&QCoreApplication::quit, Qt::QueuedConnection);
q->connect(q, &QQmlApplicationEngine::exit, QCoreApplication::instance(),
&QCoreApplication::exit, Qt::QueuedConnection);
- q->connect(q, SIGNAL(uiLanguageChanged()), q_func(), SLOT(_q_loadTranslations()));
+ QObject::connect(q, &QJSEngine::uiLanguageChanged, q, [this](){
+ _q_loadTranslations();
+ });
#if QT_CONFIG(translation)
QTranslator* qtTranslator = new QTranslator(q);
if (qtTranslator->load(QLocale(), QLatin1String("qt"), QLatin1String("_"), QLibraryInfo::path(QLibraryInfo::TranslationsPath), QLatin1String(".qm")))
@@ -89,11 +91,10 @@ void QQmlApplicationEnginePrivate::init()
void QQmlApplicationEnginePrivate::_q_loadTranslations()
{
#if QT_CONFIG(translation)
+ Q_Q(QQmlApplicationEngine);
if (translationsDirectory.isEmpty())
return;
- Q_Q(QQmlApplicationEngine);
-
QScopedPointer<QTranslator> translator(new QTranslator);
if (!uiLanguage.value().isEmpty()) {
QLocale locale(uiLanguage);
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 62275c792e..0b5081d491 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -394,19 +394,26 @@ protected:
}
};
-class QQmlTranslationBinding : public GenericBinding<QMetaType::QString> {
+class QQmlTranslationBinding : public GenericBinding<QMetaType::QString>, public QPropertyObserver {
public:
QQmlTranslationBinding(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
+ : QPropertyObserver(&QQmlTranslationBinding::onLanguageChange)
{
setCompilationUnit(compilationUnit);
m_binding = binding;
+ setSource(QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage);
}
QQmlSourceLocation sourceLocation() const override final
{
- return QQmlSourceLocation(m_compilationUnit->fileName(), m_binding->valueLocation.line, m_binding->valueLocation.column);
+ return QQmlSourceLocation(
+ m_compilationUnit->fileName(), m_binding->valueLocation.line(),
+ m_binding->valueLocation.column());
}
+ static void onLanguageChange(QPropertyObserver *observer, QUntypedPropertyData *)
+ { static_cast<QQmlTranslationBinding *>(observer)->update(); }
+
void doUpdate(const DeleteWatcher &watcher,
QQmlPropertyData::WriteFlags flags, QV4::Scope &scope) override final
{
@@ -528,8 +535,12 @@ Q_NEVER_INLINE bool QQmlBinding::slowWrite(const QQmlPropertyData &core,
value = v4engine->toVariant(result, QMetaType::fromType<QList<QObject *> >());
} else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)nullptr);
- } else if (core.propType().id() == qMetaTypeId<QList<QUrl> >()) {
- value = QQmlPropertyPrivate::urlSequence(v4engine->toVariant(result, QMetaType::fromType<QList<QUrl>>()));
+ } else if (core.propType() == QMetaType::fromType<QList<QUrl>>()) {
+ const QVariant resultVariant
+ = v4engine->toVariant(result, QMetaType::fromType<QList<QUrl>>());
+ value = QVariant::fromValue(QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? QQmlPropertyPrivate::urlSequence(resultVariant, context())
+ : QQmlPropertyPrivate::urlSequence(resultVariant));
} else if (!isVarProperty && metaType != QMetaType::fromType<QJSValue>()) {
value = v4engine->toVariant(result, metaType);
}
@@ -680,14 +691,34 @@ bool QQmlBinding::setTarget(QObject *object, const QQmlPropertyData &core, const
valueType ? valueType->coreIndex() : -1);
}
-bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+static const QQmlPropertyData *getObjectPropertyData(QObject *object, int coreIndex)
{
- m_target = object;
+ QQmlData *data = QQmlData::get(object, true);
+ if (!data)
+ return nullptr;
+ if (!data->propertyCache) {
+ data->propertyCache = QQmlMetaType::propertyCache(object->metaObject());
+ if (!data->propertyCache)
+ return nullptr;
+ data->propertyCache->addref();
+ }
+ const QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
+ Q_ASSERT(propertyData);
+ return propertyData;
+}
- if (!object) {
+bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, int valueTypeIndex)
+{
+ auto invalidate = [this]() {
+ m_target = nullptr;
m_targetIndex = QQmlPropertyIndex();
return false;
- }
+ };
+
+ if (!object)
+ return invalidate();
+
+ m_target = object;
for (bool isAlias = coreIsAlias; isAlias;) {
QQmlVMEMetaObject *vme = QQmlVMEMetaObject::getForProperty(object, coreIndex);
@@ -695,21 +726,25 @@ bool QQmlBinding::setTarget(QObject *object, int coreIndex, bool coreIsAlias, in
int aValueTypeIndex;
if (!vme->aliasTarget(coreIndex, &object, &coreIndex, &aValueTypeIndex)) {
// can't resolve id (yet)
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
+ return invalidate();
}
- if (valueTypeIndex == -1)
- valueTypeIndex = aValueTypeIndex;
- QQmlData *data = QQmlData::get(object, false);
- if (!data || !data->propertyCache) {
- m_target = nullptr;
- m_targetIndex = QQmlPropertyIndex();
- return false;
+ const QQmlPropertyData *propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ if (aValueTypeIndex != -1) {
+ if (propertyData->propType().flags().testFlag(QMetaType::PointerToQObject)) {
+ // deep alias
+ propertyData->readProperty(object, &object);
+ coreIndex = aValueTypeIndex;
+ valueTypeIndex = -1;
+ propertyData = getObjectPropertyData(object, coreIndex);
+ if (!propertyData)
+ return invalidate();
+ } else {
+ valueTypeIndex = aValueTypeIndex;
+ }
}
- QQmlPropertyData *propertyData = data->propertyCache->property(coreIndex);
- Q_ASSERT(propertyData);
m_target = object;
isAlias = propertyData->isAlias();
@@ -772,17 +807,23 @@ QVector<QQmlProperty> QQmlBinding::dependencies() const
for (int i = 0; i < senderMeta->propertyCount(); i++) {
QMetaProperty property = senderMeta->property(i);
if (property.notifySignalIndex() == QMetaObjectPrivate::signal(senderMeta, guard->signalIndex()).methodIndex()) {
- dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(senderObject->metaObject()->property(i).name())));
+ dependencies.push_back(QQmlProperty(senderObject, QString::fromUtf8(property.name())));
}
}
}
+ for (auto trigger = qpropertyChangeTriggers; trigger; trigger = trigger->next) {
+ QMetaProperty prop = trigger->property();
+ if (prop.isValid())
+ dependencies.push_back(QQmlProperty(trigger->target, QString::fromUtf8(prop.name())));
+ }
+
return dependencies;
}
bool QQmlBinding::hasDependencies() const
{
- return !activeGuards.isEmpty() || translationsCaptured() || qpropertyChangeTriggers;
+ return !activeGuards.isEmpty() || qpropertyChangeTriggers;
}
class QObjectPointerBinding: public QQmlNonbindingBinding
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 4e824fff03..7c3dab98c2 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -97,6 +97,8 @@ public:
~QQmlBinding() override;
+ bool mustCaptureBindableProperty() const final {return true;}
+
void setTarget(const QQmlProperty &);
bool setTarget(QObject *, const QQmlPropertyData &, const QQmlPropertyData *valueType);
bool setTarget(QObject *, int coreIndex, bool coreIsAlias, int valueTypeIndex);
@@ -131,6 +133,7 @@ public:
* Call this method from the UI thread.
*/
QVector<QQmlProperty> dependencies() const;
+ // This method is used internally to check whether a binding is constant and can be removed
virtual bool hasDependencies() const;
protected:
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 665d4e6c75..13ed3cf95b 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -114,12 +114,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
QV4::ExecutionEngine *engine = ctxt->engine()->handle();
- // If the function is marked as having a nested function, then the user wrote:
- // onSomeSignal: function() { /*....*/ }
- // So take that nested function:
- if (auto closure = function->nestedFunction()) {
- function = closure;
- } else {
+ if (!function->isClosureWrapper()) {
QList<QByteArray> signalParameters = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).parameterNames();
if (!signalParameters.isEmpty()) {
QString error;
@@ -136,7 +131,29 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(const QObject *target, int
QV4::Scoped<QV4::QmlContext> qmlContext(valueScope, scope);
if (!qmlContext)
qmlContext = QV4::QmlContext::create(engine->rootContext(), ctxt, scopeObject);
- setupFunction(qmlContext, function);
+ if (auto closure = function->nestedFunction()) {
+ // If the function is marked as having a nested function, then the user wrote:
+ // onSomeSignal: function() { /*....*/ }
+ // So take that nested function:
+ setupFunction(qmlContext, closure);
+ } else {
+ setupFunction(qmlContext, function);
+
+ // If it's a closure wrapper but we cannot directly access the nested function
+ // we need to run the outer function to get the nested one.
+ if (function->isClosureWrapper()) {
+ bool isUndefined = false;
+ QV4::ScopedFunctionObject result(
+ valueScope, QQmlJavaScriptExpression::evaluate(&isUndefined));
+
+ Q_ASSERT(!isUndefined);
+ Q_ASSERT(result->function());
+ Q_ASSERT(result->function()->compilationUnit == function->compilationUnit);
+
+ QV4::Scoped<QV4::ExecutionContext> callContext(valueScope, result->scope());
+ setupFunction(callContext, result->function());
+ }
+ }
}
void QQmlBoundSignalExpression::init(const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope)
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 0a3229b731..89635dec69 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -80,6 +80,8 @@ public:
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
+ bool mustCaptureBindableProperty() const final {return true;}
+
QString expression() const;
const QObject *target() const { return m_target; }
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 64698444ff..80f8c88973 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -159,11 +159,12 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
{
// ...
component = new QQmlComponent(engine, QUrl("http://www.example.com/main.qml"));
- if (component->isLoading())
- QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
- this, SLOT(continueLoading()));
- else
+ if (component->isLoading()) {
+ QObject::connect(component, &QQmlComponent::statusChanged,
+ this, &MyApplication::continueLoading);
+ } else {
continueLoading();
+ }
}
void MyApplication::continueLoading()
@@ -304,7 +305,7 @@ V4_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
Specifies whether the QQmlComponent should load the component immediately, or asynchonously.
\value PreferSynchronous Prefer loading/compiling the component immediately, blocking the thread.
- This is not always possible; for example, remote URLs will always load asynchronously.
+ This is not always possible; for example, remote URLs will always load asynchronously.
\value Asynchronous Load/compile the component in a background thread.
*/
@@ -344,6 +345,7 @@ void QQmlComponentPrivate::fromTypeData(const QQmlRefPointer<QQmlTypeData> &data
RequiredProperties &QQmlComponentPrivate::requiredProperties()
{
+ Q_ASSERT(state.creator);
return state.creator->requiredProperties();
}
@@ -417,7 +419,9 @@ QQmlComponent::~QQmlComponent()
qWarning().nospace().noquote() << QLatin1String(" ") << error;
}
- d->completeCreate();
+ // we might not have the creator anymore if the engine is gone
+ if (d->state.creator)
+ d->completeCreate();
}
if (d->typeData) {
@@ -428,14 +432,16 @@ QQmlComponent::~QQmlComponent()
/*!
\qmlproperty enumeration Component::status
+
This property holds the status of component loading. The status can be one of the
following:
+
\list
- \li Component.Null - no data is available for the component
- \li Component.Ready - the component has been loaded, and can be used to create instances.
- \li Component.Loading - the component is currently being loaded
- \li Component.Error - an error occurred while loading the component.
- Calling errorString() will provide a human-readable description of any errors.
+ \li \c{Component.Null} - no data is available for the component
+ \li \c{Component.Ready} - the component has been loaded, and can be used to create instances.
+ \li \c{Component.Loading} - the component is currently being loaded
+ \li \c{Component.Error} - an error occurred while loading the component.
+ Calling \l errorString() will provide a human-readable description of any errors.
\endlist
*/
@@ -766,7 +772,7 @@ QList<QQmlError> QQmlComponent::errors() const
/*!
\internal
- errorString is only meant as a way to get the errors in script
+ errorString() is only meant as a way to get the errors from QML side.
*/
QString QQmlComponent::errorString() const
{
@@ -807,9 +813,8 @@ QQmlComponent::QQmlComponent(QQmlComponentPrivate &dd, QObject *parent)
}
/*!
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a context specifies the context within which to create the object
- instance.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
If \a context is \nullptr (the default), it will create the instance in the
\l {QQmlEngine::rootContext()}{root context} of the engine.
@@ -828,8 +833,16 @@ QObject *QQmlComponent::create(QQmlContext *context)
Q_D(QQmlComponent);
QObject *rv = d->doBeginCreate(this, context);
- if (rv)
+ if (rv) {
completeCreate();
+ } else if (d->state.completePending) {
+ // overridden completCreate might assume that
+ // the object has actually been created
+ ++creationDepth.localData();
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(d->engine);
+ d->complete(ep, &d->state);
+ --creationDepth.localData();
+ }
if (rv && !d->requiredProperties().empty()) {
delete rv;
return nullptr;
@@ -838,9 +851,8 @@ QObject *QQmlComponent::create(QQmlContext *context)
}
/*!
- Create an object instance of this component, and initialize its toplevel
- properties with \a initialProperties. \a context specifies the context
- where the object instance is to be created.
+ Create an object instance of this component, within the specified \a context,
+ and initialize its top-level properties with \a initialProperties.
\omit
TODO: also mention errorString() when QTBUG-93239 is fixed
@@ -870,20 +882,21 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
}
/*!
- This method provides advanced control over component instance creation.
+ Create an object instance from this component, within the specified \a context.
+ Returns \nullptr if creation failed.
+
+ \note This method provides advanced control over component instance creation.
In general, programmers should use QQmlComponent::create() to create object
instances.
- Create an object instance from this component. Returns \nullptr if creation
- failed. \a publicContext specifies the context within which to create the object
- instance.
-
When QQmlComponent constructs an instance, it occurs in three steps:
+
\list 1
\li The object hierarchy is created, and constant values are assigned.
\li Property bindings are evaluated for the first time.
\li If applicable, QQmlParserStatus::componentComplete() is called on objects.
\endlist
+
QQmlComponent::beginCreate() differs from QQmlComponent::create() in that it
only performs step 1. QQmlComponent::completeCreate() must be called to
complete steps 2 and 3.
@@ -896,20 +909,21 @@ QObject *QQmlComponent::createWithInitialProperties(const QVariantMap& initialPr
\sa completeCreate(), QQmlEngine::ObjectOwnership
*/
-QObject *QQmlComponent::beginCreate(QQmlContext *publicContext)
+QObject *QQmlComponent::beginCreate(QQmlContext *context)
{
Q_D(QQmlComponent);
- Q_ASSERT(publicContext);
- return d->beginCreate(QQmlContextData::get(publicContext));
+ Q_ASSERT(context);
+ return d->beginCreate(QQmlContextData::get(context));
}
QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> context)
{
Q_Q(QQmlComponent);
auto cleanup = qScopeGuard([this] {
- if (!state.errors.isEmpty()) {
- for (const auto &e : qAsConst(state.errors))
+ if (!state.errors.isEmpty() && lcQmlComponentGeneral().isDebugEnabled()) {
+ for (const auto &e : qAsConst(state.errors)) {
qCDebug(lcQmlComponentGeneral) << "QQmlComponent: " << e.toString();
+ }
}
});
if (!context) {
@@ -961,8 +975,8 @@ QObject *QQmlComponentPrivate::beginCreate(QQmlRefPointer<QQmlContextData> conte
if (rv) {
QQmlData *ddata = QQmlData::get(rv);
Q_ASSERT(ddata);
- //top level objects should never get JS ownership.
- //if JS ownership is needed this needs to be explicitly undone (like in component.createObject())
+ // top-level objects should never get JS ownership.
+ // if JS ownership is needed this needs to be explicitly undone (like in createObject())
ddata->indestructible = true;
ddata->explicitIndestructibleSet = true;
ddata->rootObjectInCreation = false;
@@ -1022,20 +1036,20 @@ void QQmlComponentPrivate::complete(QQmlEnginePrivate *enginePriv, ConstructionS
}
/*!
- * \internal
- * Finds the matching toplevel property with name \a name of the component \a createdComponent.
- * If it was a required property or an alias to a required property contained in \a
- * requiredProperties, it is removed from it.
- *
- * If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
- * was found in requiredProperties.
- *
- * Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
- * for further processing (for instance, actually setting the property value).
- *
- * Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
- * classes which create components should not need it and should only need to call
- * setInitialProperties.
+ \internal
+ Finds the matching top-level property with name \a name of the component \a createdComponent.
+ If it was a required property or an alias to a required property contained in \a
+ requiredProperties, it is removed from it.
+
+ If wasInRequiredProperties is non-null, the referenced boolean is set to true iff the property
+ was found in requiredProperties.
+
+ Returns the QQmlProperty with name \a name (which might be invalid if there is no such property),
+ for further processing (for instance, actually setting the property value).
+
+ Note: This method is used in QQmlComponent and QQmlIncubator to manage required properties. Most
+ classes which create components should not need it and should only need to call
+ setInitialProperties.
*/
QQmlProperty QQmlComponentPrivate::removePropertyFromRequired(QObject *createdComponent, const QString &name, RequiredProperties &requiredProperties, bool* wasInRequiredProperties)
{
@@ -1146,14 +1160,14 @@ QQmlComponentAttached *QQmlComponent::qmlAttachedProperties(QObject *obj)
\a incubator. \a context specifies the context within which to create the object
instance.
- If \a context is 0 (the default), it will create the instance in the
+ If \a context is \nullptr (by default), it will create the instance in the
engine's \l {QQmlEngine::rootContext()}{root context}.
\a forContext specifies a context that this object creation depends upon.
If the \a forContext is being created asynchronously, and the
\l QQmlIncubator::IncubationMode is \l QQmlIncubator::AsynchronousIfNested,
- this object will also be created asynchronously. If \a forContext is 0
- (the default), the \a context will be used for this decision.
+ this object will also be created asynchronously.
+ If \a forContext is \nullptr (by default), the \a context will be used for this decision.
The created object and its creation status are available via the
\a incubator.
@@ -1201,8 +1215,7 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context, QQmlC
}
/*!
- Set toplevel \a properties of the \a component.
-
+ Set top-level \a properties of the \a component.
This method provides advanced control over component instance creation.
In general, programmers should use
@@ -1339,7 +1352,7 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
}
/*!
- \qmlmethod object Component::createObject(QtObject parent, object properties)
+ \qmlmethod QtObject Component::createObject(QtObject parent, object properties)
Creates and returns an object instance of this component that will have
the given \a parent and \a properties. The \a properties argument is optional.
@@ -1368,9 +1381,10 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
below creates an object with initial \c x and \c y values of 100 and 100, respectively:
\js
- var component = Qt.createComponent("Button.qml");
- if (component.status == Component.Ready)
- component.createObject(parent, {x: 100, y: 100});
+ const component = Qt.createComponent("Button.qml");
+ if (component.status === Component.Ready) {
+ component.createObject(parent, { x: 100, y: 100 });
+ }
\endjs
Dynamically created instances can be deleted with the \c destroy() method.
@@ -1408,10 +1422,18 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV
break;
}
}
- if (engine->hasException || !object) {
+ if (engine->hasException) {
qmlWarning(createdComponent, engine->catchExceptionAsQmlError());
continue;
}
+ if (!object) {
+ QQmlError error;
+ error.setUrl(qmlContext ? qmlContext->qmlContext()->url() : QUrl());
+ error.setDescription(QLatin1String("Cannot resolve property \"%1\".")
+ .arg(properties.join(u'.')));
+ qmlWarning(createdComponent, error);
+ continue;
+ }
name = engine->newString(properties.last());
object->put(name, val);
if (engine->hasException) {
@@ -1446,8 +1468,10 @@ QQmlError QQmlComponentPrivate::unsetRequiredPropertyToQQmlError(const RequiredP
}
error.setDescription(description);
error.setUrl(unsetRequiredProperty.fileUrl);
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(unsetRequiredProperty.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ unsetRequiredProperty.location.column()));
return error;
}
@@ -1521,7 +1545,7 @@ void QQmlComponent::createObject(QQmlV4Function *args)
}
/*!
- \qmlmethod object Component::incubateObject(Item parent, object properties, enumeration mode)
+ \qmlmethod object Component::incubateObject(QtObject parent, object properties, enumeration mode)
Creates an incubator for an instance of this component. Incubators allow new component
instances to be instantiated asynchronously and do not cause freezes in the UI.
@@ -1543,29 +1567,29 @@ void QQmlComponent::createObject(QQmlV4Function *args)
properties:
\list
- \li status The status of the incubator. Valid values are Component.Ready, Component.Loading and
+ \li \c status - The status of the incubator. Valid values are Component.Ready, Component.Loading and
Component.Error.
- \li object The created object instance. Will only be available once the incubator is in the
+ \li \c object - The created object instance. Will only be available once the incubator is in the
Ready status.
- \li onStatusChanged Specifies a callback function to be invoked when the status changes. The
+ \li \c onStatusChanged - Specifies a callback function to be invoked when the status changes. The
status is passed as a parameter to the callback.
- \li forceCompletion() Call to complete incubation synchronously.
+ \li \c{forceCompletion()} - Call to complete incubation synchronously.
\endlist
The following example demonstrates how to use an incubator:
\js
- var component = Qt.createComponent("Button.qml");
+ const component = Qt.createComponent("Button.qml");
- var incubator = component.incubateObject(parent, { x: 10, y: 10 });
- if (incubator.status != Component.Ready) {
+ const incubator = component.incubateObject(parent, { x: 10, y: 10 });
+ if (incubator.status !== Component.Ready) {
incubator.onStatusChanged = function(status) {
- if (status == Component.Ready) {
- print ("Object", incubator.object, "is now ready!");
+ if (status === Component.Ready) {
+ print("Object", incubator.object, "is now ready!");
}
- }
+ };
} else {
- print ("Object", incubator.object, "is ready immediately!");
+ print("Object", incubator.object, "is ready immediately!");
}
\endjs
@@ -1785,3 +1809,4 @@ void QV4::QmlIncubatorObject::statusChanged(QQmlIncubator::Status s)
QT_END_NAMESPACE
#include "moc_qqmlcomponent.cpp"
+#include "moc_qqmlcomponentattached_p.cpp"
diff --git a/src/qml/qml/qqmlcomponentattached_p.h b/src/qml/qml/qqmlcomponentattached_p.h
index b94d474d1f..2e63289c2d 100644
--- a/src/qml/qml/qqmlcomponentattached_p.h
+++ b/src/qml/qml/qqmlcomponentattached_p.h
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
+// implemented in qqmlcomponent.cpp
class Q_QML_PRIVATE_EXPORT QQmlComponentAttached : public QObject
{
Q_OBJECT
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index b6b90f13dc..5821aca595 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -76,11 +76,11 @@ QT_BEGIN_NAMESPACE
context->setContextProperty("myModel", &modelData);
QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
+ component.setData("import QtQuick 2.0; ListView { model: myModel }", QUrl());
QObject *window = component.create(context);
\endcode
- Note it is the responsibility of the creator to delete any QQmlContext it
+ \note It is the responsibility of the creator to delete any QQmlContext it
constructs. If the \c context object in the example is no longer needed when the
\c window component instance is destroyed, the \c context must be destroyed explicitly.
The simplest way to ensure this is to set \c window as the parent of \c context.
@@ -96,10 +96,10 @@ QT_BEGIN_NAMESPACE
object.
\code
- class MyDataSet : ... {
- ...
+ class MyDataSet : public QObject {
+ // ...
Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged)
- ...
+ // ...
};
MyDataSet myDataSet;
@@ -108,7 +108,7 @@ QT_BEGIN_NAMESPACE
context->setContextObject(&myDataSet);
QQmlComponent component(&engine);
- component.setData("import QtQuick 2.0\nListView { model: myModel }", QUrl());
+ component.setData("import QtQuick 2.0; ListView { model: myModel }", QUrl());
component.create(context);
\endcode
@@ -132,10 +132,10 @@ QT_BEGIN_NAMESPACE
QQmlContext *context1 = new QQmlContext(engine.rootContext());
QQmlContext *context2 = new QQmlContext(context1);
- context1->setContextProperty("a", 12);
- context1->setContextProperty("b", 12);
+ context1->setContextProperty("a", 9001);
+ context1->setContextProperty("b", 9001);
- context2->setContextProperty("b", 15);
+ context2->setContextProperty("b", 42);
\endcode
While QML objects instantiated in a context are not strictly owned by that
@@ -212,7 +212,7 @@ bool QQmlContext::isValid() const
}
/*!
- Return the context's QQmlEngine, or 0 if the context has no QQmlEngine or the
+ Return the context's QQmlEngine, or \nullptr if the context has no QQmlEngine or the
QQmlEngine was destroyed.
*/
QQmlEngine *QQmlContext::engine() const
@@ -222,7 +222,7 @@ QQmlEngine *QQmlContext::engine() const
}
/*!
- Return the context's parent QQmlContext, or 0 if this context has no
+ Return the context's parent QQmlContext, or \nullptr if this context has no
parent or if the parent has been destroyed.
*/
QQmlContext *QQmlContext::parentContext() const
@@ -235,7 +235,7 @@ QQmlContext *QQmlContext::parentContext() const
}
/*!
- Return the context object, or 0 if there is no context object.
+ Return the context object, or \nullptr if there is no context object.
*/
QObject *QQmlContext::contextObject() const
{
diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h
index 82d15b8102..2da9541e5a 100644
--- a/src/qml/qml/qqmlcontext.h
+++ b/src/qml/qml/qqmlcontext.h
@@ -108,6 +108,4 @@ private:
};
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QList<QObject*>)
-
#endif // QQMLCONTEXT_H
diff --git a/src/qml/qml/qqmlcontextdata.cpp b/src/qml/qml/qqmlcontextdata.cpp
index f7decc2992..c07d52e2a3 100644
--- a/src/qml/qml/qqmlcontextdata.cpp
+++ b/src/qml/qml/qqmlcontextdata.cpp
@@ -173,7 +173,7 @@ QQmlContextData::~QQmlContextData()
QQmlGuardedContextData *contextGuard = m_contextGuards;
while (contextGuard) {
QQmlGuardedContextData *next = contextGuard->next();
- next->reset();
+ contextGuard->reset();
contextGuard = next;
}
m_contextGuards = nullptr;
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index b0df4f26dc..62bcaa41c6 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -102,8 +102,8 @@ void QQmlCustomParser::clearErrors()
void QQmlCustomParser::error(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
exceptions << error;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index ff55ab49d4..27088e1032 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -258,7 +258,8 @@ public:
static void markAsDeleted(QObject *);
static void setQueuedForDeletion(QObject *);
- static inline void flushPendingBinding(QObject *, QQmlPropertyIndex propertyIndex);
+ static inline void flushPendingBinding(QObject *object, int coreIndex);
+ void flushPendingBinding(int coreIndex);
static QQmlPropertyCache *ensurePropertyCache(QJSEngine *engine, QObject *object)
{
@@ -279,8 +280,6 @@ private:
Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
Q_NEVER_INLINE static QQmlPropertyCache *createPropertyCache(QJSEngine *engine, QObject *object);
- void flushPendingBindingImpl(QQmlPropertyIndex index);
-
Q_ALWAYS_INLINE bool hasBitSet(int bit) const
{
uint offset = offsetForBit(bit);
@@ -399,11 +398,11 @@ void QQmlData::clearPendingBindingBit(int coreIndex)
clearBit(coreIndex * 2 + 1);
}
-void QQmlData::flushPendingBinding(QObject *o, QQmlPropertyIndex propertyIndex)
+void QQmlData::flushPendingBinding(QObject *object, int coreIndex)
{
- QQmlData *data = QQmlData::get(o, false);
- if (data && data->hasPendingBindingBit(propertyIndex.coreIndex()))
- data->flushPendingBindingImpl(propertyIndex);
+ QQmlData *data = QQmlData::get(object, false);
+ if (data && data->hasPendingBindingBit(coreIndex))
+ data->flushPendingBinding(coreIndex);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 4830558db4..ff8e2de238 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -162,7 +162,7 @@ QT_BEGIN_NAMESPACE
\endcode
*/
-bool QQmlEnginePrivate::qml_debugging_enabled = false;
+std::atomic<bool> QQmlEnginePrivate::qml_debugging_enabled{false};
bool QQmlEnginePrivate::s_designerMode = false;
bool QQmlEnginePrivate::designerMode()
@@ -379,138 +379,20 @@ The following functions are also on the Qt object.
The \c application object provides access to global application state
properties shared by many QML components.
- Its properties are:
-
- \table
- \row
- \li \c application.active
- \li
- Deprecated, use Qt.application.state == Qt.ApplicationActive instead.
-
- \row
- \li \c application.state
- \li
- This read-only property indicates the current state of the application.
-
- Possible values are:
-
- \list
- \li Qt.ApplicationActive - The application is the top-most and focused application, and the
- user is able to interact with the application.
- \li Qt.ApplicationInactive - The application is visible or partially visible, but not selected
- to be in front, the user cannot interact with the application.
- On desktop platforms, this typically means that the user activated
- another application. On mobile platforms, it is more common to
- enter this state when the OS is interrupting the user with for
- example incoming calls, SMS-messages or dialogs. This is usually a
- transient state during which the application is paused. The user
- may return focus to your application, but most of the time it will
- be the first indication that the application is going to be suspended.
- While in this state, consider pausing or stopping any activity that
- should not continue when the user cannot interact with your
- application, such as a video, a game, animations, or sensors.
- You should also avoid performing CPU-intensive tasks which might
- slow down the application in front.
- \li Qt.ApplicationSuspended - The application is suspended and not visible to the user. On
- mobile platforms, the application typically enters this state when
- the user returns to the home screen or switches to another
- application. While in this state, the application should ensure
- that the user perceives it as always alive and does not lose his
- progress, saving any persistent data. The application should cease
- all activities and be prepared for code execution to stop. While
- suspended, the application can be killed at any time without
- further warnings (for example when low memory forces the OS to purge
- suspended applications).
- \li Qt.ApplicationHidden - The application is hidden and runs in the background. This is the
- normal state for applications that need to do background processing,
- like playing music, while the user interacts with other applications.
- The application should free up all graphical resources when entering
- this state. A Qt Quick application should not usually handle this state
- at the QML level. Instead, you should unload the entire UI and reload
- the QML files whenever the application becomes active again.
- \endlist
-
- \row
- \li \c application.layoutDirection
- \li
- This read-only property can be used to query the default layout direction of the
- application. On system start-up, the default layout direction depends on the
- application's language. The property has a value of \c Qt.RightToLeft in locales
- where text and graphic elements are read from right to left, and \c Qt.LeftToRight
- where the reading direction flows from left to right. You can bind to this
- property to customize your application layouts to support both layout directions.
-
- Possible values are:
-
- \list
- \li Qt.LeftToRight - Text and graphics elements should be positioned
- from left to right.
- \li Qt.RightToLeft - Text and graphics elements should be positioned
- from right to left.
- \endlist
- \row
- \li \c application.font
- \li This read-only property holds the default application font as
- returned by \l QGuiApplication::font().
- \row
- \li \c application.arguments
- \li This is a string list of the arguments the executable was invoked with.
- \row
- \li \c application.name
- \li This is the application name set on the QCoreApplication instance. This property can be written
- to in order to set the application name.
- \row
- \li \c application.displayName (since Qt 5.9)
- \li This is the application display name set on the QGuiApplication instance. This property can be written
- to in order to set the application display name.
- \row
- \li \c application.version
- \li This is the application version set on the QCoreApplication instance. This property can be written
- to in order to set the application version.
- \row
- \li \c application.organization
- \li This is the organization name set on the QCoreApplication instance. This property can be written
- to in order to set the organization name.
- \row
- \li \c application.domain
- \li This is the organization domain set on the QCoreApplication instance. This property can be written
- to in order to set the organization domain.
-
- \row
- \li \c application.supportsMultipleWindows
- \li This read-only property can be used to determine whether or not the
- platform supports multiple windows. Some embedded platforms do not support
- multiple windows, for example.
-
- \row
- \li \c application.screens
- \li An array containing the descriptions of all connected screens. The
- elements of the array are objects with the same properties as the
- \l{Screen} attached object. In practice the array corresponds to the screen
- list returned by QGuiApplication::screens(). In addition to examining
- properties like name, width, height, etc., the array elements can also be
- assigned to the screen property of Window items, thus serving as an
- alternative to the C++ side's QWindow::setScreen(). This property has been
- added in Qt 5.9.
-
- \endtable
-
- The object also has one signal, aboutToQuit(), which is the same as \l QCoreApplication::aboutToQuit().
+ It is the same as the \l Application singleton.
The following example uses the \c application object to indicate
whether the application is currently active:
\snippet qml/application.qml document
- Note that when using QML without a QGuiApplication, the following properties will be undefined:
+ \note When using QML without a QGuiApplication, the following properties will be undefined:
\list
\li application.active
\li application.state
\li application.layoutDirection
\li application.font
\endlist
-
- \sa Screen, Window, {Window::screen}{Window.screen}
*/
/*!
@@ -807,17 +689,17 @@ void QQmlData::setQueuedForDeletion(QObject *object)
}
}
-void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index)
+void QQmlData::flushPendingBinding(int coreIndex)
{
- clearPendingBindingBit(index.coreIndex());
+ clearPendingBindingBit(coreIndex);
// Find the binding
QQmlAbstractBinding *b = bindings;
- while (b && (b->targetPropertyIndex().coreIndex() != index.coreIndex() ||
+ while (b && (b->targetPropertyIndex().coreIndex() != coreIndex ||
b->targetPropertyIndex().hasValueTypeIndex()))
b = b->nextBinding();
- if (b && b->targetPropertyIndex().coreIndex() == index.coreIndex() &&
+ if (b && b->targetPropertyIndex().coreIndex() == coreIndex &&
!b->targetPropertyIndex().hasValueTypeIndex())
b->setEnabled(true, QQmlPropertyData::BypassInterceptor |
QQmlPropertyData::DontRemoveBinding);
@@ -978,6 +860,16 @@ QQmlEngine::~QQmlEngine()
Once the component cache has been cleared, components must be loaded before
any new objects can be created.
+ \note Any existing objects created from QML components retain their types,
+ even if you clear the component cache. This includes singleton objects. If you
+ create more objects from the same QML code after clearing the cache, the new
+ objects will be of different types than the old ones. Assigning such a new
+ object to a property of its declared type belonging to an object created
+ before clearing the cache won't work.
+
+ As a general rule of thumb, make sure that no objects created from QML
+ components are alive when you clear the component cache.
+
\sa trimComponentCache()
*/
void QQmlEngine::clearComponentCache()
@@ -1368,21 +1260,12 @@ QJSValue QQmlEngine::singletonInstance<QJSValue>(int qmlTypeId)
QCoreApplication::installTranslator, to ensure that your user-interface
shows up-to-date translations.
- \note Due to a limitation in the implementation, this function
- refreshes all the engine's bindings, not only those that use strings
- marked for translation.
- This may be optimized in a future release.
-
\since 5.10
*/
void QQmlEngine::retranslate()
{
Q_D(QQmlEngine);
- for (QQmlRefPointer<QQmlContextData> context
- = QQmlContextData::get(d->rootContext)->childContexts();
- context; context = context->nextChild()) {
- context->refreshExpressions();
- }
+ d->translationLanguage.notify();
}
/*!
@@ -1541,7 +1424,7 @@ void QQmlData::deferData(
const QV4::CompiledData::Binding *binding = compiledObject->bindingTable();
for (quint32 i = 0; i < compiledObject->nBindings; ++i, ++binding) {
const QQmlPropertyData *property = propertyData.at(i);
- if (property && binding->flags & QV4::CompiledData::Binding::IsDeferredBinding)
+ if (property && binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding))
deferData->bindings.insert(property->coreIndex(), binding);
}
@@ -1886,7 +1769,7 @@ void QQmlEnginePrivate::cleanupScarceResources()
The newly added \a path will be first in the importPathList().
- \sa setImportPathList(), {QML Modules}
+ \sa setImportPathList(), {QML Modules}, {QML Import Path}
*/
void QQmlEngine::addImportPath(const QString& path)
{
@@ -1904,9 +1787,8 @@ void QQmlEngine::addImportPath(const QString& path)
provided by that module. A \c qmldir file is required for defining the
type version mapping and possibly QML extensions plugins.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
\sa addImportPath(), setImportPathList()
*/
@@ -1920,9 +1802,11 @@ QStringList QQmlEngine::importPathList() const
Sets \a paths as the list of directories where the engine searches for
installed modules in a URL-based directory structure.
- By default, the list contains the directory of the application executable,
- paths specified in the \c QML_IMPORT_PATH environment variable,
- and the builtin \c QmlImportsPath from QLibraryInfo.
+ By default, this list contains the paths mentioned in
+ \l {QML Import Path}.
+
+ \warning Calling setImportPathList does not preserve the default
+ import paths.
\sa importPathList(), addImportPath()
*/
@@ -2007,7 +1891,8 @@ bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList
Returns the directory where SQL and other offline
storage is placed.
- The SQL databases created with openDatabase() are stored here.
+ The SQL databases created with \c openDatabaseSync() are stored here.
+ \sa \l{Qt Quick Local Storage QML Types}
The default is QML/OfflineStorage in the platform-standard
user application data directory.
@@ -2406,4 +2291,6 @@ bool QQml_isFileCaseCorrect(const QString &fileName, int lengthIn /* = -1 */)
QT_END_NAMESPACE
+#include "moc_qqmlengine_p.cpp"
+
#include "moc_qqmlengine.cpp"
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 499f9dd492..77ea35d034 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -75,6 +75,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qthread.h>
+#include <QtCore/QMetaProperty>
#include <private/qobject_p.h>
@@ -83,6 +84,8 @@
#include <qproperty.h>
+#include <atomic>
+
QT_BEGIN_NAMESPACE
class QQmlContext;
@@ -132,6 +135,8 @@ struct QPropertyChangeTrigger : QPropertyObserver {
QObject *target = nullptr;
int propertyIndex = 0;
static void trigger(QPropertyObserver *, QUntypedPropertyData *);
+
+ QMetaProperty property() const;
};
struct TriggerList : QPropertyChangeTrigger {
@@ -159,6 +164,7 @@ public:
QRecyclePool<TriggerList> qPropertyTriggerPool;
QQmlContext *rootContext;
+ Q_OBJECT_BINDABLE_PROPERTY(QQmlEnginePrivate, QString, translationLanguage);
#if !QT_CONFIG(qml_debug)
static const quintptr profiler = 0;
@@ -275,7 +281,7 @@ public:
static bool designerMode();
static void activateDesignerMode();
- static bool qml_debugging_enabled;
+ static std::atomic<bool> qml_debugging_enabled;
mutable QMutex networkAccessManagerMutex;
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index cb9096ae66..3cf2bce588 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -206,7 +206,7 @@ QQmlExpression::~QQmlExpression()
}
/*!
- Returns the QQmlEngine this expression is associated with, or 0 if there
+ Returns the QQmlEngine this expression is associated with, or \nullptr if there
is no association or the QQmlEngine has been destroyed.
*/
QQmlEngine *QQmlExpression::engine() const
@@ -216,7 +216,7 @@ QQmlEngine *QQmlExpression::engine() const
}
/*!
- Returns the QQmlContext this expression is associated with, or 0 if there
+ Returns the QQmlContext this expression is associated with, or \nullptr if there
is no association or the QQmlContext has been destroyed.
*/
QQmlContext *QQmlExpression::context() const
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index 3df839a6a2..26c0cddb9e 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -76,6 +76,7 @@ public:
QVariant value(bool *isUndefined = nullptr);
QV4::ReturnedValue v4value(bool *isUndefined = nullptr);
+ bool mustCaptureBindableProperty() const final {return true;}
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp
index 14704a0442..c2fc291d48 100644
--- a/src/qml/qml/qqmlextensionplugin.cpp
+++ b/src/qml/qml/qqmlextensionplugin.cpp
@@ -43,6 +43,21 @@
QT_BEGIN_NAMESPACE
/*!
+ \since 5.0
+ \inmodule QtQml
+ \class QQmlExtensionPlugin
+ \brief The QQmlExtensionPlugin class provides an abstract base for custom QML extension plugins
+ with custom type registration functions.
+
+ \ingroup plugins
+
+ \note If you need to write a plugin manually (which is rare) you should always use
+ \l{QQmlEngineExtensionPlugin}. QQmlExtensionPlugin only provides the registerTypes() and
+ unregisterTypes() functions in addition. You should not use them, but rather declare your
+ types with \l{QML_ELEMENT} and friends and have the build system take care of the registration.
+*/
+
+/*!
\since 5.14
\inmodule QtQml
\class QQmlEngineExtensionPlugin
@@ -61,7 +76,6 @@ QT_BEGIN_NAMESPACE
/*!
\fn void QQmlExtensionPlugin::registerTypes(const char *uri)
- \internal
Registers the QML types in the given \a uri. Subclasses should implement
this to call qmlRegisterType() for all types which are provided by the extension
@@ -127,9 +141,10 @@ void QQmlExtensionPlugin::unregisterTypes()
}
/*!
- \internal
-*/
-
+ Initializes the extension from the \a uri using the \a engine. Here an application
+ plugin might, for example, expose some data or objects to QML,
+ as context properties on the engine's root context.
+ */
void QQmlExtensionPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
{
Q_UNUSED(engine);
@@ -168,9 +183,12 @@ void QQmlEngineExtensionPlugin::initializeEngine(QQmlEngine *engine, const char
/*!
\macro Q_IMPORT_QML_PLUGIN(PluginName)
- \relates <QQmlExtensionPlugin>
+ \since 6.2
+ \relates QQmlEngineExtensionPlugin
+
+ Ensures the plugin whose metadata-declaring class is named \a PluginName
+ is linked into static builds.
- Ensures that a QML plugin works in static builds.
\sa Q_IMPORT_PLUGIN
*/
diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h
index afd58e4032..f6fec10654 100644
--- a/src/qml/qml/qqmlextensionplugin.h
+++ b/src/qml/qml/qqmlextensionplugin.h
@@ -44,6 +44,12 @@
#include <QtCore/QUrl>
#include <QtQml/qqmlextensioninterface.h>
+#if defined(Q_CC_GHS)
+# define Q_GHS_KEEP_REFERENCE(S) QT_DO_PRAGMA(ghs reference S ##__Fv)
+#else
+# define Q_GHS_KEEP_REFERENCE(S)
+#endif
+
#define Q_IMPORT_QML_PLUGIN(PLUGIN) \
Q_IMPORT_PLUGIN(PLUGIN)
diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp
index 4db8981975..dc2734d7d1 100644
--- a/src/qml/qml/qqmlfile.cpp
+++ b/src/qml/qml/qqmlfile.cpp
@@ -516,58 +516,91 @@ bool QQmlFile::isLocalFile(const QUrl &url)
{
QString scheme = url.scheme();
- if ((scheme.length() == 4 && 0 == scheme.compare(QLatin1String(file_string), Qt::CaseInsensitive)) ||
- (scheme.length() == 3 && 0 == scheme.compare(QLatin1String(qrc_string), Qt::CaseInsensitive))) {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ if (scheme.length() == 4 && scheme.startsWith(QLatin1String(file_string), Qt::CaseInsensitive))
return true;
+ if (scheme.length() == 3 && scheme.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive))
+ return url.authority().isEmpty();
+
#if defined(Q_OS_ANDROID)
- } else if (scheme.length() == 6 && 0 == scheme.compare(QLatin1String(assets_string), Qt::CaseInsensitive)) {
- return true;
+ if ((scheme.length() == 6
+ && scheme.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive))
+ || (scheme.length() == 7
+ && scheme.startsWith(QLatin1String(content_string), Qt::CaseInsensitive))) {
+ return url.authority().isEmpty();
+ }
#endif
- } else {
+ return false;
+}
+
+static bool hasSchemeAndNoAuthority(const QString &url, const char *scheme, qsizetype schemeLength)
+{
+ const qsizetype urlLength = url.length();
+
+ if (urlLength < schemeLength + 1)
+ return false;
+
+ if (!url.startsWith(QLatin1String(scheme, scheme + schemeLength), Qt::CaseInsensitive))
+ return false;
+
+ if (url[schemeLength] != QLatin1Char(':'))
return false;
+
+ if (urlLength < schemeLength + 3)
+ return true;
+
+ const QLatin1Char slash('/');
+ if (url[schemeLength + 1] == slash && url[schemeLength + 2] == slash) {
+ // Exactly two slashes denote an authority. We don't want that.
+ if (urlLength < schemeLength + 4 || url[schemeLength + 3] != slash)
+ return false;
}
+
+ return true;
}
/*!
Returns true if \a url is a local file that can be opened with QFile.
-Local file urls have either a qrc:/ or file:// scheme.
+Local file urls have either a qrc: or file: scheme.
-\note On Android, urls with assets:/ scheme are also considered local files.
+\note On Android, urls with assets: or content: scheme are also considered local files.
*/
bool QQmlFile::isLocalFile(const QString &url)
{
- if (url.length() < 5 /* qrc:/ */)
+ if (url.length() < 4 /* qrc: */)
return false;
- QChar f = url[0];
-
- if (f == QLatin1Char('f') || f == QLatin1Char('F')) {
-
- return url.length() >= 7 /* file:// */ &&
- url.startsWith(QLatin1String(file_string), Qt::CaseInsensitive) &&
- url[4] == QLatin1Char(':') && url[5] == QLatin1Char('/') && url[6] == QLatin1Char('/');
-
- } else if (f == QLatin1Char('q') || f == QLatin1Char('Q')) {
-
- return url.length() >= 5 /* qrc:/ */ &&
- url.startsWith(QLatin1String(qrc_string), Qt::CaseInsensitive) &&
- url[3] == QLatin1Char(':') && url[4] == QLatin1Char('/');
-
+ switch (url[0].toLatin1()) {
+ case 'f':
+ case 'F': {
+ // file: URLs with two slashes following the scheme can be interpreted as local files
+ // where the slashes are part of the path. Therefore, disregard the authority.
+ // See QUrl::toLocalFile().
+ const qsizetype fileLength = strlen(file_string);
+ return url.startsWith(QLatin1String(file_string, file_string + fileLength),
+ Qt::CaseInsensitive)
+ && url.length() > fileLength
+ && url[fileLength] == QLatin1Char(':');
}
+ case 'q':
+ case 'Q':
+ return hasSchemeAndNoAuthority(url, qrc_string, strlen(qrc_string));
#if defined(Q_OS_ANDROID)
- else if (f == QLatin1Char('a') || f == QLatin1Char('A')) {
- return url.length() >= 8 /* assets:/ */ &&
- url.startsWith(QLatin1String(assets_string), Qt::CaseInsensitive) &&
- url[6] == QLatin1Char(':') && url[7] == QLatin1Char('/');
- } else if (f == QLatin1Char('c') || f == QLatin1Char('C')) {
- return url.length() >= 9 /* content:/ */ &&
- url.startsWith(QLatin1String(content_string), Qt::CaseInsensitive) &&
- url[7] == QLatin1Char(':') && url[8] == QLatin1Char('/');
- }
+ case 'a':
+ case 'A':
+ return hasSchemeAndNoAuthority(url, assets_string, strlen(assets_string));
+ case 'c':
+ case 'C':
+ return hasSchemeAndNoAuthority(url, content_string, strlen(content_string));
#endif
+ default:
+ break;
+ }
return false;
}
@@ -585,13 +618,10 @@ QString QQmlFile::urlToLocalFileOrQrc(const QUrl& url)
}
#if defined(Q_OS_ANDROID)
- else if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0) {
- if (url.authority().isEmpty())
- return url.toString();
- return QString();
- } else if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0) {
- return url.toString();
- }
+ if (url.scheme().compare(QLatin1String("assets"), Qt::CaseInsensitive) == 0)
+ return url.authority().isEmpty() ? url.toString() : QString();
+ if (url.scheme().compare(QLatin1String("content"), Qt::CaseInsensitive) == 0)
+ return url.authority().isEmpty() ? url.toString() : QString();
#endif
return url.toLocalFile();
@@ -603,11 +633,28 @@ static QString toLocalFile(const QString &url)
if (!file.isLocalFile())
return QString();
- //XXX TODO: handle windows hostnames: "//servername/path/to/file.txt"
+ // QUrl::toLocalFile() interprets two slashes as part of the path.
+ // Therefore windows hostnames like "//servername/path/to/file.txt" are preserved.
return file.toLocalFile();
}
+static bool isDoubleSlashed(const QString &url, qsizetype offset)
+{
+ const qsizetype urlLength = url.length();
+ if (urlLength < offset + 2)
+ return false;
+
+ const QLatin1Char slash('/');
+ if (url[offset] != slash || url[offset + 1] != slash)
+ return false;
+
+ if (urlLength < offset + 3)
+ return true;
+
+ return url[offset + 2] != slash;
+}
+
/*!
If \a url is a local file returns a path suitable for passing to QFile. Otherwise returns an
empty string.
@@ -615,23 +662,28 @@ empty string.
QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
if (url.startsWith(QLatin1String("qrc://"), Qt::CaseInsensitive)) {
- if (url.length() > 6)
- return QLatin1Char(':') + QStringView{url}.mid(6);
- return QString();
+ // Exactly two slashes are bad because that's a URL authority.
+ // One slash is fine and >= 3 slashes are file.
+ if (url.length() == 6 || url[6] != QLatin1Char('/')) {
+ Q_ASSERT(isDoubleSlashed(url, strlen("qrc:")));
+ return QString();
+ }
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
+ return QLatin1Char(':') + QStringView{url}.mid(6);
}
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
+ Q_ASSERT(!isDoubleSlashed(url, strlen("qrc:")));
if (url.length() > 4)
return QLatin1Char(':') + QStringView{url}.mid(4);
- return QString();
+ return QStringLiteral(":");
}
#if defined(Q_OS_ANDROID)
- else if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive)) {
- return url;
- } else if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive)) {
- return url;
- }
+ if (url.startsWith(QLatin1String("assets:"), Qt::CaseInsensitive))
+ return isDoubleSlashed(url, strlen("assets:")) ? QString() : url;
+ if (url.startsWith(QLatin1String("content:"), Qt::CaseInsensitive))
+ return isDoubleSlashed(url, strlen("content:")) ? QString() : url;
#endif
return toLocalFile(url);
diff --git a/src/qml/qml/qqmlfileselector.cpp b/src/qml/qml/qqmlfileselector.cpp
index 4b773adc3e..5b1264bfd7 100644
--- a/src/qml/qml/qqmlfileselector.cpp
+++ b/src/qml/qml/qqmlfileselector.cpp
@@ -90,8 +90,7 @@ QT_BEGIN_NAMESPACE
directories used for selection must start with a '+' character, so you will not accidentally
trigger this feature unless you have directories with such names inside your project.
- If a new QQmlFileSelector is set on the engine, the old one will be replaced. Use
- \l QQmlFileSelector::get() to query or use the existing instance.
+ If a new QQmlFileSelector is set on the engine, the old one will be replaced.
*/
/*!
@@ -147,7 +146,7 @@ QQmlFileSelectorPrivate::~QQmlFileSelectorPrivate()
/*!
Sets the QFileSelector instance for use by the QQmlFileSelector to \a selector.
QQmlFileSelector does not take ownership of the new QFileSelector. To reset QQmlFileSelector
- to use its internal QFileSelector instance, call setSelector(0).
+ to use its internal QFileSelector instance, call setSelector(\nullptr).
*/
void QQmlFileSelector::setSelector(QFileSelector *selector)
@@ -180,7 +179,9 @@ void QQmlFileSelector::setExtraSelectors(const QStringList &strings)
#if QT_DEPRECATED_SINCE(6, 0)
/*!
- \deprecated
+ \deprecated [6.0] The file selector should not be accessed after it
+ is set. It may be in use. See below for further details.
+
Gets the QQmlFileSelector currently active on the target \a engine.
This method is deprecated. You should not retrieve the files selector from an
diff --git a/src/qml/qml/qqmlguard_p.h b/src/qml/qml/qqmlguard_p.h
index 3ac63926a0..85b2b898df 100644
--- a/src/qml/qml/qqmlguard_p.h
+++ b/src/qml/qml/qqmlguard_p.h
@@ -110,19 +110,19 @@ template <typename T>
class QQmlStrongJSQObjectReference : public QQmlGuard<T>
{
public:
- void setObject(T *o, QObject *parent) {
+ void setObject(T *obj, QObject *parent) {
T *old = this->object();
- if (o == old)
+ if (obj == old)
return;
if (m_jsOwnership && old && old->parent() == parent)
QQml_setParent_noEvent(old, nullptr);
- this->QQmlGuard<T>::operator=(o);
+ this->QQmlGuard<T>::operator=(obj);
- if (o && !o->parent() && !QQmlData::keepAliveDuringGarbageCollection(o)) {
+ if (obj && !obj->parent() && !QQmlData::keepAliveDuringGarbageCollection(obj)) {
m_jsOwnership = true;
- QQml_setParent_noEvent(o, parent);
+ QQml_setParent_noEvent(obj, parent);
} else {
m_jsOwnership = false;
}
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index a5c11fa2f2..d04d6751cd 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -46,7 +46,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qlibraryinfo.h>
-#include <QtCore/qreadwritelock.h>
+#include <QtCore/qloggingcategory.h>
#include <QtQml/qqmlextensioninterface.h>
#include <QtQml/qqmlextensionplugin.h>
#include <private/qqmlextensionplugin_p.h>
@@ -1169,6 +1169,26 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba
return stableRelativePath;
}
+/* removes all file selector occurrences in path
+ firstPlus is the position of the initial '+' in the path
+ which we always have as we check for '+' to decide whether
+ we need to do some work at all
+*/
+static QString pathWithoutFileSelectors(QString path, // we want a copy of path
+ qsizetype firstPlus)
+{
+ do {
+ Q_ASSERT(path.at(firstPlus) == u'+');
+ const auto eos = path.size();
+ qsizetype terminatingSlashPos = firstPlus + 1;
+ while (terminatingSlashPos != eos && path.at(terminatingSlashPos) != u'/')
+ ++terminatingSlashPos;
+ path.remove(firstPlus, terminatingSlashPos - firstPlus + 1);
+ firstPlus = path.indexOf(u'+', firstPlus);
+ } while (firstPlus != -1);
+ return path;
+}
+
/*!
\internal
@@ -1215,10 +1235,42 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
typedef QQmlDirComponents::const_iterator ConstIterator;
const QQmlDirComponents &components = qmldir.components();
+ QMultiHash<QString, ConstIterator> baseFileName2ConflictingComponents;
+
ConstIterator cend = components.constEnd();
for (ConstIterator cit = components.constBegin(); cit != cend; ++cit) {
for (ConstIterator cit2 = components.constBegin(); cit2 != cit; ++cit2) {
if (cit2->typeName == cit->typeName && cit2->version == cit->version) {
+ // ugly heuristic to deal with file selectors
+ const auto comp2PotentialFileSelectorPos = cit2->fileName.indexOf(u'+');
+ const bool comp2MightHaveFileSelector = comp2PotentialFileSelectorPos != -1;
+ /* If we detect conflicting paths, we check if they agree when we remove anything looking like a
+ file selector.
+ We need to create copies of the filenames, otherwise QString::replace would modify the
+ existing file-names
+ */
+ QString compFileName1 = cit->fileName;
+ QString compFileName2 = cit2->fileName;
+ if (auto fileSelectorPos1 = compFileName1.indexOf(u'+'); fileSelectorPos1 != -1) {
+ // existing entry was file selector entry, fix it up
+ // it could also be the case that _both_ are using file selectors
+ QString baseName = comp2MightHaveFileSelector ? pathWithoutFileSelectors(compFileName2,
+ comp2PotentialFileSelectorPos)
+ : compFileName2;
+ if (pathWithoutFileSelectors(compFileName1, fileSelectorPos1) == baseName) {
+ baseFileName2ConflictingComponents.insert(baseName, cit);
+ baseFileName2ConflictingComponents.insert(baseName, cit2);
+ continue;
+ }
+ // fall through to error case
+ } else if (comp2MightHaveFileSelector) {
+ // new entry contains file selector (and we now that cit did not)
+ if (pathWithoutFileSelectors(compFileName2, comp2PotentialFileSelectorPos) == compFileName1) {
+ baseFileName2ConflictingComponents.insert(compFileName1, cit2);
+ continue;
+ }
+ // fall through to error case
+ }
// This entry clashes with a predecessor
QQmlError error;
error.setDescription(QQmlImportDatabase::tr("\"%1\" version %2.%3 is defined more than once in module \"%4\"")
@@ -1232,6 +1284,14 @@ QTypeRevision QQmlImportsPrivate::matchingQmldirVersion(
addVersion(cit->version);
}
+ // ensure that all components point to the actual base URL, and let the file selectors resolve them correctly during URL resolution
+ for (auto keyIt = baseFileName2ConflictingComponents.keyBegin(); keyIt != baseFileName2ConflictingComponents.keyEnd(); ++keyIt) {
+ const QString& baseFileName = *keyIt;
+ const auto conflictingComponents = baseFileName2ConflictingComponents.values(baseFileName);
+ for (ConstIterator component: conflictingComponents)
+ component->fileName = baseFileName;
+ }
+
typedef QList<QQmlDirParser::Script>::const_iterator SConstIterator;
const QQmlDirScripts &scripts = qmldir.scripts();
@@ -1369,8 +1429,12 @@ QTypeRevision QQmlImportsPrivate::addLibraryImport(
return matchingVersion;
if (inserted->qmlDirComponents.isEmpty() && inserted->qmlDirScripts.isEmpty()) {
- if (qmldir.plugins().isEmpty() && !qmldir.imports().isEmpty())
- return validVersion(); // This is a pure redirection
+ if (qmldir.plugins().isEmpty()) {
+ if (!qmldir.imports().isEmpty())
+ return validVersion(); // This is a pure redirection
+ if (qmldir.hasTypeInfo())
+ return validVersion(); // A pure C++ module without plugin
+ }
errors->prepend(moduleNotFoundError(uri, relevantVersion(uri, version)));
return QTypeRevision();
} else if (qmldir.hasContent()) {
@@ -1388,6 +1452,18 @@ QTypeRevision QQmlImportsPrivate::addFileImport(
const QString& uri, const QString &prefix, QTypeRevision version, uint flags,
QQmlImportDatabase *database, QList<QQmlError> *errors)
{
+ if (uri.startsWith(Slash) || uri.startsWith(Colon)) {
+ QQmlError error;
+ const QString fix = uri.startsWith(Slash) ? QLatin1String("file:") + uri
+ : QLatin1String("qrc") + uri;
+ error.setDescription(QQmlImportDatabase::tr(
+ "\"%1\" is not a valid import URL. "
+ "You can pass relative paths or URLs with schema, but not "
+ "absolute paths or resource paths. Try \"%2\".").arg(uri, fix));
+ errors->prepend(error);
+ return QTypeRevision();
+ }
+
Q_ASSERT(errors);
QQmlImportNamespace *nameSpace = importNamespace(prefix);
@@ -1616,7 +1692,7 @@ QTypeRevision QQmlImports::addLibraryImport(
qCDebug(lcQmlImport)
<< "addLibraryImport:" << qPrintable(baseUrl().toString())
- << uri << version << "as" << prefix;
+ << uri << "version '" << version << "'" << "as" << prefix;
return d->addLibraryImport(uri, prefix, version, qmldirIdentifier, qmldirUrl, flags,
importDb, errors);
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 2d27fed648..ba0b6286fd 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -42,6 +42,7 @@
#include <QtCore/qurl.h>
#include <QtCore/qcoreapplication.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qset.h>
#include <QtCore/qstringlist.h>
#include <QtQml/qqmlengine.h>
@@ -73,6 +74,8 @@ class QQmlImportDatabase;
class QQmlTypeLoader;
class QQmlTypeLoaderQmldirContent;
+const QLoggingCategory &lcQmlImport();
+
namespace QQmlImport {
enum RecursionRestriction { PreventRecursion, AllowRecursion };
}
@@ -217,6 +220,11 @@ class Q_QML_PRIVATE_EXPORT QQmlImportDatabase
public:
enum PathType { Local, Remote, LocalOrRemote };
+ enum LocalQmldirSearchLocation {
+ QmldirFileAndCache,
+ QmldirCacheOnly,
+ };
+
enum LocalQmldirResult {
QmldirFound,
QmldirNotFound,
@@ -240,7 +248,8 @@ public:
template<typename Callback>
LocalQmldirResult locateLocalQmldir(
- const QString &uri, QTypeRevision version, const Callback &callback);
+ const QString &uri, QTypeRevision version, LocalQmldirSearchLocation location,
+ const Callback &callback);
static QTypeRevision lockModule(const QString &uri, const QString &typeNamespace,
QTypeRevision version, QList<QQmlError> *errors);
@@ -273,7 +282,8 @@ private:
template<typename Callback>
QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
- const QString &uri, QTypeRevision version, const Callback &callback)
+ const QString &uri, QTypeRevision version,
+ QQmlImportDatabase::LocalQmldirSearchLocation location, const Callback &callback)
{
// Check cache first
@@ -301,7 +311,7 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
// Do not try to construct the cache if it already had any entries for the URI.
// Otherwise we might duplicate cache entries.
- if (result != QmldirNotFound)
+ if (location == QmldirCacheOnly || result != QmldirNotFound)
return result;
const bool hasInterceptors = !engine->urlInterceptors().isEmpty();
@@ -313,6 +323,7 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(
uri, localImportPaths, version);
+ QString qmldirAbsoluteFilePath;
for (QString qmldirPath : qmlDirPaths) {
if (hasInterceptors) {
const QUrl intercepted = engine->interceptUrl(
@@ -326,7 +337,7 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
}
}
- QString qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
+ qmldirAbsoluteFilePath = absoluteFilePath(qmldirPath);
if (!qmldirAbsoluteFilePath.isEmpty()) {
QString url;
const QString absolutePath = qmldirAbsoluteFilePath.left(
@@ -373,6 +384,15 @@ QQmlImportDatabase::LocalQmldirResult QQmlImportDatabase::locateLocalQmldir(
cache->qmldirPathUrl = QStringLiteral("intercepted");
}
qmldirCache.insert(uri, cache);
+
+ if (result == QmldirNotFound) {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir file not found";
+ }
+ } else {
+ qCDebug(lcQmlImport)
+ << "locateLocalQmldir:" << qPrintable(uri) << "module's qmldir found at"
+ << qmldirAbsoluteFilePath;
}
return result;
diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp
index 7d4ffcec3f..59f4bf296e 100644
--- a/src/qml/qml/qqmlincubator.cpp
+++ b/src/qml/qml/qqmlincubator.cpp
@@ -269,6 +269,7 @@ void QQmlIncubatorPrivate::forceCompletion(QQmlInstantiationInterrupt &i)
}
}
+
void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
{
if (!compilationUnit)
@@ -280,6 +281,20 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
// get a copy of the engine pointer as it might get reset;
QQmlEnginePrivate *enginePriv = this->enginePriv;
+ // Incubating objects takes quite a bit more stack space than our usual V4 function
+ enum { EstimatedSizeInV4Frames = 2 };
+ QV4::ExecutionEngineCallDepthRecorder<EstimatedSizeInV4Frames> callDepthRecorder(
+ compilationUnit->engine);
+ if (callDepthRecorder.hasOverflow()) {
+ QQmlError error;
+ error.setMessageType(QtCriticalMsg);
+ error.setUrl(compilationUnit->url());
+ error.setDescription(QQmlComponent::tr("Maximum call stack size exceeded."));
+ errors << error;
+ progress = QQmlIncubatorPrivate::Completed;
+ goto finishIncubate;
+ }
+
if (!vmeGuard.isOK()) {
QQmlError error;
error.setMessageType(QtInfoMsg);
diff --git a/src/qml/qml/qqmlirloader.cpp b/src/qml/qml/qqmlirloader.cpp
index ee75a2b4f7..c2d9aa941c 100644
--- a/src/qml/qml/qqmlirloader.cpp
+++ b/src/qml/qml/qqmlirloader.cpp
@@ -101,10 +101,11 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
serializedObject->location);
object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
- object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
- object->isInlineComponent = serializedObject->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
- object->flags = serializedObject->flags;
- object->id = serializedObject->id;
+ object->defaultPropertyIsAlias = serializedObject->hasAliasAsDefaultProperty();
+ object->isInlineComponent = serializedObject->hasFlag(
+ QV4::CompiledData::Object::IsInlineComponentRoot);
+ object->flags = serializedObject->flags();
+ object->id = serializedObject->objectId();
object->locationOfIdProperty = serializedObject->locationOfIdProperty;
QVector<int> functionIndices;
@@ -114,7 +115,7 @@ QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *seriali
QmlIR::Binding *b = pool->New<QmlIR::Binding>();
*static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
object->bindings->append(b);
- if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ if (b->type() == QV4::CompiledData::Binding::Type_Script) {
functionIndices.append(b->value.compiledScriptIndex);
b->value.compiledScriptIndex = functionIndices.count() - 1;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 75bc944fee..f937a3fff8 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -129,8 +129,8 @@ QString QQmlJavaScriptExpression::expressionIdentifier() const
{
if (auto f = function()) {
QString url = f->sourceFile();
- uint lineNumber = f->compiledFunction->location.line;
- uint columnNumber = f->compiledFunction->location.column;
+ uint lineNumber = f->compiledFunction->location.line();
+ uint columnNumber = f->compiledFunction->location.column();
return url + QString::asprintf(":%u:%u", lineNumber, columnNumber);
}
@@ -221,9 +221,6 @@ public:
while (QQmlJavaScriptExpressionGuard *g = capture.guards.takeFirst())
g->Delete();
- if (!watcher.wasDeleted())
- capture.expression->setTranslationsCaptured(capture.translationCaptured);
-
ep->propertyCapture = lastPropertyCapture;
}
@@ -393,12 +390,27 @@ void QQmlPropertyCapture::captureProperty(
captureNonBindableProperty(o, propertyData->notifyIndex(), propertyData->coreIndex(), doNotify);
}
+void QQmlPropertyCapture::captureTranslation()
+{
+ // use a unique invalid index to avoid needlessly querying the metaobject for
+ // the correct index of of the translationLanguage property
+ int const invalidIndex = -2;
+ for (auto trigger = expression->qpropertyChangeTriggers; trigger;
+ trigger = trigger->next) {
+ if (trigger->target == engine && trigger->propertyIndex == invalidIndex)
+ return; // already installed
+ }
+ auto trigger = expression->allocatePropertyChangeTrigger(engine, invalidIndex);
+
+ trigger->setSource(QQmlEnginePrivate::get(engine)->translationLanguage);
+}
+
void QQmlPropertyCapture::captureBindableProperty(
QObject *o, const QMetaObject *metaObjectForBindable, int c)
{
// if the property is a QPropery, and we're binding to a QProperty
// the automatic capturing process already takes care of everything
- if (typeid(QQmlPropertyBindingJS) == typeid(*expression))
+ if (!expression->mustCaptureBindableProperty())
return;
for (auto trigger = expression->qpropertyChangeTriggers; trigger;
trigger = trigger->next) {
@@ -541,6 +553,16 @@ void QPropertyChangeTrigger::trigger(QPropertyObserver *observer, QUntypedProper
This->m_expression->expressionChanged();
}
+QMetaProperty QPropertyChangeTrigger::property() const
+{
+ if (!target)
+ return {};
+ auto const mo = target->metaObject();
+ if (!mo)
+ return {};
+ return mo->property(propertyIndex);
+}
+
QPropertyChangeTrigger *QQmlJavaScriptExpression::allocatePropertyChangeTrigger(QObject *target, int propertyIndex)
{
auto trigger = QQmlEnginePrivate::get(engine())->qPropertyTriggerPool.New( this );
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index 7a741afb75..bfdc922729 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -158,6 +158,7 @@ public:
void clearError();
void clearActiveGuards();
QQmlDelayedError *delayedError();
+ virtual bool mustCaptureBindableProperty() const {return true;}
static QV4::ReturnedValue evalFunction(
const QQmlRefPointer<QQmlContextData> &ctxt, QObject *scope, const QString &code,
@@ -186,22 +187,12 @@ protected:
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next, GuardTag> activeGuards;
- void setTranslationsCaptured(bool captured) {
- Tag newTag = captured ? TranslationsCaptured : NoTag;
- if (m_error.tag() & InEvaluationLoop)
- newTag = Tag(newTag | InEvaluationLoop);
- m_error.setTag(newTag);
- }
- bool translationsCaptured() const { return m_error.tag() & TranslationsCaptured; }
-
enum Tag {
NoTag,
- TranslationsCaptured,
InEvaluationLoop
};
- // m_error:flag1 translationsCapturedDuringEvaluation
- QTaggedPointer<QQmlDelayedError> m_error;
+ QTaggedPointer<QQmlDelayedError, Tag> m_error;
private:
friend class QQmlContextData;
@@ -238,14 +229,13 @@ public:
void captureProperty(QQmlNotifier *);
void captureProperty(QObject *, int, int, bool doNotify = true);
void captureProperty(QObject *, const QQmlPropertyCache *, const QQmlPropertyData *, bool doNotify = true);
- void captureTranslation() { translationCaptured = true; }
+ void captureTranslation();
QQmlEngine *engine;
QQmlJavaScriptExpression *expression;
QQmlJavaScriptExpression::DeleteWatcher *watcher;
QForwardFieldList<QQmlJavaScriptExpressionGuard, &QQmlJavaScriptExpressionGuard::next> guards;
QStringList *errorString;
- bool translationCaptured = false;
private:
void captureBindableProperty(QObject *o, const QMetaObject *metaObjectForBindable, int c);
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 3589dce3f0..1794a27a9d 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -703,7 +703,7 @@ ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (const QV4::FunctionObject
LOCALE_STRING_PROPERTY(name)
LOCALE_STRING_PROPERTY(nativeLanguageName)
-LOCALE_STRING_PROPERTY(nativeCountryName)
+QT_IGNORE_DEPRECATIONS(LOCALE_STRING_PROPERTY(nativeCountryName))
LOCALE_STRING_PROPERTY(decimalPoint)
LOCALE_STRING_PROPERTY(groupSeparator)
LOCALE_STRING_PROPERTY(percent)
diff --git a/src/qml/qml/qqmlloggingcategory.cpp b/src/qml/qml/qqmlloggingcategory.cpp
index b59a26e17e..98dfe62f0c 100644
--- a/src/qml/qml/qqmlloggingcategory.cpp
+++ b/src/qml/qml/qqmlloggingcategory.cpp
@@ -129,7 +129,7 @@ void QQmlLoggingCategory::componentComplete()
{
m_initialized = true;
if (m_name.isNull()) {
- qmlWarning(this) << QLatin1String("Declaring the name of the LoggingCategory is mandatory and cannot be changed later !");
+ qmlWarning(this) << QLatin1String("Declaring the name of a LoggingCategory is mandatory and cannot be changed later");
} else {
QScopedPointer<QLoggingCategory> category(new QLoggingCategory(m_name.constData(), QtMsgType(m_defaultLogLevel)));
m_category.swap(category);
@@ -138,23 +138,30 @@ void QQmlLoggingCategory::componentComplete()
void QQmlLoggingCategory::setDefaultLogLevel(DefaultLogLevel defaultLogLevel)
{
+ if (m_defaultLogLevel == defaultLogLevel)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed");
return;
}
m_defaultLogLevel = defaultLogLevel;
}
-
void QQmlLoggingCategory::setName(const QString &name)
{
+ const QByteArray newName = name.toUtf8();
+
+ if (m_name == newName)
+ return;
+
if (m_initialized) {
- qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the Item is created");
+ qmlWarning(this) << QLatin1String("The name of a LoggingCategory cannot be changed after the component is completed");
return;
}
- m_name = name.toUtf8();
+ m_name = newName;
}
#include "moc_qqmlloggingcategory_p.cpp"
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index e412263825..fdf74f4873 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -47,10 +47,6 @@
#include <private/qqmlvaluetype_p.h>
#include <private/qv4executablecompilationunit_p.h>
-#if QT_CONFIG(qml_itemmodel)
-#include <private/qqmlmodelindexvaluetype_p.h>
-#endif
-
#include <QtCore/qcoreapplication.h>
#include <QtCore/qmutex.h>
#include <QtCore/qloggingcategory.h>
@@ -230,7 +226,8 @@ static QQmlTypePrivate *createQQmlType(QQmlMetaTypeData *data, const QString &el
}
void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd)
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ QQmlMetaType::ClonePolicy policy)
{
// Set classname
builder.setClassName(ignoreEnd->className());
@@ -247,41 +244,42 @@ void QQmlMetaType::clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
}
}
- // Clone Q_PROPERTY
- for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
- QMetaProperty property = mo->property(ii);
+ if (policy != QQmlMetaType::CloneEnumsOnly) {
+ // Clone Q_METHODS - do this first to avoid duplicating the notify signals.
+ for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
+ QMetaMethod method = mo->method(ii);
- int otherIndex = ignoreEnd->indexOfProperty(property.name());
- if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
- builder.addProperty(QByteArray("__qml_ignore__") + property.name(), QByteArray("void"));
- // Skip
- } else {
- builder.addProperty(property);
- }
- }
+ // More complex - need to search name
+ QByteArray name = method.name();
- // Clone Q_METHODS
- for (int ii = mo->methodOffset(); ii < mo->methodCount(); ++ii) {
- QMetaMethod method = mo->method(ii);
+ bool found = false;
- // More complex - need to search name
- QByteArray name = method.name();
+ for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
+ !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount(); ++ii) {
+ QMetaMethod other = ignoreEnd->method(ii);
- bool found = false;
+ found = name == other.name();
+ }
- for (int ii = ignoreStart->methodOffset() + ignoreStart->methodCount();
- !found && ii < ignoreEnd->methodOffset() + ignoreEnd->methodCount();
- ++ii) {
+ QMetaMethodBuilder m = builder.addMethod(method);
+ if (found) // SKIP
+ m.setAccess(QMetaMethod::Private);
+ }
- QMetaMethod other = ignoreEnd->method(ii);
+ // Clone Q_PROPERTY
+ for (int ii = mo->propertyOffset(); ii < mo->propertyCount(); ++ii) {
+ QMetaProperty property = mo->property(ii);
- found = name == other.name();
+ int otherIndex = ignoreEnd->indexOfProperty(property.name());
+ if (otherIndex >= ignoreStart->propertyOffset() + ignoreStart->propertyCount()) {
+ builder.addProperty(QByteArray("__qml_ignore__") + property.name(),
+ QByteArray("void"));
+ // Skip
+ } else {
+ builder.addProperty(property);
+ }
}
-
- QMetaMethodBuilder m = builder.addMethod(method);
- if (found) // SKIP
- m.setAccess(QMetaMethod::Private);
}
// Clone Q_ENUMS
@@ -339,6 +337,10 @@ void QQmlMetaType::clearTypeRegistrations()
data->urlToNonFileImportType.clear();
data->metaObjectToType.clear();
data->undeletableTypes.clear();
+
+ for (auto it = data->propertyCaches.begin(), end = data->propertyCaches.end(); it != end; ++it)
+ (*it)->release();
+ data->propertyCaches.clear();
}
int QQmlMetaType::registerAutoParentFunction(const QQmlPrivate::RegisterAutoParent &function)
@@ -431,7 +433,7 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
if (uri && !typeName.isEmpty()) {
QString nameSpace = QString::fromUtf8(uri);
QQmlTypeModule *qqtm = data->findTypeModule(nameSpace, version);
- if (qqtm && qqtm->isLocked()) {
+ if (qqtm && qqtm->lockLevel() != QQmlTypeModule::LockLevel::Open) {
QString failure(QCoreApplication::translate(
"qmlRegisterType",
"Cannot install %1 '%2' into protected module '%3' version '%4'"));
@@ -588,12 +590,14 @@ void QQmlMetaType::unregisterInternalCompositeType(const CompositeMetaTypeIds &t
QMetaType metaType(typeIds.id);
QMetaType listMetaType(typeIds.listId);
+ // This may be called from delayed dtors on shutdown when the data is already gone.
QQmlMetaTypeDataPtr data;
-
- if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
- delete vt;
- if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
- delete vt;
+ if (data.isValid()) {
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(metaType.id()))
+ delete vt;
+ if (QQmlValueType *vt = data->metaTypeToValueType.take(listMetaType.id()))
+ delete vt;
+ }
QMetaType::unregisterMetaType(metaType);
QMetaType::unregisterMetaType(listMetaType);
@@ -645,18 +649,19 @@ void QQmlMetaType::unregisterSequentialContainer(int id)
unregisterType(id);
}
-bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version, bool protectAllVersions)
+bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version,
+ bool weakProtectAllVersions)
{
QQmlMetaTypeDataPtr data;
if (version.hasMajorVersion()) {
- if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
- if (!protectAllVersions) {
- module->lock();
- return true;
+ if (QQmlTypeModule *module = data->findTypeModule(uri, version)) {
+ if (!weakProtectAllVersions) {
+ module->setLockLevel(QQmlTypeModule::LockLevel::Strong);
+ return true;
+ }
+ } else {
+ return false;
}
- } else {
- return false;
- }
}
const auto range = std::equal_range(
@@ -664,7 +669,7 @@ bool QQmlMetaType::protectModule(const QString &uri, QTypeRevision version, bool
std::less<ModuleUri>());
for (auto it = range.first; it != range.second; ++it)
- (*it)->lock();
+ (*it)->setLockLevel(QQmlTypeModule::LockLevel::Weak);
return range.first != range.second;
}
@@ -981,12 +986,12 @@ QTypeRevision QQmlMetaType::latestModuleVersion(const QString &uri)
/*
Returns true if a module \a uri of this version is installed and locked;
*/
-bool QQmlMetaType::isLockedModule(const QString &uri, QTypeRevision version)
+bool QQmlMetaType::isStronglyLockedModule(const QString &uri, QTypeRevision version)
{
QQmlMetaTypeDataPtr data;
if (QQmlTypeModule* qqtm = data->findTypeModule(uri, version))
- return qqtm->isLocked();
+ return qqtm->lockLevel() == QQmlTypeModule::LockLevel::Strong;
return false;
}
@@ -1522,7 +1527,8 @@ QList<QQmlProxyMetaObject::ProxyData> QQmlMetaType::proxyData(const QMetaObject
return;
QMetaObjectBuilder builder;
- clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject);
+ clone(builder, extMetaObject, superdataBaseMetaObject, baseMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
builder.setFlags(MetaObjectFlag::DynamicMetaObject);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = baseMetaObject;
@@ -1598,17 +1604,7 @@ const QMetaObject *QQmlMetaType::metaObjectForValueType(QMetaType metaType)
case QMetaType::QEasingCurve:
return &QQmlEasingValueType::staticMetaObject;
#endif
-#if QT_CONFIG(qml_itemmodel)
- case QMetaType::QModelIndex:
- return &QQmlModelIndexValueType::staticMetaObject;
- case QMetaType::QPersistentModelIndex:
- return &QQmlPersistentModelIndexValueType::staticMetaObject;
-#endif
default:
-#if QT_CONFIG(qml_itemmodel)
- if (metaType == QMetaType::fromType<QItemSelectionRange>())
- return &QQmlItemSelectionRangeValueType::staticMetaObject;
-#endif
break;
}
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index 7ee16f9dc9..dc08263511 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -147,7 +147,7 @@ public:
static void registerModule(const char *uri, QTypeRevision version);
static bool protectModule(const QString &uri, QTypeRevision version,
- bool protectAllVersions = false);
+ bool weakProtectAllVersions = false);
static void registerModuleImport(const QString &uri, QTypeRevision version,
const QQmlDirParser::Import &import);
@@ -197,7 +197,7 @@ public:
static bool isList(QMetaType type);
static QTypeRevision latestModuleVersion(const QString &uri);
- static bool isLockedModule(const QString &uri, QTypeRevision version);
+ static bool isStronglyLockedModule(const QString &uri, QTypeRevision version);
static QTypeRevision matchingModuleVersion(const QString &module, QTypeRevision version);
static QQmlTypeModule *typeModule(const QString &uri, QTypeRevision version);
@@ -245,8 +245,13 @@ public:
const QMetaObject *baseMetaObject,
QMetaObject *lastMetaObject);
+ enum ClonePolicy {
+ CloneAll, // default
+ CloneEnumsOnly, // skip properties and methods
+ };
static void clone(QMetaObjectBuilder &builder, const QMetaObject *mo,
- const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd);
+ const QMetaObject *ignoreStart, const QMetaObject *ignoreEnd,
+ ClonePolicy policy);
static void qmlInsertModuleRegistration(const QString &uri, void (*registerFunction)());
static void qmlRemoveModuleRegistration(const QString &uri);
diff --git a/src/qml/qml/qqmlmetatypedata.cpp b/src/qml/qml/qqmlmetatypedata.cpp
index 71901e23fe..6b21e23349 100644
--- a/src/qml/qml/qqmlmetatypedata.cpp
+++ b/src/qml/qml/qqmlmetatypedata.cpp
@@ -145,8 +145,9 @@ QQmlRefPointer<QQmlPropertyCache> QQmlMetaTypeData::propertyCache(const QMetaObj
return rv;
if (!metaObject->superClass()) {
- QQmlPropertyCache *rv = new QQmlPropertyCache(metaObject);
- propertyCaches.insert(metaObject, rv);
+ QQmlRefPointer<QQmlPropertyCache> rv = QQmlPropertyCache::createStandalone(metaObject);
+ rv->addref(); // extra ref for the propertyCaches storage
+ propertyCaches.insert(metaObject, rv.data());
return rv;
}
auto super = propertyCache(metaObject->superClass(), version);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index c0cc917499..0a96bb0af8 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -168,13 +168,16 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
phase = CreatingObjects;
int objectToCreate;
+ bool isComponentRoot = false; // either a "real" component of or an inline component
if (subComponentIndex == -1) {
objectToCreate = /*root object*/0;
+ isComponentRoot = true;
} else {
Q_ASSERT(subComponentIndex >= 0);
if (flags & CreationFlags::InlineComponent) {
objectToCreate = subComponentIndex;
+ isComponentRoot = true;
} else {
Q_ASSERT(flags & CreationFlags::NormalObject);
const QV4::CompiledData::Object *compObj = compilationUnit->objectAt(subComponentIndex);
@@ -199,7 +202,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
if (topLevelCreator)
sharedState->allJavaScriptObjects = scope.alloc(compilationUnit->totalObjectCount());
- if (subComponentIndex == -1 && compilationUnit->dependentScripts.count()) {
+ if (isComponentRoot && compilationUnit->dependentScripts.count()) {
QV4::ScopedObject scripts(scope, v4->newArrayObject(compilationUnit->dependentScripts.count()));
context->setImportedScripts(QV4::PersistentValue(v4, scripts.asReturnedValue()));
QV4::ScopedValue v(scope);
@@ -290,7 +293,7 @@ void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex,
if (binding) {
Q_ASSERT(qmlProperty);
- Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding);
+ Q_ASSERT(binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding));
QQmlListProperty<void> savedList;
qSwap(_currentList, savedList);
@@ -352,7 +355,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
int propertyType = property->propType().id();
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum)) {
propertyType = QMetaType::Int;
} else {
// ### This should be resolved earlier at compile time and the binding value should be changed accordingly.
@@ -366,18 +369,18 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
auto assertOrNull = [&](bool ok)
{
- Q_ASSERT(ok || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(ok || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(ok);
};
- auto assertType = [&](QV4::CompiledData::Binding::ValueType type)
+ auto assertType = [&](QV4::CompiledData::Binding::Type type)
{
- Q_ASSERT(binding->type == type || binding->type == QV4::CompiledData::Binding::Type_Null);
+ Q_ASSERT(binding->type()== type || binding->type() == QV4::CompiledData::Binding::Type_Null);
Q_UNUSED(type);
};
if (property->isQObject()) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QObject *value = nullptr;
const bool ok = property->writeProperty(_qobject, &value, propertyWriteFlags);
Q_ASSERT(ok);
@@ -388,7 +391,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
switch (propertyType) {
case QMetaType::QVariant: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Number) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) == n) {
if (property->isVarProperty()) {
@@ -406,14 +409,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Boolean) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromBoolean(binding->valueAsBoolean()));
} else {
QVariant value(binding->valueAsBoolean());
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
if (property->isVarProperty()) {
_vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::nullValue());
} else {
@@ -453,7 +456,9 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
case QMetaType::QUrl: {
assertType(QV4::CompiledData::Binding::Type_String);
const QString string = compilationUnit->bindingValueAsString(binding);
- QUrl value(string);
+ QUrl value = (!string.isEmpty() && QQmlPropertyPrivate::resolveUrlsOnAssignment())
+ ? compilationUnit->finalUrl().resolved(QUrl(string))
+ : QUrl(string);
property->writeProperty(_qobject, &value, propertyWriteFlags);
}
break;
@@ -600,7 +605,12 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
} else if (propertyType == qMetaTypeId<QList<QUrl> >()) {
assertType(QV4::CompiledData::Binding::Type_String);
- QList<QUrl> value { QUrl(compilationUnit->bindingValueAsString(binding)) };
+ const QUrl url(compilationUnit->bindingValueAsString(binding));
+ QList<QUrl> value {
+ QQmlPropertyPrivate::resolveUrlsOnAssignment()
+ ? compilationUnit->finalUrl().resolved(url)
+ : url
+ };
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
} else if (propertyType == qMetaTypeId<QList<QString> >()) {
@@ -611,18 +621,24 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
break;
} else if (propertyType == qMetaTypeId<QJSValue>()) {
QJSValue value;
- if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Boolean:
value = QJSValue(binding->valueAsBoolean());
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
- double n = compilationUnit->bindingValueAsNumber(binding);
- if (double(int(n)) == n) {
+ break;
+ case QV4::CompiledData::Binding::Type_Number: {
+ const double n = compilationUnit->bindingValueAsNumber(binding);
+ if (double(int(n)) == n)
value = QJSValue(int(n));
- } else
+ else
value = QJSValue(n);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ break;
+ }
+ case QV4::CompiledData::Binding::Type_Null:
value = QJSValue::NullValue;
- } else {
+ break;
+ default:
value = QJSValue(compilationUnit->bindingValueAsString(binding));
+ break;
}
property->writeProperty(_qobject, &value, propertyWriteFlags);
break;
@@ -662,8 +678,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType().id() == QMetaType::QString) {
QV4::CompiledData::Binding idBinding;
idBinding.propertyNameIndex = 0; // Not used
- idBinding.flags = 0;
- idBinding.type = QV4::CompiledData::Binding::Type_String;
+ idBinding.clearFlags();
+ idBinding.setType(QV4::CompiledData::Binding::Type_String);
idBinding.stringIndex = _compiledObject->idNameIndex;
idBinding.location = _compiledObject->location; // ###
setPropertyValue(idProperty, &idBinding);
@@ -718,10 +734,10 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
}
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsDeferredBinding)) {
if (!applyDeferredBindings)
continue;
} else {
@@ -778,7 +794,8 @@ void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProperty, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex);
Q_ASSERT(tr);
@@ -793,7 +810,15 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
QObject *qmlObject = qmlAttachedPropertiesObject(
_qobject, attachedType.attachedPropertiesFunction(QQmlEnginePrivate::get(engine)));
- if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject, /*value type property*/nullptr))
+ if (!qmlObject) {
+ recordError(binding->location,
+ QStringLiteral("Could not create attached properties object '%1'")
+ .arg(QString::fromUtf8(attachedType.typeName())));
+ return false;
+ }
+
+ if (!populateInstance(binding->value.objectIndex, qmlObject, qmlObject,
+ /*value type property*/ nullptr, binding))
return false;
return true;
}
@@ -802,11 +827,11 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
if (bindingProperty && bindingProperty->propType() == QMetaType::fromType<QQmlScriptString>()) {
QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding),
context->asQQmlContext(), _scopeObject);
- ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
- ss.d.data()->lineNumber = binding->location.line;
- ss.d.data()->columnNumber = binding->location.column;
- ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String;
- ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number;
+ ss.d.data()->bindingId = bindingType == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid;
+ ss.d.data()->lineNumber = binding->location.line();
+ ss.d.data()->columnNumber = binding->location.column();
+ ss.d.data()->isStringLiteral = bindingType == QV4::CompiledData::Binding::Type_String;
+ ss.d.data()->isNumberLiteral = bindingType == QV4::CompiledData::Binding::Type_Number;
ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding);
QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor |
@@ -818,7 +843,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
QObject *createdSubObject = nullptr;
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
createdSubObject = createInstance(binding->value.objectIndex, _bindingTarget);
if (!createdSubObject)
return false;
@@ -827,7 +852,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
if (!bindingProperty) // ### error
return true;
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_GroupProperty) {
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(binding->value.objectIndex);
if (stringAt(obj->inheritedTypeNameIndex).isEmpty()) {
@@ -858,7 +883,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
bindingTarget = groupObject;
}
- if (!populateInstance(binding->value.objectIndex, groupObject, bindingTarget, valueTypeProperty))
+ if (!populateInstance(binding->value.objectIndex, groupObject, bindingTarget,
+ valueTypeProperty, binding))
return false;
if (valueType)
@@ -868,14 +894,26 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
}
- if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && !(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
- && !_valueTypeProperty)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ const bool allowedToRemoveBinding
+ = !(bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
+ && !_valueTypeProperty;
+
+ if (_ddata->hasBindingBit(bindingProperty->coreIndex()) && allowedToRemoveBinding) {
QQmlPropertyPrivate::removeBinding(_bindingTarget, QQmlPropertyIndex(bindingProperty->coreIndex()));
+ } else if (bindingProperty->isBindable() && allowedToRemoveBinding) {
+ QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
+ auto it = std::remove_if(pendingBindings.begin(), pendingBindings.end(), [&](const DeferredQPropertyBinding &deferred) {
+ return deferred.properyIndex == bindingProperty->coreIndex() && deferred.target == _bindingTarget;
+ });
+ pendingBindings.erase(it, pendingBindings.end());
+ }
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver) {
QV4::Function *runtimeFunction = compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex];
int signalIndex = _propertyCache->methodIndexToSignalIndex(bindingProperty->coreIndex());
QQmlBoundSignalExpression *expr = new QQmlBoundSignalExpression(
@@ -915,7 +953,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
QQmlPropertyIndex index(bindingProperty->coreIndex(), -1);
qmlBinding = QQmlPropertyBinding::create(bindingProperty, runtimeFunction, _scopeObject, context, currentQmlContext(), _bindingTarget, index);
}
- sharedState.data()->allQPropertyBindings.emplaceBack(_bindingTarget, bindingProperty->coreIndex(), qmlBinding);
+ sharedState.data()->allQPropertyBindings.push_back(DeferredQPropertyBinding {_bindingTarget, bindingProperty->coreIndex(), qmlBinding });
} else {
// When writing bindings to grouped properties implemented as value types,
// such as point.x: { someExpression; }, then the binding is installed on
@@ -966,8 +1004,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
return true;
}
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsOnAssignment) {
// ### determine value source and interceptor casts ahead of time.
QQmlType type = qmlTypeForObject(createdSubObject);
Q_ASSERT(type.isValid());
@@ -1031,7 +1069,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper
}
// Assigning object to signal property? ### Qt 7: Remove that functionality
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
if (!bindingProperty->isFunction()) {
recordError(binding->valueLocation, tr("Cannot assign an object to signal property %1").arg(bindingProperty->name(_qobject)));
return false;
@@ -1156,16 +1194,16 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
{
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
errors << error;
}
void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
{
- if (object->id >= 0)
- context->setIdValue(object->id, instance);
+ if (object->objectId() >= 0)
+ context->setIdValue(object->objectId(), instance);
}
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
@@ -1185,7 +1223,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
QQmlParserStatus *parserStatus = nullptr;
bool installPropertyCache = true;
- if (obj->flags & QV4::CompiledData::Object::IsComponent) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)) {
isComponent = true;
QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent);
typeName = QStringLiteral("<component>");
@@ -1275,13 +1313,13 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
compilationUnit.data(), obj, typeName, context->url()));
Q_UNUSED(typeName); // only relevant for tracing
- ddata->lineNumber = obj->location.line;
- ddata->columnNumber = obj->location.column;
+ ddata->lineNumber = obj->location.line();
+ ddata->columnNumber = obj->location.column();
ddata->setImplicitDestructible();
// inline components are root objects, but their index is != 0, so we need
// an additional check
- const bool isInlineComponent = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
+ const bool isInlineComponent = obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot);
if (static_cast<quint32>(index) == /*root object*/0 || ddata->rootObjectInCreation || isInlineComponent) {
if (ddata->context) {
Q_ASSERT(ddata->context != context.data());
@@ -1315,7 +1353,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (isContextObject)
context->setContextObject(instance);
- if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
+ if (customParser && obj->hasFlag(QV4::CompiledData::Object::HasCustomParserBindings)) {
customParser->engine = QQmlEnginePrivate::get(engine);
customParser->imports = compilationUnit->typeNameCache.data();
@@ -1323,9 +1361,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index);
const QV4::CompiledData::Binding *binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
- if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsCustomParserBinding))
bindings << binding;
- }
}
customParser->applyBindings(instance, compilationUnit.data(), bindings);
@@ -1438,16 +1475,24 @@ bool QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
void *argv[] = { &bindable };
// allow interception
target->metaObject()->metacall(target, QMetaObject::BindableProperty, index, argv);
- bindable.setBinding(qmlBinding);
+ const bool success = bindable.setBinding(qmlBinding);
+
+ // Only pop_front after setting the binding as the bindings are refcounted.
sharedState->allQPropertyBindings.pop_front();
- if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
- auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
- auto jsExpression = qmlBindingPriv->jsExpression();
- const bool canRemove = !qmlBinding.error().hasError() && !qmlBindingPriv->hasDependencies()
- && !jsExpression->hasUnresolvedNames();
- if (canRemove)
- bindable.takeBinding();
+
+ // If the binding was actually not set, it's deleted now.
+ if (success) {
+ if (auto priv = QPropertyBindingPrivate::get(qmlBinding); priv->hasCustomVTable()) {
+ auto qmlBindingPriv = static_cast<QQmlPropertyBinding *>(priv);
+ auto jsExpression = qmlBindingPriv->jsExpression();
+ const bool canRemove = !qmlBinding.error().hasError()
+ && !qmlBindingPriv->hasDependencies()
+ && !jsExpression->hasUnresolvedNames();
+ if (canRemove)
+ bindable.takeBinding();
+ }
}
+
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return false;
}
@@ -1519,8 +1564,11 @@ void QQmlObjectCreator::clear()
phase = Done;
}
-bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
+bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding)
{
+ Q_ASSERT(instance);
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
qSwap(_qobject, instance);
@@ -1555,9 +1603,10 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
qSwap(_propertyCache, cache);
qSwap(_vmeMetaObject, vmeMetaObject);
- if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings)
+ if (_compiledObject->hasFlag(QV4::CompiledData::Object::HasDeferredBindings))
_ddata->deferData(_compiledObjectIndex, compilationUnit, context);
+ const qsizetype oldRequiredPropertiesCount = sharedState->requiredProperties.size();
QSet<QString> postHocRequired;
for (auto it = _compiledObject->requiredPropertyExtraDataBegin(); it != _compiledObject->requiredPropertyExtraDataEnd(); ++it)
postHocRequired.insert(stringAt(it->nameIndex));
@@ -1568,7 +1617,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
QQmlPropertyData *propertyData = _propertyCache->property(_propertyCache->propertyOffset() + propertyIndex);
// only compute stringAt if there's a chance for the lookup to succeed
auto postHocIt = postHocRequired.isEmpty() ? postHocRequired.end() : postHocRequired.find(stringAt(property->nameIndex));
- if (!property->isRequired && postHocRequired.end() == postHocIt)
+ if (!property->isRequired() && postHocRequired.end() == postHocIt)
continue;
if (postHocIt != postHocRequired.end())
postHocRequired.erase(postHocIt);
@@ -1578,10 +1627,48 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
}
- for (int i = 0; i <= _propertyCache->propertyOffset(); ++i) {
+ const auto getPropertyCacheRange = [&]() -> std::pair<int, int> {
+ // the logic in a nutshell: we work with QML instances here. every
+ // instance has a QQmlType:
+ // * if QQmlType is valid && not an inline component, it's a C++ type
+ // * otherwise, it's a QML-defined type (a.k.a. Composite type), where
+ // invalid type == "comes from another QML document"
+ //
+ // 1. if the type we inherit from comes from C++, we must check *all*
+ // properties in the property cache so far - since we can have
+ // required properties defined in C++
+ // 2. otherwise - the type comes from QML, it's enough to check just
+ // *own* properties in the property cache, because there's a previous
+ // type in the hierarchy that has checked the C++ properties (via 1.)
+ // 3. required attached properties are explicitly not supported. to
+ // achieve that, go through all its properties
+ // 4. required group properties: the group itself is covered by 1.
+ // required sub-properties are not properly handled (QTBUG-96544), so
+ // just return the old range here for consistency
+ QV4::ResolvedTypeReference *typeRef = resolvedType(_compiledObject->inheritedTypeNameIndex);
+ if (!typeRef) { // inside a binding on attached/group property
+ Q_ASSERT(binding);
+ if (binding->isAttachedProperty())
+ return { 0, _propertyCache->propertyCount() }; // 3.
+ Q_ASSERT(binding->isGroupProperty());
+ return { 0, _propertyCache->propertyOffset() + 1 }; // 4.
+ }
+ Q_ASSERT(!_compiledObject->hasFlag(QV4::CompiledData::Object::IsComponent));
+ QQmlType type = typeRef->type();
+ if (type.isValid() && !type.isInlineComponentType()) {
+ return { 0, _propertyCache->propertyCount() }; // 1.
+ }
+ // Q_ASSERT(type.isComposite());
+ return { _propertyCache->propertyOffset(), _propertyCache->propertyCount() }; // 2.
+ };
+ const auto [offset, count] = getPropertyCacheRange();
+ for (int i = offset; i < count; ++i) {
QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
if (!propertyData)
continue;
+ // TODO: the property might be a group property (in which case we need
+ // to dive into its sub-properties and check whether there are any
+ // required elements there) - QTBUG-96544
if (!propertyData->isRequired() && postHocRequired.isEmpty())
continue;
QString name = propertyData->name(_qobject);
@@ -1593,8 +1680,43 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
postHocRequired.erase(postHocIt);
sharedState->hadRequiredProperties = true;
- sharedState->requiredProperties.insert(propertyData, RequiredPropertyInfo {name, compilationUnit->finalUrl(), _compiledObject->location, {}});
+ sharedState->requiredProperties.insert(
+ propertyData,
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
+ }
+
+ if (binding && binding->isAttachedProperty()
+ && sharedState->requiredProperties.size() != oldRequiredPropertiesCount) {
+ recordError(
+ binding->location,
+ QLatin1String("Attached property has required properties. This is not supported"));
+ }
+
+ // Note: there's a subtle case with the above logic: if we process a random
+ // QML-defined leaf type, it could have a required attribute overwrite on an
+ // *existing* property: `import QtQuick; Text { required text }`. in this
+ // case, we must add the property to a required list
+ if (!postHocRequired.isEmpty()) {
+ // NB: go through [0, offset) range as [offset, count) is already done
+ for (int i = 0; i < offset; ++i) {
+ QQmlPropertyData *propertyData = _propertyCache->maybeUnresolvedProperty(i);
+ if (!propertyData)
+ continue;
+ QString name = propertyData->name(_qobject);
+ auto postHocIt = postHocRequired.find(name);
+ if (postHocRequired.end() == postHocIt)
+ continue;
+ postHocRequired.erase(postHocIt);
+
+ sharedState->hadRequiredProperties = true;
+ sharedState->requiredProperties.insert(
+ propertyData,
+ RequiredPropertyInfo {
+ name, compilationUnit->finalUrl(), _compiledObject->location, {} });
+ }
}
+
if (!postHocRequired.isEmpty() && hadInheritedRequiredProperties)
recordError({}, QLatin1String("Property %1 was marked as required but does not exist").arg(*postHocRequired.begin()));
@@ -1605,12 +1727,12 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
for (int aliasIndex = 0; aliasIndex != _compiledObject->aliasCount(); ++aliasIndex) {
const QV4::CompiledData::Alias* alias = _compiledObject->aliasesBegin() + aliasIndex;
const auto originalAlias = alias;
- while (alias->aliasToLocalAlias)
+ while (alias->isAliasToLocalAlias())
alias = _compiledObject->aliasesBegin() + alias->localAliasIndex;
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
if (!context->isIdValueSet(0)) // TODO: Do we really want 0 here?
continue;
- QObject *target = context->idValue(alias->targetObjectId);
+ QObject *target = context->idValue(alias->targetObjectId());
if (!target)
continue;
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
@@ -1622,7 +1744,11 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
continue;
auto it = sharedState->requiredProperties.find(targetProperty);
if (it != sharedState->requiredProperties.end())
- it->aliasesToRequired.push_back(AliasToRequiredInfo {compilationUnit->stringAt(originalAlias->nameIndex), compilationUnit->finalUrl()});
+ it->aliasesToRequired.push_back(
+ AliasToRequiredInfo {
+ compilationUnit->stringAt(originalAlias->nameIndex()),
+ compilationUnit->finalUrl()
+ });
}
qSwap(_vmeMetaObject, vmeMetaObject);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 1881b3eb23..4e788e88d4 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -89,6 +89,12 @@ struct RequiredPropertyInfo
class RequiredProperties : public QHash<QQmlPropertyData*, RequiredPropertyInfo> {};
+struct DeferredQPropertyBinding {
+ QObject *target = nullptr;
+ int properyIndex = -1;
+ QUntypedPropertyBinding binding;
+};
+
struct QQmlObjectCreatorSharedState : QQmlRefCount
{
QQmlRefPointer<QQmlContextData> rootContext;
@@ -102,7 +108,7 @@ struct QQmlObjectCreatorSharedState : QQmlRefCount
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
RequiredProperties requiredProperties;
- QList<std::tuple<QObject *, int, QUntypedPropertyBinding>> allQPropertyBindings;
+ QList<DeferredQPropertyBinding> allQPropertyBindings;
bool hadRequiredProperties;
};
@@ -155,8 +161,9 @@ private:
QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
- bool populateInstance(int index, QObject *instance,
- QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
+ bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
void populateDeferred(QObject *instance, int deferredIndex,
diff --git a/src/qml/qml/qqmlopenmetaobject.cpp b/src/qml/qml/qqmlopenmetaobject.cpp
index ec2d57013f..ddd94630d7 100644
--- a/src/qml/qml/qqmlopenmetaobject.cpp
+++ b/src/qml/qml/qqmlopenmetaobject.cpp
@@ -40,6 +40,7 @@
#include "qqmlopenmetaobject_p.h"
#include <private/qqmlpropertycache_p.h>
#include <private/qqmldata_p.h>
+#include <private/qqmlmetatype_p.h>
#include <private/qmetaobjectbuilder_p.h>
#include <qdebug.h>
@@ -427,8 +428,11 @@ void QQmlOpenMetaObject::setCached(bool c)
QQmlData *qmldata = QQmlData::get(d->object, true);
if (d->cacheProperties) {
+ // As the propertyCache is not saved in QQmlMetaType (due to it being dynamic)
+ // we cannot leak it to other places before we're done with it. Yes, it's still
+ // terrible.
if (!d->type->d->cache)
- d->type->d->cache = new QQmlPropertyCache(this);
+ d->type->d->cache = QQmlPropertyCache::createStandalone(this).take();
qmldata->propertyCache = d->type->d->cache;
d->type->d->cache->addref();
} else {
diff --git a/src/qml/qml/qqmlpluginimporter.cpp b/src/qml/qml/qqmlpluginimporter.cpp
index c121ea7066..f0cc3d2a5b 100644
--- a/src/qml/qml/qqmlpluginimporter.cpp
+++ b/src/qml/qml/qqmlpluginimporter.cpp
@@ -46,6 +46,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qdir.h>
+#include <QtCore/qloggingcategory.h>
#include <QtCore/qjsonarray.h>
#include <unordered_map>
@@ -336,6 +337,12 @@ QTypeRevision QQmlPluginImporter::importDynamicPlugin(
if (it != plugins->end() && it->second.loader)
instance = it->second.loader->instance();
}
+#else
+ // Here plugin is not optional and NOT QT_CONFIG(library)
+ // Cannot finalize such plugin and return valid, because no types are registered.
+ // Just return invalid.
+ if (!optional)
+ return QTypeRevision();
#endif // QT_CONFIG(library)
}
@@ -423,53 +430,64 @@ QString QQmlPluginImporter::resolvePlugin(const QString &qmldirPluginPath, const
searchPaths.prepend(qmldirPluginPath);
for (const QString &pluginPath : qAsConst(searchPaths)) {
- QString resolvedPath;
+ QString resolvedBasePath;
if (pluginPath == QLatin1String(".")) {
if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty()
&& qmldirPluginPath != QLatin1String(".")) {
- resolvedPath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath);
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + qmldirPluginPath);
} else {
- resolvedPath = qmldirPath;
+ resolvedBasePath = qmldirPath;
}
} else {
if (QDir::isRelativePath(pluginPath))
- resolvedPath = QDir::cleanPath(qmldirPath + u'/' + pluginPath);
+ resolvedBasePath = QDir::cleanPath(qmldirPath + u'/' + pluginPath);
else
- resolvedPath = pluginPath;
+ resolvedBasePath = pluginPath;
}
// hack for resources, should probably go away
- if (resolvedPath.startsWith(u':'))
- resolvedPath = QCoreApplication::applicationDirPath();
+ if (resolvedBasePath.startsWith(u':'))
+ resolvedBasePath = QCoreApplication::applicationDirPath();
+
+ if (!resolvedBasePath.endsWith(u'/'))
+ resolvedBasePath += u'/';
- if (!resolvedPath.endsWith(u'/'))
- resolvedPath += u'/';
+ QString resolvedPath = resolvedBasePath + prefix + baseName;
+ for (const QString &suffix : suffixes) {
+ const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
+ if (!absolutePath.isEmpty())
+ return absolutePath;
+ }
-#if defined(Q_OS_ANDROID)
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+# if defined(Q_OS_ANDROID)
if (qmldirPath.size() > 25 && qmldirPath.at(0) == QLatin1Char(':')
- && qmldirPath.at(1) == QLatin1Char('/') &&
- qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"),
- Qt::CaseInsensitive)) {
+ && qmldirPath.at(1) == QLatin1Char('/')
+ && qmldirPath.startsWith(QStringLiteral(":/android_rcc_bundle/qml/"),
+ Qt::CaseInsensitive)) {
QString pluginName = qmldirPath.mid(21) + u'/' + baseName;
pluginName.replace(QLatin1Char('/'), QLatin1Char('_'));
- QString bundledPath = resolvedPath + QLatin1String("lib") + pluginName;
+ QString bundledPath = resolvedBasePath + QLatin1String("lib") + pluginName;
for (const QString &suffix : suffixes) {
const QString absolutePath = typeLoader->absoluteFilePath(bundledPath + suffix);
- if (!absolutePath.isEmpty())
+ if (!absolutePath.isEmpty()) {
+ qWarning("The implicit resolving of Qml plugin locations using the URI "
+ "embedded in the filename has been deprecated. Please use the "
+ "modern CMake API to create QML modules or set the name of "
+ "QML plugin in qmldir file, that matches the name of plugin "
+ "on file system. The correct plugin name is '%s'.",
+ qPrintable(pluginName));
return absolutePath;
+ }
}
}
+# endif
#endif
- resolvedPath += prefix + baseName;
- for (const QString &suffix : suffixes) {
- const QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + suffix);
- if (!absolutePath.isEmpty())
- return absolutePath;
- }
}
- qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve plugin"
- << baseName << "in" << qmldirPath;
+ qCDebug(lcQmlImport) << "resolvePlugin" << "Could not resolve dynamic plugin with base name"
+ << baseName << "in" << qmldirPath
+ << " file does not exist";
return QString();
}
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index b24b57a0e4..372103b94f 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -74,6 +74,8 @@ Q_DECLARE_METATYPE(QList<QUrl>)
QT_BEGIN_NAMESPACE
+DEFINE_BOOL_CONFIG_OPTION(compatResolveUrlsOnAssigment, QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT);
+
/*!
\class QQmlProperty
\since 5.0
@@ -246,6 +248,11 @@ QQmlProperty QQmlPropertyPrivate::create(QObject *target, const QString &propert
return result;
}
+bool QQmlPropertyPrivate::resolveUrlsOnAssignment()
+{
+ return ::compatResolveUrlsOnAssigment();
+}
+
QQmlRefPointer<QQmlContextData> QQmlPropertyPrivate::effectiveContext() const
{
if (context)
@@ -287,17 +294,24 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
currentObject = qmlAttachedPropertiesObject(currentObject, func);
if (!currentObject) return; // Something is broken with the attachable type
} else if (r.importNamespace) {
- if ((ii + 1) == path.count()) return; // No type following the namespace
+ if (++ii == path.count())
+ return; // No type following the namespace
- ++ii; r = typeNameCache->query(path.at(ii), r.importNamespace);
- if (!r.type.isValid()) return; // Invalid type in namespace
+ // TODO: Do we really _not_ want to query the namespaced types here?
+ r = typeNameCache->query<QQmlTypeNameCache::QueryNamespaced::No>(
+ path.at(ii), r.importNamespace);
+
+ if (!r.type.isValid())
+ return; // Invalid type in namespace
QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine);
QQmlAttachedPropertiesFunc func = r.type.attachedPropertiesFunction(enginePrivate);
- if (!func) return; // Not an attachable type
+ if (!func)
+ return; // Not an attachable type
currentObject = qmlAttachedPropertiesObject(currentObject, func);
- if (!currentObject) return; // Something is broken with the attachable type
+ if (!currentObject)
+ return; // Something is broken with the attachable type
} else if (r.scriptIndex != -1) {
return; // Not a type
@@ -612,12 +626,8 @@ QObject *QQmlProperty::object() const
*/
QQmlProperty &QQmlProperty::operator=(const QQmlProperty &other)
{
- if (d)
- d->release();
- d = other.d;
- if (d)
- d->addref();
-
+ QQmlProperty copied(other);
+ qSwap(d, copied.d);
return *this;
}
@@ -1134,32 +1144,38 @@ QVariant QQmlPropertyPrivate::readValueProperty()
}
// helper function to allow assignment / binding to QList<QUrl> properties.
-QVariant QQmlPropertyPrivate::urlSequence(const QVariant &value)
+QList<QUrl> QQmlPropertyPrivate::urlSequence(const QVariant &value)
{
+ if (value.metaType() == QMetaType::fromType<QList<QUrl>>())
+ return value.value<QList<QUrl> >();
+
QList<QUrl> urls;
- if (value.userType() == qMetaTypeId<QUrl>()) {
+ if (value.metaType() == QMetaType::fromType<QUrl>()) {
urls.append(value.toUrl());
- } else if (value.userType() == qMetaTypeId<QString>()) {
+ } else if (value.metaType() == QMetaType::fromType<QString>()) {
urls.append(QUrl(value.toString()));
- } else if (value.userType() == qMetaTypeId<QByteArray>()) {
+ } else if (value.metaType() == QMetaType::fromType<QByteArray>()) {
urls.append(QUrl(QString::fromUtf8(value.toByteArray())));
- } else if (value.userType() == qMetaTypeId<QList<QUrl> >()) {
- urls = value.value<QList<QUrl> >();
- } else if (value.userType() == qMetaTypeId<QStringList>()) {
+ } else if (value.metaType() == QMetaType::fromType<QStringList>()) {
QStringList urlStrings = value.value<QStringList>();
const int urlStringsSize = urlStrings.size();
urls.reserve(urlStringsSize);
for (int i = 0; i < urlStringsSize; ++i)
urls.append(QUrl(urlStrings.at(i)));
- } else if (value.userType() == qMetaTypeId<QList<QString> >()) {
- QList<QString> urlStrings = value.value<QList<QString> >();
- const int urlStringsSize = urlStrings.size();
- urls.reserve(urlStringsSize);
- for (int i = 0; i < urlStringsSize; ++i)
- urls.append(QUrl(urlStrings.at(i)));
} // note: QList<QByteArray> is not currently supported.
+ return urls;
+}
- return QVariant::fromValue<QList<QUrl> >(urls);
+// ### Qt7: Get rid of this
+QList<QUrl> QQmlPropertyPrivate::urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt)
+{
+ QList<QUrl> urls = urlSequence(value);
+
+ for (auto urlIt = urls.begin(); urlIt != urls.end(); ++urlIt)
+ *urlIt = ctxt->resolvedUrl(*urlIt);
+
+ return urls;
}
//writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC!
@@ -1293,15 +1309,18 @@ bool QQmlPropertyPrivate::write(
return property.writeProperty(object, const_cast<void *>(value.constData()), flags);
} else if (property.isQObject()) {
QVariant val = value;
- int varType = variantType;
- if (variantType == QMetaType::Nullptr) {
+ const QMetaType variantMetaType = value.metaType();
+ QMetaType varType;
+ if (variantMetaType == QMetaType::fromType<std::nullptr_t>()) {
// This reflects the fact that you can assign a nullptr to a QObject pointer
// Without the change to QObjectStar, rawMetaObjectForType would not give us a QQmlMetaObject
- varType = QMetaType::QObjectStar;
+ varType = QMetaType::fromType<QObject*>();
val = QVariant(QMetaType::fromType<QObject *>(), nullptr);
+ } else {
+ varType = variantMetaType;
}
- QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType);
- if (valMo.isNull())
+ QQmlMetaObject valMo = rawMetaObjectForType(enginePriv, varType.id());
+ if (valMo.isNull() || !varType.flags().testFlag(QMetaType::PointerToQObject))
return false;
QObject *o = *static_cast<QObject *const *>(val.constData());
QQmlMetaObject propMo = rawMetaObjectForType(enginePriv, propertyType);
@@ -1354,8 +1373,11 @@ bool QQmlPropertyPrivate::write(
return property.writeProperty(object, const_cast<QVariant *>(&value), flags);
} else if (isUrl) {
QUrl u;
- if (variantType == QMetaType::QUrl)
+ if (variantType == QMetaType::QUrl) {
u = value.toUrl();
+ if (compatResolveUrlsOnAssigment() && context && u.isRelative() && !u.isEmpty())
+ u = context->resolvedUrl(u);
+ }
else if (variantType == QMetaType::QByteArray)
u = QUrl(QString::fromUtf8(value.toByteArray()));
else if (variantType == QMetaType::QString)
@@ -1365,7 +1387,9 @@ bool QQmlPropertyPrivate::write(
return property.writeProperty(object, &u, flags);
} else if (propertyType == qMetaTypeId<QList<QUrl>>()) {
- QList<QUrl> urlSeq = urlSequence(value).value<QList<QUrl>>();
+ QList<QUrl> urlSeq = compatResolveUrlsOnAssigment()
+ ? urlSequence(value, context)
+ : urlSequence(value);
return property.writeProperty(object, &urlSeq, flags);
} else if (property.isQList()) {
QQmlMetaObject listType;
@@ -1775,3 +1799,5 @@ void QQmlPropertyPrivate::flushSignal(const QObject *sender, int signal_index)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlproperty.cpp"
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index c54d066152..5b42134a1f 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -82,6 +82,9 @@ public:
QString nameCache;
+ // ### Qt7: Get rid of this.
+ static bool resolveUrlsOnAssignment();
+
QQmlPropertyPrivate() {}
QQmlPropertyIndex encodedIndex() const
@@ -161,7 +164,9 @@ public:
int type = 0, int *types = nullptr);
static void flushSignal(const QObject *sender, int signal_index);
- static QVariant urlSequence(const QVariant &value);
+ static QList<QUrl> urlSequence(const QVariant &value);
+ static QList<QUrl> urlSequence(
+ const QVariant &value, const QQmlRefPointer<QQmlContextData> &ctxt);
static QQmlProperty create(
QObject *target, const QString &propertyName,
const QQmlRefPointer<QQmlContextData> &context);
diff --git a/src/qml/qml/qqmlpropertybinding.cpp b/src/qml/qml/qqmlpropertybinding.cpp
index 185fac6dcc..0cc544e266 100644
--- a/src/qml/qml/qqmlpropertybinding.cpp
+++ b/src/qml/qml/qqmlpropertybinding.cpp
@@ -42,6 +42,9 @@
#include <private/qv4jscall_p.h>
#include <qqmlinfo.h>
#include <QtCore/qloggingcategory.h>
+#include <private/qqmlscriptstring_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qv4qmlcontext_p.h>
QT_BEGIN_NAMESPACE
@@ -91,6 +94,44 @@ QUntypedPropertyBinding QQmlPropertyBinding::createFromCodeString(const QQmlProp
return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
}
+QUntypedPropertyBinding QQmlPropertyBinding::createFromScriptString(const QQmlPropertyData *property, const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt, QObject *target, QQmlPropertyIndex targetIndex)
+{
+ const QQmlScriptStringPrivate *scriptPrivate = script.d.data();
+ // without a valid context, we cannot create anything
+ if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid())) {
+ return {};
+ }
+
+ auto scopeObject = obj ? obj : scriptPrivate->scope;
+
+ QV4::Function *runtimeFunction = nullptr;
+ QString url;
+ QQmlRefPointer<QQmlContextData> ctxtdata = QQmlContextData::get(scriptPrivate->context);
+ QQmlEnginePrivate *engine = QQmlEnginePrivate::get(scriptPrivate->context->engine());
+ if (engine && ctxtdata && !ctxtdata->urlString().isEmpty() && ctxtdata->typeCompilationUnit()) {
+ url = ctxtdata->urlString();
+ if (scriptPrivate->bindingId != QQmlBinding::Invalid)
+ runtimeFunction = ctxtdata->typeCompilationUnit()->runtimeFunctions.at(scriptPrivate->bindingId);
+ }
+ // Do we actually have a function in the script string? If not, this becomes createCodeFromString
+ if (!runtimeFunction)
+ return createFromCodeString(property, scriptPrivate->script, obj, ctxtdata, url, scriptPrivate->lineNumber, target, targetIndex);
+
+ auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
+ + sizeof(QQmlPropertyBindingJS)+jsExpressionOffsetLength()]; // QQmlPropertyBinding uses delete[]
+ auto binding = new(buffer) QQmlPropertyBinding(QMetaType(property->propType()), target, targetIndex, TargetData::WithoutBoundFunction);
+ auto js = new(buffer + QQmlPropertyBinding::getSizeEnsuringAlignment() + jsExpressionOffsetLength()) QQmlPropertyBindingJS();
+ Q_ASSERT(binding->jsExpression() == js);
+ Q_ASSERT(js->asBinding() == binding);
+ js->setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
+
+ QV4::ExecutionEngine *v4 = engine->v4engine();
+ QV4::Scope scope(v4);
+ QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxtdata, scopeObject));
+ js->setupFunction(qmlContext, runtimeFunction);
+ return QUntypedPropertyBinding(static_cast<QPropertyBindingPrivate *>(QPropertyBindingPrivatePtr(binding).data()));
+}
+
QUntypedPropertyBinding QQmlPropertyBinding::createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function, QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt, QV4::ExecutionContext *scope, QObject *target, QQmlPropertyIndex targetIndex)
{
auto buffer = new std::byte[QQmlPropertyBinding::getSizeEnsuringAlignment()
@@ -124,8 +165,10 @@ void QQmlPropertyBindingJS::expressionChanged()
{
if (!asBinding()->propertyDataPtr)
return;
+ if (QQmlData::wasDeleted(asBinding()->target()))
+ return;
const auto currentTag = m_error.tag();
- if (currentTag & InEvaluationLoop) {
+ if (currentTag == InEvaluationLoop) {
QQmlError err;
auto location = QQmlJavaScriptExpression::sourceLocation();
err.setUrl(QUrl{location.sourceFile});
@@ -141,15 +184,15 @@ void QQmlPropertyBindingJS::expressionChanged()
qmlWarning(this->scopeObject(), err);
return;
}
- m_error.setTag(currentTag | InEvaluationLoop);
+ m_error.setTag(InEvaluationLoop);
asBinding()->evaluateRecursive();
asBinding()->notifyRecursive();
- m_error.setTag(currentTag);
+ m_error.setTag(NoTag);
}
QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlPropertyIndex targetIndex, TargetData::BoundFunction hasBoundFunction)
: QPropertyBindingPrivate(mt,
- &QtPrivate::bindingFunctionVTable<QQmlPropertyBinding>,
+ bindingFunctionVTableForQQmlPropertyBinding(mt),
QPropertyBindingSourceLocation(), true)
{
static_assert (std::is_trivially_destructible_v<TargetData>);
@@ -160,165 +203,6 @@ QQmlPropertyBinding::QQmlPropertyBinding(QMetaType mt, QObject *target, QQmlProp
errorCallBack = bindingErrorCallback;
}
-template<typename T>
-bool compareAndAssign(void *dataPtr, const void *result)
-{
- if (*static_cast<const T *>(result) == *static_cast<const T *>(dataPtr))
- return false;
- *static_cast<T *>(dataPtr) = *static_cast<const T *>(result);
- return true;
-}
-
-bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
-{
- const auto ctxt = jsExpression()->context();
- QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
- if (!engine) {
- QPropertyBindingError error(QPropertyBindingError::EvaluationError);
- if (auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
- currentBinding->setError(std::move(error));
- return false;
- }
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- ep->referenceScarceResources();
-
- const auto handleErrorAndUndefined = [&](bool evaluatedToUndefined) {
- ep->dereferenceScarceResources();
- if (jsExpression()->hasError()) {
- QPropertyBindingError error(QPropertyBindingError::UnknownError,
- jsExpression()->delayedError()->error().description());
- QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
- bindingErrorCallback(this);
- return false;
- }
-
- if (evaluatedToUndefined) {
- handleUndefinedAssignment(ep, dataPtr);
- // if property has been changed due to reset, reset is responsible for
- // notifying observers
- return false;
- } else if (isUndefined()) {
- setIsUndefined(false);
- }
-
- return true;
- };
-
- if (!hasBoundFunction()) {
- Q_ASSERT(metaType.sizeOf() > 0);
-
- // No need to construct here. evaluate() expects uninitialized memory.
- Q_ALLOCA_VAR(void, result, metaType.sizeOf());
-
- const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
- if (!handleErrorAndUndefined(evaluatedToUndefined))
- return false;
-
- if (metaType.flags() & QMetaType::PointerToQObject)
- return compareAndAssign<QObject *>(dataPtr, result);
-
- switch (metaType.id()) {
- case QMetaType::Bool:
- return compareAndAssign<bool>(dataPtr, result);
- case QMetaType::Int:
- return compareAndAssign<int>(dataPtr, result);
- case QMetaType::Double:
- return compareAndAssign<double>(dataPtr, result);
- case QMetaType::Float:
- return compareAndAssign<float>(dataPtr, result);
- case QMetaType::QString: {
- const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
- static_cast<QString *>(result)->~QString();
- return hasChanged;
- }
- default:
- break;
- }
-
- const bool hasChanged = !metaType.equals(result, dataPtr);
- if (hasChanged) {
- metaType.destruct(dataPtr);
- metaType.construct(dataPtr, result);
- }
- metaType.destruct(result);
- return hasChanged;
- }
-
- bool evaluatedToUndefined = false;
- QV4::Scope scope(engine->handle());
- QV4::ScopedValue result(scope, static_cast<QQmlPropertyBindingJSForBoundFunction *>(
- jsExpression())->evaluate(&evaluatedToUndefined));
-
- if (!handleErrorAndUndefined(evaluatedToUndefined))
- return false;
-
- int propertyType = metaType.id();
-
- switch (propertyType) {
- case QMetaType::Bool: {
- bool b;
- if (result->isBoolean())
- b = result->booleanValue();
- else
- b = result->toBoolean();
- if (b == *static_cast<bool *>(dataPtr))
- return false;
- *static_cast<bool *>(dataPtr) = b;
- return true;
- }
- case QMetaType::Int: {
- int i;
- if (result->isInteger())
- i = result->integerValue();
- else if (result->isNumber()) {
- i = QV4::StaticValue::toInteger(result->doubleValue());
- } else {
- break;
- }
- if (i == *static_cast<int *>(dataPtr))
- return false;
- *static_cast<int *>(dataPtr) = i;
- return true;
- }
- case QMetaType::Double:
- if (result->isNumber()) {
- double d = result->asDouble();
- if (d == *static_cast<double *>(dataPtr))
- return false;
- *static_cast<double *>(dataPtr) = d;
- return true;
- }
- break;
- case QMetaType::Float:
- if (result->isNumber()) {
- float d = float(result->asDouble());
- if (d == *static_cast<float *>(dataPtr))
- return false;
- *static_cast<float *>(dataPtr) = d;
- return true;
- }
- break;
- case QMetaType::QString:
- if (result->isString()) {
- QString s = result->toQStringNoThrow();
- if (s == *static_cast<QString *>(dataPtr))
- return false;
- *static_cast<QString *>(dataPtr) = s;
- return true;
- }
- break;
- default:
- break;
- }
-
- QVariant resultVariant(scope.engine->toVariant(result, metaType));
- resultVariant.convert(metaType);
- const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
- metaType.destruct(dataPtr);
- metaType.construct(dataPtr, resultVariant.constData());
- return hasChanged;
-}
-
static QtPrivate::QPropertyBindingData *bindingDataFromPropertyData(QUntypedPropertyData *dataPtr, QMetaType type)
{
// XXX Qt 7: We need a clean way to access the binding data
@@ -452,8 +336,8 @@ void QQmlPropertyBinding::bindingErrorCallback(QPropertyBindingPrivate *that)
QUntypedPropertyBinding QQmlTranslationPropertyBinding::create(const QQmlPropertyData *pd, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
auto translationBinding = [compilationUnit, binding](const QMetaType &metaType, void *dataPtr) -> bool {
- // Create a dependency to the uiLanguage
- QJSEnginePrivate::get(compilationUnit->engine)->uiLanguage.value();
+ // Create a dependency to the translationLanguage
+ QQmlEnginePrivate::get(compilationUnit->engine)->translationLanguage.value();
QVariant resultVariant(compilationUnit->bindingValueAsString(binding));
if (metaType.id() != QMetaType::QString)
diff --git a/src/qml/qml/qqmlpropertybinding_p.h b/src/qml/qml/qqmlpropertybinding_p.h
index 341e300de4..17f74d5675 100644
--- a/src/qml/qml/qqmlpropertybinding_p.h
+++ b/src/qml/qml/qqmlpropertybinding_p.h
@@ -56,6 +56,7 @@
#include "qqmlpropertydata_p.h"
#include "qqmljavascriptexpression_p.h"
+#include <private/qv4alloca_p.h>
#include <memory>
@@ -69,6 +70,8 @@ class QQmlPropertyBinding;
class Q_QML_PRIVATE_EXPORT QQmlPropertyBindingJS : public QQmlJavaScriptExpression
{
+ bool mustCaptureBindableProperty() const final {return false;}
+
friend class QQmlPropertyBinding;
void expressionChanged() override;
QQmlPropertyBinding *asBinding()
@@ -126,6 +129,10 @@ public:
const QQmlRefPointer<QQmlContextData> &ctxt,
const QString &url, quint16 lineNumber,
QObject *target, QQmlPropertyIndex targetIndex);
+ static QUntypedPropertyBinding createFromScriptString(const QQmlPropertyData *property,
+ const QQmlScriptString& script, QObject *obj,
+ QQmlContext *ctxt, QObject *target,
+ QQmlPropertyIndex targetIndex);
static QUntypedPropertyBinding createFromBoundFunction(const QQmlPropertyData *pd, QV4::BoundFunction *function,
QObject *obj, const QQmlRefPointer<QQmlContextData> &ctxt,
@@ -144,11 +151,12 @@ public:
return static_cast<const QQmlPropertyBinding *>(binding)->isUndefined();
}
+ template<QMetaType::Type type>
static bool doEvaluate(QMetaType metaType, QUntypedPropertyData *dataPtr, void *f) {
auto address = static_cast<std::byte*>(f);
address -= QPropertyBindingPrivate::getSizeEnsuringAlignment(); // f now points to QPropertyBindingPrivate suboject
// and that has the same address as QQmlPropertyBinding
- return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate(metaType, dataPtr);
+ return reinterpret_cast<QQmlPropertyBinding *>(address)->evaluate<type>(metaType, dataPtr);
}
bool hasDependencies()
@@ -157,6 +165,7 @@ public:
}
private:
+ template <QMetaType::Type type>
bool evaluate(QMetaType metaType, void *dataPtr);
Q_NEVER_INLINE void handleUndefinedAssignment(QQmlEnginePrivate *ep, void *dataPtr);
@@ -210,9 +219,9 @@ template <auto I>
struct Print {};
namespace QtPrivate {
-template<>
-inline constexpr BindingFunctionVTable bindingFunctionVTable<QQmlPropertyBinding> = {
- &QQmlPropertyBinding::doEvaluate,
+template<QMetaType::Type type>
+inline constexpr BindingFunctionVTable bindingFunctionVTableForQQmlPropertyBinding = {
+ &QQmlPropertyBinding::doEvaluate<type>,
[](void *qpropertyBinding){
QQmlPropertyBinding *binding = reinterpret_cast<QQmlPropertyBinding *>(qpropertyBinding);
binding->jsExpression()->~QQmlPropertyBindingJS();
@@ -225,6 +234,24 @@ inline constexpr BindingFunctionVTable bindingFunctionVTable<QQmlPropertyBinding
};
}
+inline const QtPrivate::BindingFunctionVTable *bindingFunctionVTableForQQmlPropertyBinding(QMetaType type)
+{
+#define FOR_TYPE(TYPE) \
+ case TYPE: return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<TYPE>
+ switch (type.id()) {
+ FOR_TYPE(QMetaType::Int);
+ FOR_TYPE(QMetaType::QString);
+ FOR_TYPE(QMetaType::Double);
+ FOR_TYPE(QMetaType::Float);
+ FOR_TYPE(QMetaType::Bool);
+ default:
+ if (type.flags() & QMetaType::PointerToQObject)
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::QObjectStar>;
+ return &QtPrivate::bindingFunctionVTableForQQmlPropertyBinding<QMetaType::UnknownType>;
+ }
+#undef FOR_TYPE
+}
+
class QQmlTranslationPropertyBinding
{
public:
@@ -242,6 +269,173 @@ inline const QQmlPropertyBinding *QQmlPropertyBindingJS::asBinding() const
}
static_assert(sizeof(QQmlPropertyBinding) == sizeof(QPropertyBindingPrivate)); // else the whole offset computatation will break
+template<typename T>
+bool compareAndAssign(void *dataPtr, const void *result)
+{
+ if (*static_cast<const T *>(result) == *static_cast<const T *>(dataPtr))
+ return false;
+ *static_cast<T *>(dataPtr) = *static_cast<const T *>(result);
+ return true;
+}
+
+template <QMetaType::Type type>
+bool QQmlPropertyBinding::evaluate(QMetaType metaType, void *dataPtr)
+{
+ const auto ctxt = jsExpression()->context();
+ QQmlEngine *engine = ctxt ? ctxt->engine() : nullptr;
+ if (!engine) {
+ QPropertyBindingError error(QPropertyBindingError::EvaluationError);
+ if (auto currentBinding = QPropertyBindingPrivate::currentlyEvaluatingBinding())
+ currentBinding->setError(std::move(error));
+ return false;
+ }
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ ep->referenceScarceResources();
+
+ const auto handleErrorAndUndefined = [&](bool evaluatedToUndefined) {
+ ep->dereferenceScarceResources();
+ if (jsExpression()->hasError()) {
+ QPropertyBindingError error(QPropertyBindingError::UnknownError,
+ jsExpression()->delayedError()->error().description());
+ QPropertyBindingPrivate::currentlyEvaluatingBinding()->setError(std::move(error));
+ bindingErrorCallback(this);
+ return false;
+ }
+
+ if (evaluatedToUndefined) {
+ handleUndefinedAssignment(ep, dataPtr);
+ // if property has been changed due to reset, reset is responsible for
+ // notifying observers
+ return false;
+ } else if (isUndefined()) {
+ setIsUndefined(false);
+ }
+
+ return true;
+ };
+
+ if (!hasBoundFunction()) {
+ Q_ASSERT(metaType.sizeOf() > 0);
+
+ // No need to construct here. evaluate() expects uninitialized memory.
+ const auto size = [&]() -> qsizetype {
+ switch (type) {
+ case QMetaType::QObjectStar: return sizeof(QObject *);
+ case QMetaType::Bool: return sizeof(bool);
+ case QMetaType::Int: return (sizeof(int));
+ case QMetaType::Double: return (sizeof(double));
+ case QMetaType::Float: return (sizeof(float));
+ case QMetaType::QString: return (sizeof(QString));
+ default: return metaType.sizeOf();
+ }
+ }();
+ Q_ALLOCA_VAR(void, result, size);
+
+ const bool evaluatedToUndefined = !jsExpression()->evaluate(&result, &metaType, 0);
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::QObjectStar:
+ return compareAndAssign<QObject *>(dataPtr, result);
+ case QMetaType::Bool:
+ return compareAndAssign<bool>(dataPtr, result);
+ case QMetaType::Int:
+ return compareAndAssign<int>(dataPtr, result);
+ case QMetaType::Double:
+ return compareAndAssign<double>(dataPtr, result);
+ case QMetaType::Float:
+ return compareAndAssign<float>(dataPtr, result);
+ case QMetaType::QString: {
+ const bool hasChanged = compareAndAssign<QString>(dataPtr, result);
+ static_cast<QString *>(result)->~QString();
+ return hasChanged;
+ }
+ default:
+ break;
+ }
+
+ const bool hasChanged = !metaType.equals(result, dataPtr);
+ if (hasChanged) {
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, result);
+ }
+ metaType.destruct(result);
+ return hasChanged;
+ }
+
+ bool evaluatedToUndefined = false;
+ QV4::Scope scope(engine->handle());
+ QV4::ScopedValue result(scope, static_cast<QQmlPropertyBindingJSForBoundFunction *>(
+ jsExpression())->evaluate(&evaluatedToUndefined));
+
+ if (!handleErrorAndUndefined(evaluatedToUndefined))
+ return false;
+
+ switch (type) {
+ case QMetaType::Bool: {
+ bool b;
+ if (result->isBoolean())
+ b = result->booleanValue();
+ else
+ b = result->toBoolean();
+ if (b == *static_cast<bool *>(dataPtr))
+ return false;
+ *static_cast<bool *>(dataPtr) = b;
+ return true;
+ }
+ case QMetaType::Int: {
+ int i;
+ if (result->isInteger())
+ i = result->integerValue();
+ else if (result->isNumber()) {
+ i = QV4::StaticValue::toInteger(result->doubleValue());
+ } else {
+ break;
+ }
+ if (i == *static_cast<int *>(dataPtr))
+ return false;
+ *static_cast<int *>(dataPtr) = i;
+ return true;
+ }
+ case QMetaType::Double:
+ if (result->isNumber()) {
+ double d = result->asDouble();
+ if (d == *static_cast<double *>(dataPtr))
+ return false;
+ *static_cast<double *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::Float:
+ if (result->isNumber()) {
+ float d = float(result->asDouble());
+ if (d == *static_cast<float *>(dataPtr))
+ return false;
+ *static_cast<float *>(dataPtr) = d;
+ return true;
+ }
+ break;
+ case QMetaType::QString:
+ if (result->isString()) {
+ QString s = result->toQStringNoThrow();
+ if (s == *static_cast<QString *>(dataPtr))
+ return false;
+ *static_cast<QString *>(dataPtr) = s;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ QVariant resultVariant(scope.engine->toVariant(result, metaType));
+ resultVariant.convert(metaType);
+ const bool hasChanged = !metaType.equals(resultVariant.constData(), dataPtr);
+ metaType.destruct(dataPtr);
+ metaType.construct(dataPtr, resultVariant.constData());
+ return hasChanged;
+}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 269f02afbd..2ebba1eb72 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -51,8 +51,8 @@
#include <QtCore/qdebug.h>
#include <QtCore/QCryptographicHash>
+#include <QtCore/private/qtools_p.h>
-#include <ctype.h> // for toupper
#include <limits.h>
#include <algorithm>
@@ -159,14 +159,23 @@ QQmlPropertyCache::QQmlPropertyCache()
}
/*!
-Creates a new QQmlPropertyCache of \a metaObject.
+ Creates a standalone QQmlPropertyCache of \a metaObject. It is separate from the usual
+ QQmlPropertyCache hierarchy. Its parent is not equal to any other QQmlPropertyCache
+ created from QObject::staticMetaObject, for example.
*/
-QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
- : QQmlPropertyCache()
+QQmlRefPointer<QQmlPropertyCache> QQmlPropertyCache::createStandalone(
+ const QMetaObject *metaObject, QTypeRevision metaObjectRevision)
{
Q_ASSERT(metaObject);
- update(metaObject);
+ QQmlRefPointer<QQmlPropertyCache> result;
+ if (const QMetaObject *super = metaObject->superClass()) {
+ result.adopt(createStandalone(super, metaObjectRevision)
+ ->copyAndAppend(metaObject, metaObjectRevision));
+ } else {
+ result.adopt(new QQmlPropertyCache());
+ result->update(metaObject);
+ }
if (metaObjectRevision.isValid() && metaObjectRevision != QTypeRevision::zero()) {
// Set the revision of the meta object that this cache describes to be
@@ -174,9 +183,13 @@ QQmlPropertyCache::QQmlPropertyCache(const QMetaObject *metaObject, QTypeRevisio
// from a type that was created directly in C++, and not through QML. For such
// types, the revision for each recorded QMetaObject would normally be zero, which
// would exclude any revisioned properties.
- for (int metaObjectOffset = 0; metaObjectOffset < allowedRevisionCache.size(); ++metaObjectOffset)
- allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ for (int metaObjectOffset = 0; metaObjectOffset < result->allowedRevisionCache.size();
+ ++metaObjectOffset) {
+ result->allowedRevisionCache[metaObjectOffset] = metaObjectRevision;
+ }
}
+
+ return result;
}
QQmlPropertyCache::~QQmlPropertyCache()
@@ -350,7 +363,7 @@ const QMetaObject *QQmlPropertyCache::createMetaObject()
QQmlPropertyData *QQmlPropertyCache::maybeUnresolvedProperty(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
QQmlPropertyData *rv = nullptr;
@@ -514,7 +527,7 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
QVarLengthArray<char, 128> str(length+3);
str[0] = 'o';
str[1] = 'n';
- str[2] = toupper(rawName[0]);
+ str[2] = QtMiscUtils::toAsciiUpper(rawName[0]);
if (length > 1)
memcpy(&str[3], &rawName[1], length - 1);
str[length + 2] = '\0';
@@ -593,16 +606,6 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject,
}
}
-void QQmlPropertyCache::updateRecur(const QMetaObject *metaObject)
-{
- if (!metaObject)
- return;
-
- updateRecur(metaObject->superClass());
-
- append(metaObject, QTypeRevision());
-}
-
void QQmlPropertyCache::update(const QMetaObject *metaObject)
{
Q_ASSERT(metaObject);
@@ -622,7 +625,8 @@ void QQmlPropertyCache::update(const QMetaObject *metaObject)
// cached in a parent cache.
stringCache.reserve(pc + mc + sc);
- updateRecur(metaObject);
+ if (metaObject)
+ append(metaObject, QTypeRevision());
}
/*! \internal
@@ -676,7 +680,8 @@ inline bool contextHasNoExtensions(const QQmlRefPointer<QQmlContextData> &contex
{
// This context has no extension if its parent is the engine's rootContext,
// which has children but no imports
- return (!context->parent() || !context->parent()->imports());
+ const QQmlRefPointer<QQmlContextData> parent = context->parent();
+ return (!parent || !parent->imports());
}
inline int maximumIndexForProperty(QQmlPropertyData *prop, const int methodCount, const int signalCount, const int propertyCount)
@@ -1062,6 +1067,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder)
property.setWritable(data->isWritable());
property.setResettable(data->isResettable());
property.setBindable(data->isBindable());
+ property.setAlias(data->isAlias());
}
for (int ii = 0; ii < methods.count(); ++ii) {
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index f3f81fbc78..689ce8d35f 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -129,7 +129,10 @@ class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount
{
public:
QQmlPropertyCache();
- QQmlPropertyCache(const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
+
+ static QQmlRefPointer<QQmlPropertyCache> createStandalone(
+ const QMetaObject *, QTypeRevision metaObjectRevision = QTypeRevision::zero());
+
~QQmlPropertyCache() override;
void update(const QMetaObject *);
@@ -246,8 +249,6 @@ private:
QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *,
const QQmlRefPointer<QQmlContextData> &) const;
- void updateRecur(const QMetaObject *);
-
template<typename K>
QQmlPropertyData *findNamedProperty(const K &key) const
{
@@ -326,7 +327,7 @@ inline const QMetaObject *QQmlPropertyCache::firstCppMetaObject() const
inline QQmlPropertyData *QQmlPropertyCache::property(int index) const
{
- if (index < 0 || index >= (propertyIndexCacheStart + propertyIndexCache.count()))
+ if (index < 0 || index >= propertyCount())
return nullptr;
if (index < propertyIndexCacheStart)
diff --git a/src/qml/qml/qqmlpropertycachecreator.cpp b/src/qml/qml/qqmlpropertycachecreator.cpp
index ff607add09..f6bedc94e9 100644
--- a/src/qml/qml/qqmlpropertycachecreator.cpp
+++ b/src/qml/qml/qqmlpropertycachecreator.cpp
@@ -110,11 +110,15 @@ QQmlBindingInstantiationContext::QQmlBindingInstantiationContext(int referencing
bool QQmlBindingInstantiationContext::resolveInstantiatingProperty()
{
- if (!instantiatingBinding || instantiatingBinding->type != QV4::CompiledData::Binding::Type_GroupProperty)
+ if (!instantiatingBinding
+ || instantiatingBinding->type() != QV4::CompiledData::Binding::Type_GroupProperty) {
return true;
+ }
+
+ if (!referencingObjectPropertyCache)
+ return false;
Q_ASSERT(referencingObjectIndex >= 0);
- Q_ASSERT(referencingObjectPropertyCache);
Q_ASSERT(instantiatingBinding->propertyNameIndex != 0);
bool notInRevision = false;
@@ -147,6 +151,11 @@ void QQmlPendingGroupPropertyBindings::resolveMissingPropertyCaches(QQmlEnginePr
if (propertyCaches->at(groupPropertyObjectIndex))
continue;
+ if (!pendingBinding.referencingObjectPropertyCache) {
+ pendingBinding.referencingObjectPropertyCache
+ = propertyCaches->at(pendingBinding.referencingObjectIndex);
+ }
+
if (!pendingBinding.resolveInstantiatingProperty())
continue;
diff --git a/src/qml/qml/qqmlpropertycachecreator_p.h b/src/qml/qml/qqmlpropertycachecreator_p.h
index 0a5e642c9f..c415b5f33a 100644
--- a/src/qml/qml/qqmlpropertycachecreator_p.h
+++ b/src/qml/qml/qqmlpropertycachecreator_p.h
@@ -67,8 +67,8 @@ inline QQmlError qQmlCompileError(const QV4::CompiledData::Location &location,
const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
return error;
}
@@ -243,7 +243,7 @@ QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectsIncrementally()
// create meta objects for inline components before compiling actual root component
if (nodeIt != nodesSorted.rend()) {
- const auto &ic = allICs[nodeIt->index];
+ const auto &ic = allICs[nodeIt->index()];
QV4::ResolvedTypeReference *typeRef = objectContainer->resolvedType(ic.nameIndex);
Q_ASSERT(propertyCaches->at(ic.objectIndex) == nullptr);
Q_ASSERT(typeRef->typePropertyCache().isNull()); // not set yet
@@ -290,7 +290,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
const CompiledObject *obj = objectContainer->objectAt(objectIndex);
bool needVMEMetaObject = isVMERequired == VMEMetaObjectIsRequired::Always || obj->propertyCount() != 0 || obj->aliasCount() != 0
|| obj->signalCount() != 0 || obj->functionCount() != 0 || obj->enumCount() != 0
- || (((obj->flags & QV4::CompiledData::Object::IsComponent)
+ || ((obj->hasFlag(QV4::CompiledData::Object::IsComponent)
|| (objectIndex == 0 && isAddressable(objectContainer->url())))
&& !objectContainer->resolvedType(obj->inheritedTypeNameIndex)->isFullyDynamicType());
@@ -298,7 +298,8 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
auto binding = obj->bindingsBegin();
auto end = obj->bindingsEnd();
for ( ; binding != end; ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object
+ && (binding->flags() & QV4::CompiledData::Binding::IsOnAssignment)) {
// If the on assignment is inside a group property, we need to distinguish between QObject based
// group properties and value type group properties. For the former the base type is derived from
// the property that references us, for the latter we only need a meta-object on the referencing object
@@ -340,24 +341,24 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::buildMetaObjectRecur
}
}
- if (QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex)) {
- auto binding = obj->bindingsBegin();
- auto end = obj->bindingsEnd();
- for ( ; binding != end; ++binding)
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
- QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
-
- // Binding to group property where we failed to look up the type of the
- // property? Possibly a group property that is an alias that's not resolved yet.
- // Let's attempt to resolve it after we're done with the aliases and fill in the
- // propertyCaches entry then.
- if (!context.resolveInstantiatingProperty())
- pendingGroupPropertyBindings->append(context);
-
- QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
- if (error.isValid())
- return error;
- }
+ QQmlPropertyCache *thisCache = propertyCaches->at(objectIndex);
+ auto binding = obj->bindingsBegin();
+ auto end = obj->bindingsEnd();
+ for ( ; binding != end; ++binding) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
+ QQmlBindingInstantiationContext context(objectIndex, &(*binding), stringAt(binding->propertyNameIndex), thisCache);
+
+ // Binding to group property where we failed to look up the type of the
+ // property? Possibly a group property that is an alias that's not resolved yet.
+ // Let's attempt to resolve it after we're done with the aliases and fill in the
+ // propertyCaches entry then.
+ if (!thisCache || !context.resolveInstantiatingProperty())
+ pendingGroupPropertyBindings->append(context);
+
+ QQmlError error = buildMetaObjectRecursively(binding->value.objectIndex, context, VMEMetaObjectIsRequired::Maybe);
+ if (error.isValid())
+ return error;
+ }
}
QQmlError noError;
@@ -448,7 +449,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
auto aend = obj->aliasesEnd();
for ( ; a != aend; ++a) {
bool notInRevision = false;
- QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
+ QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex()), &notInRevision);
if (d && d->isFinal())
return qQmlCompileError(a->location, QQmlPropertyCacheCreatorBase::tr("Cannot override FINAL property"));
}
@@ -496,7 +497,7 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
for ( ; a != aend; ++a) {
auto flags = QQmlPropertyData::defaultSignalFlags();
- QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
+ QString changedSigName = stringAt(a->nameIndex()) + QLatin1String("Changed");
seenSignals.insert(changedSigName);
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
@@ -606,15 +607,14 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
if (type == QV4::CompiledData::BuiltinType::Var)
propertyFlags.type = QQmlPropertyData::Flags::VarPropertyType;
-
if (type != QV4::CompiledData::BuiltinType::InvalidBuiltin) {
propertyType = metaTypeForPropertyType(type);
} else {
- Q_ASSERT(!p->isBuiltinType);
+ Q_ASSERT(!p->isBuiltinType());
QQmlType qmltype;
bool selfReference = false;
- if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex), &qmltype, nullptr, nullptr,
+ if (!imports->resolveType(stringAt(p->builtinTypeOrTypeNameIndex()), &qmltype, nullptr, nullptr,
nullptr, QQmlType::AnyRegistrationType, &selfReference)) {
return qQmlCompileError(p->location, QQmlPropertyCacheCreatorBase::tr("Invalid property type"));
}
@@ -646,13 +646,13 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
typeIds = compilationUnit->typeIdsForComponent();
}
- if (p->isList) {
+ if (p->isList()) {
propertyType = typeIds.listId;
} else {
propertyType = typeIds.id;
}
} else {
- if (p->isList) {
+ if (p->isList()) {
propertyType = qmltype.qListTypeId();
} else {
propertyType = qmltype.typeId();
@@ -660,18 +660,18 @@ inline QQmlError QQmlPropertyCacheCreator<ObjectContainer>::createMetaObject(int
}
}
- if (p->isList)
+ if (p->isList())
propertyFlags.type = QQmlPropertyData::Flags::QListType;
else
propertyFlags.type = QQmlPropertyData::Flags::QObjectDerivedType;
}
- if (!p->isReadOnly && !p->isList)
+ if (!p->isReadOnly() && !p->isList())
propertyFlags.setIsWritable(true);
QString propertyName = stringAt(p->nameIndex);
- if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
+ if (!obj->hasAliasAsDefaultProperty() && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
propertyType, propertyTypeVersion, effectiveSignalIndex);
@@ -687,13 +687,14 @@ template <typename ObjectContainer>
inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter(const QV4::CompiledData::ParameterType &param,
QString *customTypeName)
{
- if (param.indexIsBuiltinType) {
+ if (param.indexIsBuiltinType()) {
// built-in type
- return metaTypeForPropertyType(static_cast<QV4::CompiledData::BuiltinType>(int(param.typeNameIndexOrBuiltinType)));
+ return metaTypeForPropertyType(
+ static_cast<QV4::CompiledData::BuiltinType>(param.typeNameIndexOrBuiltinType()));
}
// lazily resolved type
- const QString typeName = stringAt(param.typeNameIndexOrBuiltinType);
+ const QString typeName = stringAt(param.typeNameIndexOrBuiltinType());
if (customTypeName)
*customTypeName = typeName;
QQmlType qmltype;
@@ -702,8 +703,15 @@ inline QMetaType QQmlPropertyCacheCreator<ObjectContainer>::metaTypeForParameter
QQmlType::AnyRegistrationType, &selfReference))
return QMetaType();
- if (!qmltype.isComposite())
- return qmltype.typeId();
+ if (!qmltype.isComposite()) {
+ const QMetaType typeId = qmltype.typeId();
+ if (!typeId.isValid() && qmltype.isInlineComponentType()) {
+ const int objectId = qmltype.inlineComponentId();
+ return objectContainer->typeIdsForComponent(objectId).id;
+ } else {
+ return typeId;
+ }
+ }
if (selfReference)
return objectContainer->typeIdsForComponent().id;
@@ -756,7 +764,7 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
// from a binding.
for (int i = 1; i < objectContainer->objectCount(); ++i) {
const CompiledObject &component = *objectContainer->objectAt(i);
- if (!(component.flags & QV4::CompiledData::Object::IsComponent))
+ if (!component.hasFlag(QV4::CompiledData::Object::IsComponent))
continue;
const auto rootBinding = component.bindingsBegin();
@@ -779,12 +787,12 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasPropertie
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
- const int targetObjectIndex = objectForId(component, alias->targetObjectId);
+ const int targetObjectIndex = objectForId(component, alias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
- if (alias->aliasToLocalAlias)
+ if (alias->isAliasToLocalAlias())
continue;
if (alias->encodedMetaPropertyIndex == -1)
@@ -826,18 +834,21 @@ inline void QQmlPropertyCacheAliasCreator<ObjectContainer>::collectObjectsWithAl
objectsWithAliases->append(objectIndex);
// Stop at Component boundary
- if (object.flags & QV4::CompiledData::Object::IsComponent && objectIndex != /*root object*/0)
+ if (object.hasFlag(QV4::CompiledData::Object::IsComponent) && objectIndex != /*root object*/0)
return;
auto binding = object.bindingsBegin();
auto end = object.bindingsEnd();
for (; binding != end; ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ collectObjectsWithAliasesRecursively(binding->value.objectIndex, objectsWithAliases);
+ break;
+ default:
+ break;
+ }
}
}
@@ -854,12 +865,12 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
propertyFlags->setIsAlias(true);
- if (alias.aliasToLocalAlias) {
+ if (alias.isAliasToLocalAlias()) {
const QV4::CompiledData::Alias *lastAlias = &alias;
QVarLengthArray<const QV4::CompiledData::Alias *, 4> seenAliases({lastAlias});
do {
- const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId);
+ const int targetObjectIndex = objectForId(component, lastAlias->targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject *targetObject = objectContainer->objectAt(targetObjectIndex);
Q_ASSERT(targetObject);
@@ -876,17 +887,17 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
seenAliases.append(targetAlias);
lastAlias = targetAlias;
- } while (lastAlias->aliasToLocalAlias);
+ } while (lastAlias->isAliasToLocalAlias());
return propertyDataForAlias(component, *lastAlias, type, version, propertyFlags, enginePriv);
}
- const int targetObjectIndex = objectForId(component, alias.targetObjectId);
+ const int targetObjectIndex = objectForId(component, alias.targetObjectId());
Q_ASSERT(targetObjectIndex >= 0);
const CompiledObject &targetObject = *objectContainer->objectAt(targetObjectIndex);
if (alias.encodedMetaPropertyIndex == -1) {
- Q_ASSERT(alias.flags & QV4::CompiledData::Alias::AliasPointsToPointerObject);
+ Q_ASSERT(alias.hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject));
auto *typeRef = objectContainer->resolvedType(targetObject.inheritedTypeNameIndex);
if (!typeRef) {
// Can be caused by the alias target not being a valid id or property. E.g.:
@@ -897,10 +908,16 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
}
const auto referencedType = typeRef->type();
- if (referencedType.isValid())
+ if (referencedType.isValid()) {
*type = referencedType.typeId();
- else
+ if (!type->isValid() && referencedType.isInlineComponentType()) {
+ int objectId = referencedType.inlineComponentId();
+ *type = objectContainer->typeIdsForComponent(objectId).id;
+ Q_ASSERT(type->isValid());
+ }
+ } else {
*type = typeRef->compilationUnit()->typeIds.id;
+ }
*version = typeRef->version();
@@ -960,7 +977,8 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::propertyDataFor
}
}
- propertyFlags->setIsWritable(!(alias.flags & QV4::CompiledData::Alias::IsReadOnly) && writable);
+ propertyFlags->setIsWritable(!(alias.hasFlag(QV4::CompiledData::Alias::IsReadOnly))
+ && writable);
propertyFlags->setIsResettable(resettable);
propertyFlags->setIsBindable(bindable);
return QQmlError();
@@ -984,7 +1002,7 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
auto alias = object.aliasesBegin();
auto end = object.aliasesEnd();
for ( ; alias != end; ++alias, ++aliasIndex) {
- Q_ASSERT(alias->flags & QV4::CompiledData::Alias::Resolved);
+ Q_ASSERT(alias->hasFlag(QV4::CompiledData::Alias::Resolved));
QMetaType type;
QTypeRevision version = QTypeRevision::zero();
@@ -994,9 +1012,9 @@ inline QQmlError QQmlPropertyCacheAliasCreator<ObjectContainer>::appendAliasesTo
if (error.isValid())
return error;
- const QString propertyName = objectContainer->stringAt(alias->nameIndex);
+ const QString propertyName = objectContainer->stringAt(alias->nameIndex());
- if (object.defaultPropertyIsAlias && aliasIndex == object.indexOfDefaultPropertyOrAlias)
+ if (object.hasAliasAsDefaultProperty() && aliasIndex == object.indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
@@ -1012,7 +1030,7 @@ inline int QQmlPropertyCacheAliasCreator<ObjectContainer>::objectForId(const Com
for (quint32 i = 0, count = component.namedObjectsInComponentCount(); i < count; ++i) {
const int candidateIndex = component.namedObjectsInComponentTable()[i];
const CompiledObject &candidate = *objectContainer->objectAt(candidateIndex);
- if (candidate.id == id)
+ if (candidate.objectId() == id)
return candidateIndex;
}
return -1;
diff --git a/src/qml/qml/qqmlpropertydata_p.h b/src/qml/qml/qqmlpropertydata_p.h
index edf777ff18..1fbf24a1a7 100644
--- a/src/qml/qml/qqmlpropertydata_p.h
+++ b/src/qml/qml/qqmlpropertydata_p.h
@@ -281,7 +281,6 @@ public:
{
Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
- Q_ASSERT(idx != m_coreIndex);
m_overrideIndex = qint16(idx);
}
diff --git a/src/qml/qml/qqmlpropertyvalidator.cpp b/src/qml/qml/qqmlpropertyvalidator.cpp
index f1826b2f1c..6a36c279e8 100644
--- a/src/qml/qml/qqmlpropertyvalidator.cpp
+++ b/src/qml/qml/qqmlpropertyvalidator.cpp
@@ -106,10 +106,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return errors;
}
- if (obj->flags & QV4::CompiledData::Object::IsComponent && !(obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)) {
+ if (obj->hasFlag(QV4::CompiledData::Object::IsComponent)
+ && !obj->hasFlag(QV4::CompiledData::Object::IsInlineComponentRoot)) {
Q_ASSERT(obj->nBindings == 1);
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return validateObject(componentBinding->value.objectIndex, componentBinding);
}
@@ -134,7 +135,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!binding->isGroupProperty())
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment))
continue;
if (populatingValueTypeGroupProperty) {
@@ -163,9 +164,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
binding = obj->bindingTable();
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
QString name = stringAt(binding->propertyNameIndex);
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
customBindings << binding;
continue;
@@ -178,13 +181,14 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
bool bindingToDefaultProperty = false;
- bool isGroupProperty = instantiatingBinding && instantiatingBinding->type == QV4::CompiledData::Binding::Type_GroupProperty;
+ bool isGroupProperty = instantiatingBinding
+ && instantiatingBinding->type() == QV4::CompiledData::Binding::Type_GroupProperty;
bool notInRevision = false;
QQmlPropertyData *pd = nullptr;
if (!name.isEmpty()) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject) {
pd = propertyResolver.signal(name, &notInRevision);
} else {
pd = propertyResolver.property(name, &notInRevision,
@@ -228,11 +232,12 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(binding->location, tr("Invalid attached object assignment"));
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty())) {
const bool populatingValueTypeGroupProperty
= pd
&& QQmlMetaType::metaObjectForValueType(pd->propType())
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment);
+ && !binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment);
const QVector<QQmlError> subObjectValidatorErrors
= validateObject(binding->value.objectIndex, binding,
populatingValueTypeGroupProperty);
@@ -241,13 +246,13 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
}
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
- if (binding->flags & (QV4::CompiledData::Binding::IsSignalHandlerExpression
+ if (binding->flags() & (QV4::CompiledData::Binding::IsSignalHandlerExpression
| QV4::CompiledData::Binding::IsSignalHandlerObject
| QV4::CompiledData::Binding::IsPropertyObserver)) {
continue;
}
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (instantiatingBinding && (instantiatingBinding->isAttachedProperty() || instantiatingBinding->isGroupProperty())) {
return recordError(binding->location, tr("Attached properties cannot be used here"));
}
@@ -261,15 +266,15 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!pd->isWritable()
&& !pd->isQList()
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
+ && !(bindingFlags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration)
) {
- if (assigningToGroupProperty && binding->type < QV4::CompiledData::Binding::Type_Object)
+ if (assigningToGroupProperty && bindingType < QV4::CompiledData::Binding::Type_Object)
return recordError(binding->valueLocation, tr("Cannot assign a value directly to a grouped property"));
return recordError(binding->valueLocation, tr("Invalid property assignment: \"%1\" is a read-only property").arg(name));
}
- if (!pd->isQList() && (binding->flags & QV4::CompiledData::Binding::IsListItem)) {
+ if (!pd->isQList() && (bindingFlags & QV4::CompiledData::Binding::IsListItem)) {
QString error;
if (pd->propType() == QMetaType::fromType<QQmlScriptString>())
error = tr( "Cannot assign multiple values to a script property");
@@ -280,7 +285,7 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
if (!bindingToDefaultProperty
&& !binding->isGroupProperty()
- && !(binding->flags & QV4::CompiledData::Binding::IsOnAssignment)
+ && !(bindingFlags & QV4::CompiledData::Binding::IsOnAssignment)
&& assigningToGroupProperty) {
QV4::CompiledData::Location loc = binding->valueLocation;
if (loc < (*assignedGroupProperty)->valueLocation)
@@ -291,11 +296,11 @@ QVector<QQmlError> QQmlPropertyValidator::validateObject(
return recordError(loc, tr("Cannot assign a value directly to a grouped property"));
}
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
QQmlError bindingError = validateLiteralBinding(propertyCache, pd, binding);
if (bindingError.isValid())
return recordError(bindingError);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Object) {
QQmlError bindingError = validateObjectBinding(pd, name, binding);
if (bindingError.isValid())
return recordError(bindingError);
@@ -378,7 +383,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
QQmlError noError;
if (property->isEnum()) {
- if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsResolvedEnum))
return noError;
QString value = compilationUnit->bindingValueAsString(binding);
@@ -396,11 +401,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
auto warnOrError = [&](const QString &error) {
- if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Null) {
QQmlError warning;
warning.setUrl(compilationUnit->url());
- warning.setLine(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.line));
- warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(binding->valueLocation.column));
+ warning.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ binding->valueLocation.line()));
+ warning.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ binding->valueLocation.column()));
warning.setDescription(error + tr(" - Assigning null to incompatible properties in QML "
"is deprecated. This will become a compile error in "
"future versions of Qt."));
@@ -410,10 +417,11 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return qQmlCompileError(binding->valueLocation, error);
};
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
const auto isStringBinding = [&]() -> bool {
// validateLiteralBinding is not supposed to be used on scripts
- Q_ASSERT(binding->type != QV4::CompiledData::Binding::Type_Script);
- return binding->type == QV4::CompiledData::Binding::Type_String;
+ Q_ASSERT(bindingType != QV4::CompiledData::Binding::Type_Script);
+ return bindingType == QV4::CompiledData::Binding::Type_String;
};
switch (property->propType().id()) {
@@ -432,19 +440,17 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::QByteArray: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: byte array expected"));
- }
}
break;
case QMetaType::QUrl: {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String)
return warnOrError(tr("Invalid property assignment: url expected"));
- }
}
break;
case QMetaType::UInt: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(uint(d)) == d)
return noError;
@@ -453,7 +459,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Int: {
- if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType == QV4::CompiledData::Binding::Type_Number) {
double d = compilationUnit->bindingValueAsNumber(binding);
if (double(int(d)) == d)
return noError;
@@ -462,13 +468,13 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Float: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
break;
case QMetaType::Double: {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number expected"));
}
}
@@ -566,7 +572,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
}
break;
case QMetaType::Bool: {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: boolean expected"));
}
}
@@ -598,12 +604,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
default: {
// generate single literal value assignment to a list property if required
if (property->propType() == QMetaType::fromType<QList<qreal> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Number) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Number) {
return warnOrError(tr("Invalid property assignment: number or array of numbers expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<int> >()) {
- bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number);
+ bool ok = (bindingType == QV4::CompiledData::Binding::Type_Number);
if (ok) {
double n = compilationUnit->bindingValueAsNumber(binding);
if (double(int(n)) != n)
@@ -613,12 +619,12 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
return warnOrError(tr("Invalid property assignment: int or array of ints expected"));
break;
} else if (property->propType() == QMetaType::fromType<QList<bool> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_Boolean) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Boolean) {
return warnOrError(tr("Invalid property assignment: bool or array of bools expected"));
}
break;
} else if (property->propType() == QMetaType::fromType<QList<QUrl> >()) {
- if (binding->type != QV4::CompiledData::Binding::Type_String) {
+ if (bindingType != QV4::CompiledData::Binding::Type_String) {
return warnOrError(tr("Invalid property assignment: url or array of urls expected"));
}
break;
@@ -632,7 +638,7 @@ QQmlError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache *prope
} else if (property->propType() == QMetaType::fromType<QQmlScriptString>()) {
break;
} else if (property->isQObject()
- && binding->type == QV4::CompiledData::Binding::Type_Null) {
+ && bindingType == QV4::CompiledData::Binding::Type_Null) {
break;
}
@@ -690,8 +696,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
{
QQmlError noError;
- if (binding->flags & QV4::CompiledData::Binding::IsOnAssignment) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Object);
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsOnAssignment)) {
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Object);
bool isValueSource = false;
bool isPropertyInterceptor = false;
@@ -740,7 +746,8 @@ QQmlError QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *propert
}
}
return noError;
- } else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
+ } else if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject)
+ && property->isFunction()) {
return noError;
} else if (isPrimitiveType(propType)) {
auto typeName = QString::fromUtf8(QMetaType(propType).name());
diff --git a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
index be061ba6cd..9ef8360d2d 100644
--- a/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
+++ b/src/qml/qml/qqmlpropertyvalueinterceptor_p.h
@@ -54,6 +54,7 @@
#include <private/qtqmlglobal_p.h>
#include <private/qqmlpropertyindex_p.h>
#include <QtCore/qobject.h>
+#include <QtCore/qproperty.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/qqmlproxymetaobject.cpp b/src/qml/qml/qqmlproxymetaobject.cpp
index 21d3c7ed05..6f48146fa3 100644
--- a/src/qml/qml/qqmlproxymetaobject.cpp
+++ b/src/qml/qml/qqmlproxymetaobject.cpp
@@ -68,11 +68,8 @@ QQmlProxyMetaObject::~QQmlProxyMetaObject()
QObject *QQmlProxyMetaObject::getProxy(int index)
{
if (!proxies) {
- if (!proxies) {
- proxies = new QObject*[metaObjects->count()];
- ::memset(proxies, 0,
- sizeof(QObject *) * metaObjects->count());
- }
+ proxies = new QObject *[metaObjects->count()];
+ ::memset(proxies, 0, sizeof(QObject *) * metaObjects->count());
}
if (!proxies[index]) {
@@ -112,6 +109,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
const int globalPropertyOffset = metaObjects->at(ii).propertyOffset;
if (id >= globalPropertyOffset) {
QObject *proxy = getProxy(ii);
+ Q_ASSERT(proxy);
const int localProxyOffset = proxy->metaObject()->propertyOffset();
const int localProxyId = id - globalPropertyOffset + localProxyOffset;
@@ -129,7 +127,7 @@ int QQmlProxyMetaObject::metaCall(QObject *o, QMetaObject::Call c, int id, void
const int globalMethodOffset = metaObjects->at(ii).methodOffset;
if (id >= globalMethodOffset) {
QObject *proxy = getProxy(ii);
-
+ Q_ASSERT(proxy);
const int localMethodOffset = proxy->metaObject()->methodOffset();
const int localMethodId = id - globalMethodOffset + localMethodOffset;
diff --git a/src/qml/qml/qqmlscriptblob.cpp b/src/qml/qml/qqmlscriptblob.cpp
index 7b7a842d04..9e2b02162f 100644
--- a/src/qml/qml/qqmlscriptblob.cpp
+++ b/src/qml/qml/qqmlscriptblob.cpp
@@ -169,8 +169,8 @@ void QQmlScriptBlob::done()
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -238,8 +238,8 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer<QV4::Exe
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(import->location.line);
- error.setColumn(import->location.column);
+ error.setLine(import->location.line());
+ error.setColumn(import->location.column());
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return;
diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp
index 3230e69b6d..4df3a63785 100644
--- a/src/qml/qml/qqmlscriptstring.cpp
+++ b/src/qml/qml/qqmlscriptstring.cpp
@@ -220,3 +220,5 @@ bool QQmlScriptString::booleanLiteral(bool *ok) const
QT_END_NAMESPACE
+#include "moc_qqmlscriptstring.cpp"
+
diff --git a/src/qml/qml/qqmlscriptstring.h b/src/qml/qml/qqmlscriptstring.h
index a768dabf9f..d2ccfe5bc6 100644
--- a/src/qml/qml/qqmlscriptstring.h
+++ b/src/qml/qml/qqmlscriptstring.h
@@ -86,6 +86,7 @@ private:
friend class QQmlScriptStringPrivate;
friend class QQmlExpression;
friend class QQmlBinding;
+ friend class QQmlPropertyBinding;
friend struct QV4::QObjectWrapper;
};
diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp
index 811ff668c6..c283f7c718 100644
--- a/src/qml/qml/qqmltype.cpp
+++ b/src/qml/qml/qqmltype.cpp
@@ -216,16 +216,15 @@ void QQmlTypePrivate::init() const
return;
}
- auto setupExtendedMetaObject = [&](
- const QMetaObject *extMetaObject,
- QObject *(*extFunc)(QObject *)) {
-
+ auto setupExtendedMetaObject = [&](const QMetaObject *extMetaObject,
+ QObject *(*extFunc)(QObject *)) {
if (!extMetaObject)
return;
// XXX - very inefficient
QMetaObjectBuilder builder;
- QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject);
+ QQmlMetaType::clone(builder, extMetaObject, extMetaObject, extMetaObject,
+ extFunc ? QQmlMetaType::CloneAll : QQmlMetaType::CloneEnumsOnly);
builder.setFlags(MetaObjectFlag::DynamicMetaObject);
QMetaObject *mmo = builder.toMetaObject();
mmo->d.superdata = mo;
diff --git a/src/qml/qml/qqmltypecompiler.cpp b/src/qml/qml/qqmltypecompiler.cpp
index 839d417a56..d72fdb4d5c 100644
--- a/src/qml/qml/qqmltypecompiler.cpp
+++ b/src/qml/qml/qqmltypecompiler.cpp
@@ -151,11 +151,13 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
document->jsModule.fileName = typeData->urlString();
document->jsModule.finalUrl = typeData->finalUrlString();
QmlIR::JSCodeGen v4CodeGenerator(document, engine->v4engine()->illegalNames());
- if (!v4CodeGenerator.generateCodeForComponents(componentRoots())) {
- recordError(v4CodeGenerator.error());
- return nullptr;
+ for (QmlIR::Object *object : qAsConst(document->objects)) {
+ if (!v4CodeGenerator.generateRuntimeFunctions(object)) {
+ Q_ASSERT(v4CodeGenerator.hasError());
+ recordError(v4CodeGenerator.error());
+ return nullptr;
+ }
}
-
document->javaScriptCompilationUnit = v4CodeGenerator.generateCompilationUnit(/*generated unit data*/false);
}
@@ -180,8 +182,8 @@ QQmlRefPointer<QV4::ExecutableCompilationUnit> QQmlTypeCompiler::compile()
void QQmlTypeCompiler::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(location.column()));
error.setDescription(description);
error.setUrl(url());
errors << error;
@@ -340,7 +342,8 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
const QString bindingPropertyName = stringAt(binding->propertyNameIndex);
// Attached property?
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType == QV4::CompiledData::Binding::Type_AttachedProperty) {
const QmlIR::Object *attachedObj = qmlObjects.at(binding->value.objectIndex);
auto *typeRef = resolvedType(binding->propertyNameIndex);
QQmlType type = typeRef ? typeRef->type() : QQmlType();
@@ -373,7 +376,8 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
QQmlPropertyData * const signalPropertyData = resolver.property(signalName, /*notInRevision ptr*/nullptr);
QQmlPropertyData * const qPropertyData = !qPropertyName.isEmpty() ? resolver.property(qPropertyName) : nullptr;
QString finalSignalHandlerPropertyName = signalName;
- uint flags = QV4::CompiledData::Binding::IsSignalHandlerExpression;
+ QV4::CompiledData::Binding::Flag flag
+ = QV4::CompiledData::Binding::IsSignalHandlerExpression;
const bool isPropertyObserver = !signalPropertyData && qPropertyData && qPropertyData->isBindable();
if (signal && !(qPropertyData && qPropertyData->isAlias() && isPropertyObserver)) {
@@ -395,7 +399,7 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
} else if (isPropertyObserver) {
finalSignalHandlerPropertyName = qPropertyName;
- flags = QV4::CompiledData::Binding::IsPropertyObserver;
+ flag = QV4::CompiledData::Binding::IsPropertyObserver;
} else {
if (notInRevision) {
// Try assinging it as a property later
@@ -443,13 +447,13 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
// Binding object to signal means connect the signal to the object's default method.
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- binding->flags |= QV4::CompiledData::Binding::IsSignalHandlerObject;
+ if (bindingType == QV4::CompiledData::Binding::Type_Object) {
+ binding->setFlag(QV4::CompiledData::Binding::IsSignalHandlerObject);
continue;
}
- if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- if (binding->type < QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType != QV4::CompiledData::Binding::Type_Script) {
+ if (bindingType < QV4::CompiledData::Binding::Type_Script) {
COMPILE_EXCEPTION(binding, tr("Cannot assign a value to a signal (expecting a script to be run)"));
} else {
COMPILE_EXCEPTION(binding, tr("Incorrectly specified signal assignment"));
@@ -457,7 +461,7 @@ bool SignalHandlerResolver::resolveSignalHandlerExpressions(const QmlIR::Object
}
binding->propertyNameIndex = compiler->registerString(finalSignalHandlerPropertyName);
- binding->flags |= flags;
+ binding->setFlag(flag);
}
return true;
}
@@ -481,12 +485,13 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
QQmlPropertyResolver resolver(propertyCache);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
continue;
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propertyName = stringAt(binding->propertyNameIndex);
@@ -508,10 +513,10 @@ bool QQmlEnumTypeResolver::resolveEnumBindings()
bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, QStringView, int enumValue, bool)
{
- binding->type = QV4::CompiledData::Binding::Type_Number;
+ binding->setType(QV4::CompiledData::Binding::Type_Number);
binding->value.constantValueIndex = compiler->registerConstant(QV4::Encode((double)enumValue));
// binding->setNumberValueInternal((double)enumValue);
- binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum;
+ binding->setFlag(QV4::CompiledData::Binding::IsResolvedEnum);
return true;
}
@@ -521,14 +526,24 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
if (!prop->isEnum() && !isIntProp)
return true;
- if (!prop->isWritable() && !(binding->flags & QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))
- COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property").arg(stringAt(binding->propertyNameIndex)));
+ if (!prop->isWritable()
+ && !(binding->hasFlag(QV4::CompiledData::Binding::InitializerForReadOnlyDeclaration))) {
+ COMPILE_EXCEPTION(binding, tr("Invalid property assignment: \"%1\" is a read-only property")
+ .arg(stringAt(binding->propertyNameIndex)));
+ }
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
const QString string = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
if (!string.constData()->isUpper())
return true;
+ // reject any "complex" expression (even simple arithmetic)
+ // we do this by excluding everything that is not part of a
+ // valid identifier or a dot
+ for (const QChar c: string)
+ if (!(c.isLetterOrNumber() || c == u'.' || c == u'_' || c.isSpace()))
+ return true;
+
// we support one or two '.' in the enum phrase:
// * <TypeName>.<EnumValue>
// * <TypeName>.<ScopedEnumName>.<EnumValue>
@@ -664,15 +679,21 @@ void QQmlCustomParserScriptIndexer::scanObjectRecursively(int objectIndex, bool
if (!annotateScriptBindings)
annotateScriptBindings = customParsers.contains(obj->inheritedTypeNameIndex);
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Script:
+ if (annotateScriptBindings) {
+ binding->stringIndex = compiler->registerString(
+ compiler->bindingAsString(obj, binding->value.compiledScriptIndex));
+ }
+ break;
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
scanObjectRecursively(binding->value.objectIndex, annotateScriptBindings);
- continue;
- } else if (binding->type != QV4::CompiledData::Binding::Type_Script)
- continue;
- if (!annotateScriptBindings)
- continue;
- const QString script = compiler->bindingAsString(obj, binding->value.compiledScriptIndex);
- binding->stringIndex = compiler->registerString(script);
+ break;
+ default:
+ break;
+ }
}
}
@@ -701,7 +722,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
if (pd && pd->isAlias())
- binding->flags |= QV4::CompiledData::Binding::IsBindingToAlias;
+ binding->setFlag(QV4::CompiledData::Binding::IsBindingToAlias);
}
}
}
@@ -728,7 +749,7 @@ void QQmlScriptStringScanner::scan()
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
bool notInRevision = false;
QQmlPropertyData *pd = binding->propertyNameIndex != quint32(0) ? resolver.property(stringAt(binding->propertyNameIndex), &notInRevision) : defaultProperty;
@@ -774,9 +795,9 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
continue;
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
+ if (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
continue;
const QmlIR::Object *targetObject = qmlObjects->at(binding->value.objectIndex);
@@ -848,7 +869,11 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
QmlIR::Binding *syntheticBinding = pool->New<QmlIR::Binding>();
*syntheticBinding = *binding;
- syntheticBinding->type = QV4::CompiledData::Binding::Type_Object;
+
+ // The synthetic binding inside Component has no name. It's just "Component { Foo {} }".
+ syntheticBinding->propertyNameIndex = 0;
+
+ syntheticBinding->setType(QV4::CompiledData::Binding::Type_Object);
QString error = syntheticComponent->appendBinding(syntheticBinding, /*isListBinding*/false);
Q_ASSERT(error.isEmpty());
Q_UNUSED(error);
@@ -859,7 +884,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
}
}
-// resolve ignores everything relating to inline components
+// Resolve ignores everything relating to inline components, except for implicit components.
bool QQmlComponentAndAliasResolver::resolve(int root)
{
// Detect real Component {} objects as well as implicitly defined components, such as
@@ -870,28 +895,35 @@ bool QQmlComponentAndAliasResolver::resolve(int root)
const int startObjectIndex = root == 0 ? root : root+1; // root+1, as ic root is handled at the end
for (int i = startObjectIndex; i < objCountWithoutSynthesizedComponents; ++i) {
QmlIR::Object *obj = qmlObjects->at(i);
- if (root == 0) {
- // normal component root, skip over anything inline component related
- if (obj->isInlineComponent || obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) {
- continue;
- }
- } else {
- if (!(obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent) ||
- obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot)
- break; // left current inline component (potentially entered a new one)
- }
- QQmlPropertyCache *cache = propertyCaches.at(i);
- if (obj->inheritedTypeNameIndex == 0 && !cache)
- continue;
+ const bool isInlineComponentRoot
+ = obj->flags & QV4::CompiledData::Object::IsInlineComponentRoot;
+ const bool isPartOfInlineComponent
+ = obj->flags & QV4::CompiledData::Object::InPartOfInlineComponent;
+ QQmlPropertyCache *cache = propertyCaches.at(i);
bool isExplicitComponent = false;
-
if (obj->inheritedTypeNameIndex) {
auto *tref = resolvedType(obj->inheritedTypeNameIndex);
Q_ASSERT(tref);
if (tref->type().metaObject() == &QQmlComponent::staticMetaObject)
isExplicitComponent = true;
}
+
+ if (root == 0) {
+ // normal component root, skip over anything inline component related
+ if (isInlineComponentRoot || isPartOfInlineComponent)
+ continue;
+ } else if (!isPartOfInlineComponent || isInlineComponentRoot) {
+ // We've left the current inline component (potentially entered a new one),
+ // but we still need to resolve implicit components which are part of inline components.
+ if (cache && !isExplicitComponent)
+ findAndRegisterImplicitComponents(obj, cache);
+ break;
+ }
+
+ if (obj->inheritedTypeNameIndex == 0 && !cache)
+ continue;
+
if (!isExplicitComponent) {
if (cache)
findAndRegisterImplicitComponents(obj, cache);
@@ -917,7 +949,7 @@ bool QQmlComponentAndAliasResolver::resolve(int root)
COMPILE_EXCEPTION(rootBinding, tr("Component elements may not contain properties other than id"));
}
- if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
+ if (rootBinding->next || rootBinding->type() != QV4::CompiledData::Binding::Type_Object)
COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
// For the root object, we are going to collect ids/aliases and resolve them for as a separate
@@ -985,13 +1017,16 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
return true;
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object
- && binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
- && binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
- continue;
-
- if (!collectIdsAndAliases(binding->value.objectIndex))
- return false;
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ case QV4::CompiledData::Binding::Type_AttachedProperty:
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ if (!collectIdsAndAliases(binding->value.objectIndex))
+ return false;
+ break;
+ default:
+ break;
+ }
}
return true;
@@ -1039,7 +1074,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases(int componentIndex)
if (!atLeastOneAliasResolved && !_objectsWithAliases.isEmpty()) {
const QmlIR::Object *obj = qmlObjects->at(_objectsWithAliases.first());
for (auto alias = obj->aliasesBegin(), end = obj->aliasesEnd(); alias != end; ++alias) {
- if (!(alias->flags & QV4::CompiledData::Alias::Resolved)) {
+ if (!alias->hasFlag(QV4::CompiledData::Alias::Resolved)) {
recordError(alias->location, tr("Circular alias reference detected"));
return false;
}
@@ -1061,7 +1096,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool seenUnresolvedAlias = false;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next) {
- if (alias->flags & QV4::CompiledData::Alias::Resolved)
+ if (alias->hasFlag(QV4::CompiledData::Alias::Resolved))
continue;
seenUnresolvedAlias = true;
@@ -1077,8 +1112,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
Q_ASSERT(targetObject->id >= 0);
- alias->targetObjectId = targetObject->id;
- alias->aliasToLocalAlias = false;
+ alias->setTargetObjectId(targetObject->id);
+ alias->setIsAliasToLocalAlias(false);
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
@@ -1095,7 +1130,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
QQmlPropertyIndex propIdx;
if (property.isEmpty()) {
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
if (!targetCache) {
@@ -1114,7 +1149,7 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
bool aliasPointsToOtherAlias = false;
int localAliasIndex = 0;
for (auto targetAlias = targetObject->aliasesBegin(), end = targetObject->aliasesEnd(); targetAlias != end; ++targetAlias, ++localAliasIndex) {
- if (stringAt(targetAlias->nameIndex) == property) {
+ if (stringAt(targetAlias->nameIndex()) == property) {
aliasPointsToOtherAlias = true;
break;
}
@@ -1122,8 +1157,8 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
if (aliasPointsToOtherAlias) {
if (targetObjectIndex == objectIndex) {
alias->localAliasIndex = localAliasIndex;
- alias->aliasToLocalAlias = true;
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setIsAliasToLocalAlias(true);
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
++numResolvedAliases;
continue;
}
@@ -1185,12 +1220,12 @@ QQmlComponentAndAliasResolver::resolveAliasesInObject(int objectIndex,
}
} else {
if (targetProperty->isQObject())
- alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
+ alias->setFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject);
}
}
alias->encodedMetaPropertyIndex = propIdx.toEncoded();
- alias->flags |= QV4::CompiledData::Alias::Resolved;
+ alias->setFlag(QV4::CompiledData::Alias::Resolved);
numResolvedAliases++;
}
@@ -1226,7 +1261,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
if (obj->flags & QV4::CompiledData::Object::IsComponent && !obj->isInlineComponent) {
Q_ASSERT(obj->bindingCount() == 1);
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
- Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
+ Q_ASSERT(componentBinding->type() == QV4::CompiledData::Binding::Type_Object);
return scanObject(componentBinding->value.objectIndex);
}
@@ -1264,16 +1299,16 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
QString name = stringAt(binding->propertyNameIndex);
if (customParser) {
- if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_AttachedProperty) {
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
continue;
}
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
continue;
}
}
@@ -1292,7 +1327,8 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
bool seenSubObjectWithId = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object
+ && (pd || binding->isAttachedProperty())) {
qSwap(_seenObjectWithId, seenSubObjectWithId);
const bool subObjectValid = scanObject(binding->value.objectIndex);
qSwap(_seenObjectWithId, seenSubObjectWithId);
@@ -1301,22 +1337,24 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
_seenObjectWithId |= seenSubObjectWithId;
}
- if (!seenSubObjectWithId && binding->type != QV4::CompiledData::Binding::Type_GroupProperty
+ if (!seenSubObjectWithId && binding->type()
+ != QV4::CompiledData::Binding::Type_GroupProperty
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
- binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsDeferredBinding);
obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
}
- if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
- || binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject
- || binding->flags & QV4::CompiledData::Binding::IsPropertyObserver)
+ const QV4::CompiledData::Binding::Flags bindingFlags = binding->flags();
+ if (bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerExpression
+ || bindingFlags & QV4::CompiledData::Binding::IsSignalHandlerObject
+ || bindingFlags & QV4::CompiledData::Binding::IsPropertyObserver)
continue;
if (!pd) {
if (customParser) {
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
- binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
+ binding->setFlag(QV4::CompiledData::Binding::IsCustomParserBinding);
}
}
}
diff --git a/src/qml/qml/qqmltypedata.cpp b/src/qml/qml/qqmltypedata.cpp
index 19ef00ecb2..fe9729cf75 100644
--- a/src/qml/qml/qqmltypedata.cpp
+++ b/src/qml/qml/qqmltypedata.cpp
@@ -203,26 +203,20 @@ bool QQmlTypeData::tryLoadFromDiskCache()
Q_ASSERT(errors.size());
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
return false;
}
}
- QQmlType containingType;
- auto containingTypeName = finalUrl().fileName().split(QLatin1Char('.')).first();
- QTypeRevision version;
- QQmlImportNamespace *ns = nullptr;
- m_importCache.resolveType(containingTypeName, &containingType, &version, &ns);
for (auto&& ic: ics) {
QString const nameString = m_compiledData->stringAt(ic.nameIndex);
- QByteArray const name = nameString.toUtf8();
auto importUrl = finalUrl();
importUrl.setFragment(QString::number(ic.objectIndex));
auto import = new QQmlImportInstance();
- m_importCache.addInlineComponentImport(import, nameString, importUrl, containingType);
+ m_importCache.addInlineComponentImport(import, nameString, importUrl, QQmlType());
}
return true;
@@ -334,8 +328,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = script.script->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(script.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(script.location.column()));
error.setDescription(QQmlTypeLoader::tr("Script %1 unavailable").arg(script.script->urlString()));
errors.prepend(error);
setError(errors);
@@ -358,8 +352,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData ? type.typeData->errors() : QList<QQmlError>{};
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 has no inline component type called %2").arg(QStringView{typeName}.left(lastDot), type.type.pendingResolutionName()));
errors.prepend(error);
setError(errors);
@@ -374,8 +368,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
@@ -393,8 +387,8 @@ void QQmlTypeData::done()
QList<QQmlError> errors = type.typeData->errors();
QQmlError error;
error.setUrl(url());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(type.location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(type.location.column()));
error.setDescription(QQmlTypeLoader::tr("Type %1 unavailable").arg(typeName));
errors.prepend(error);
setError(errors);
@@ -701,8 +695,8 @@ void QQmlTypeData::continueLoadFromIR()
// resource file system.
QQmlError error = errors.first();
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column()));
setError(error);
return;
}
@@ -727,8 +721,10 @@ void QQmlTypeData::allDependenciesDone()
QQmlError error;
error.setDescription(QQmlTypeLoader::tr("module \"%1\" is not installed").arg(import->uri));
error.setUrl(m_importCache.baseUrl());
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(import->location.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(import->location.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(
+ import->location.column()));
errors.prepend(error);
}
}
@@ -858,8 +854,8 @@ void QQmlTypeData::resolveTypes()
bool *selfReferenceDetection = unresolvedRef->needsCreation ? nullptr : &ref.selfReference;
- if (!resolveType(name, version, ref, unresolvedRef->location.line,
- unresolvedRef->location.column, reportErrors,
+ if (!resolveType(name, version, ref, unresolvedRef->location.line(),
+ unresolvedRef->location.column(), reportErrors,
QQmlType::AnyRegistrationType, selfReferenceDetection) && reportErrors)
return;
@@ -878,11 +874,9 @@ void QQmlTypeData::resolveTypes()
}
}
}
- ref.version = version;
-
- ref.location.line = unresolvedRef->location.line;
- ref.location.column = unresolvedRef->location.column;
+ ref.version = version;
+ ref.location = unresolvedRef->location;
ref.needsCreation = unresolvedRef->needsCreation;
m_resolvedTypes.insert(unresolvedRef.key(), ref);
}
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 69331a1cd4..d260700930 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -580,9 +580,14 @@ bool QQmlTypeLoader::Blob::addImport(QQmlTypeLoader::Blob::PendingImportPtr impo
scriptImported(blob, import->location, import->qualifier, QString());
} else if (import->type == QV4::CompiledData::Import::ImportLibrary) {
+ const QQmlImportDatabase::LocalQmldirSearchLocation searchMode =
+ QQmlMetaType::isStronglyLockedModule(import->uri, import->version)
+ ? QQmlImportDatabase::QmldirCacheOnly
+ : QQmlImportDatabase::QmldirFileAndCache;
+
const QQmlImportDatabase::LocalQmldirResult qmldirResult
= importDatabase->locateLocalQmldir(
- import->uri, import->version,
+ import->uri, import->version, searchMode,
[&](const QString &qmldirFilePath, const QString &qmldirUrl) {
// This is a local library import
const QTypeRevision actualVersion = m_importCache.addLibraryImport(
@@ -740,8 +745,8 @@ void QQmlTypeLoader::Blob::dependencyComplete(QQmlDataBlob *blob)
QQmlError error(errors.takeFirst());
error.setUrl(m_importCache.baseUrl());
const QV4::CompiledData::Location importLocation = data->importLocation(this);
- error.setLine(qmlConvertSourceCoordinate<quint32, int>(importLocation.line));
- error.setColumn(qmlConvertSourceCoordinate<quint32, int>(importLocation.column));
+ error.setLine(qmlConvertSourceCoordinate<quint32, int>(importLocation.line()));
+ error.setColumn(qmlConvertSourceCoordinate<quint32, int>(importLocation.column()));
errors.prepend(error); // put it back on the list after filling out information.
setError(errors);
}
diff --git a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
index af97643163..bcc5306cf8 100644
--- a/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
+++ b/src/qml/qml/qqmltypeloadernetworkreplyproxy.cpp
@@ -72,3 +72,5 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply)
}
QT_END_NAMESPACE
+
+#include "moc_qqmltypeloadernetworkreplyproxy_p.cpp"
diff --git a/src/qml/qml/qqmltypeloaderqmldircontent_p.h b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
index 55cd846925..41755767ba 100644
--- a/src/qml/qml/qqmltypeloaderqmldircontent_p.h
+++ b/src/qml/qml/qqmltypeloaderqmldircontent_p.h
@@ -84,6 +84,7 @@ public:
QString preferredPath() const { return m_parser.preferredPath(); }
bool designerSupported() const { return m_parser.designerSupported(); }
+ bool hasTypeInfo() const { return !m_parser.typeInfos().isEmpty(); }
private:
QQmlDirParser m_parser;
diff --git a/src/qml/qml/qqmltypemodule.cpp b/src/qml/qml/qqmltypemodule.cpp
index 5120728031..c373a4904e 100644
--- a/src/qml/qml/qqmltypemodule.cpp
+++ b/src/qml/qml/qqmltypemodule.cpp
@@ -87,23 +87,8 @@ void QQmlTypeModule::remove(const QQmlTypePrivate *type)
QQmlMetaType::removeQQmlTypePrivate(elementIt.value(), type);
}
-QQmlType QQmlTypeModule::type(const QHashedStringRef &name, QTypeRevision version) const
+QQmlType QQmlTypeModule::findType(const QList<QQmlTypePrivate *> *types, QTypeRevision version)
{
- QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> *types = m_typeHash.value(name);
- if (types) {
- for (int ii = 0; ii < types->count(); ++ii)
- if (types->at(ii)->version.minorVersion() <= version.minorVersion())
- return QQmlType(types->at(ii));
- }
-
- return QQmlType();
-}
-
-QQmlType QQmlTypeModule::type(const QV4::String *name, QTypeRevision version) const
-{
- QMutexLocker lock(&m_mutex);
- QList<QQmlTypePrivate *> *types = m_typeHash.value(name);
if (types) {
for (int ii = 0; ii < types->count(); ++ii)
if (types->at(ii)->version.minorVersion() <= version.minorVersion())
diff --git a/src/qml/qml/qqmltypemodule_p.h b/src/qml/qml/qqmltypemodule_p.h
index 0ba6245cbb..37b9a32b90 100644
--- a/src/qml/qml/qqmltypemodule_p.h
+++ b/src/qml/qml/qqmltypemodule_p.h
@@ -53,6 +53,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtQml/private/qstringhash_p.h>
+#include <QtQml/private/qqmltype_p.h>
#include <QtCore/qmutex.h>
#include <QtCore/qstring.h>
#include <QtCore/qversionnumber.h>
@@ -72,6 +73,12 @@ struct String;
class QQmlTypeModule
{
public:
+ enum class LockLevel {
+ Open = 0,
+ Weak = 1,
+ Strong = 2
+ };
+
QQmlTypeModule() = default;
QQmlTypeModule(const QString &uri, quint8 majorVersion)
: m_module(uri), m_majorVersion(majorVersion)
@@ -80,8 +87,17 @@ public:
void add(QQmlTypePrivate *);
void remove(const QQmlTypePrivate *type);
- bool isLocked() const { return m_locked.loadRelaxed() != 0; }
- void lock() { m_locked.storeRelaxed(1); }
+ LockLevel lockLevel() const { return LockLevel(m_lockLevel.loadRelaxed()); }
+ bool setLockLevel(LockLevel mode)
+ {
+ while (true) {
+ const int currentLock = m_lockLevel.loadAcquire();
+ if (currentLock > int(mode))
+ return false;
+ if (currentLock == int(mode) || m_lockLevel.testAndSetRelease(currentLock, int(mode)))
+ return true;
+ }
+ }
QString module() const
{
@@ -99,12 +115,24 @@ public:
quint8 minimumMinorVersion() const { return m_minMinorVersion.loadRelaxed(); }
quint8 maximumMinorVersion() const { return m_maxMinorVersion.loadRelaxed(); }
- QQmlType type(const QHashedStringRef &, QTypeRevision version) const;
- QQmlType type(const QV4::String *, QTypeRevision version) const;
+ QQmlType type(const QHashedStringRef &name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
+
+ QQmlType type(const QV4::String *name, QTypeRevision version) const
+ {
+ QMutexLocker lock(&m_mutex);
+ return findType(m_typeHash.value(name), version);
+ }
void walkCompositeSingletons(const std::function<void(const QQmlType &)> &callback) const;
private:
+ static Q_QML_PRIVATE_EXPORT QQmlType findType(
+ const QList<QQmlTypePrivate *> *types, QTypeRevision version);
+
const QString m_module;
const quint8 m_majorVersion = 0;
@@ -114,8 +142,8 @@ private:
// Can only ever increase
QAtomicInt m_maxMinorVersion = 0;
- // Bool. Can only be set to 1 once.
- QAtomicInt m_locked = 0;
+ // LockLevel. Can only be increased.
+ QAtomicInt m_lockLevel = int(LockLevel::Open);
using TypeHash = QStringHash<QList<QQmlTypePrivate *>>;
TypeHash m_typeHash;
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 45333668e3..0f23b3190e 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -86,119 +86,5 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
m_namedImports.insert(name, import);
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(name, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
- const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- Result result = typeSearch(importNamespace->modules, name);
-
- if (!result.isValid())
- result = query(importNamespace->compositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name.toString();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, QQmlImport::RecursionRestriction recursionRestriction) const
-{
- Result result = query(m_namedImports, name);
-
- if (!result.isValid())
- result = typeSearch(m_anonymousImports, name);
-
- if (!result.isValid())
- result = query(m_anonymousCompositeSingletons, name);
-
- if (!result.isValid()) {
- // Look up anonymous types from the imports of this document
- QString typeName = name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeRecursionDetected = false;
- bool typeFound = m_imports.resolveType(typeName, &t, nullptr, &typeNamespace, &errors,
- QQmlType::AnyRegistrationType,
- recursionRestriction == QQmlImport::AllowRecursion ? &typeRecursionDetected : nullptr);
- if (typeFound) {
- return Result(t);
- }
-
- }
-
- return result;
-}
-
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const QQmlImportRef *importNamespace) const
-{
- Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
-
- QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it = m_namespacedImports.constFind(importNamespace);
- if (it != m_namespacedImports.constEnd()) {
- Result r = query(*it, name);
- if (r.isValid())
- return r;
- }
-
- Result r = typeSearch(importNamespace->modules, name);
-
- if (!r.isValid())
- r = query(importNamespace->compositeSingletons, name);
-
- if (!r.isValid()) {
- // Look up types from the imports of this document
- // ### it would be nice if QQmlImports allowed us to resolve a namespace
- // first, and then types on it.
- QString qualifiedTypeName = importNamespace->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
- QQmlImportNamespace *typeNamespace = nullptr;
- QList<QQmlError> errors;
- QQmlType t;
- bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
- if (typeFound) {
- return Result(t);
- }
- }
-
- return r;
-}
-
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 974f99ecae..5e1a88b2a5 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -104,16 +104,131 @@ public:
const QQmlImportRef *importNamespace;
int scriptIndex;
};
- Result query(const QHashedStringRef &) const;
- Result query(const QHashedStringRef &, const QQmlImportRef *importNamespace) const;
- Result query(const QV4::String *, QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion) const;
- Result query(const QV4::String *, const QQmlImportRef *importNamespace) const;
+
+ enum class QueryNamespaced { No, Yes };
+
+ // Restrict the types allowed for key. We don't want QV4::ScopedString, for example.
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QHashedStringRef &key) const
+ {
+ return doQuery<const QHashedStringRef &, recursionRestriction>(key);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QHashedStringRef &key, const QQmlImportRef *importNamespace) const
+ {
+ return doQuery<const QHashedStringRef &, queryNamespaced>(key, importNamespace);
+ }
+
+ template<QQmlImport::RecursionRestriction recursionRestriction = QQmlImport::PreventRecursion>
+ Result query(const QV4::String *key) const
+ {
+ return doQuery<const QV4::String *, recursionRestriction>(key);
+ }
+
+ template<QueryNamespaced queryNamespaced = QueryNamespaced::Yes>
+ Result query(const QV4::String *key, const QQmlImportRef *importNamespace) const
+ {
+ return doQuery<const QV4::String *, queryNamespaced>(key, importNamespace);
+ }
private:
friend class QQmlImports;
+ static QHashedStringRef toHashedStringRef(const QHashedStringRef &key) { return key; }
+ static QHashedStringRef toHashedStringRef(const QV4::String *key)
+ {
+ const QV4::Heap::String *heapString = key->d();
+
+ // toQString() would also do simplifyString(). Therefore, we can be sure that this
+ // is safe. Any other operation on the string data cannot keep references on the
+ // non-simplified pieces.
+ if (heapString->subtype >= QV4::Heap::String::StringType_Complex)
+ heapString->simplifyString();
+
+ // This is safe because the string data is backed by the QV4::String we got as
+ // parameter. The contract about passing V4 values as parameters is that you have to
+ // scope them first, so that they don't get gc'd while the callee is working on them.
+ const QStringPrivate &text = heapString->text();
+ return QHashedStringRef(QStringView(text.ptr, text.size));
+ }
+
+ static QString toQString(const QHashedStringRef &key) { return key.toString(); }
+ static QString toQString(const QV4::String *key) { return key->toQStringNoThrow(); }
+
+ template<typename Key, QQmlImport::RecursionRestriction recursionRestriction>
+ Result doQuery(Key name) const
+ {
+ Result result = doQuery(m_namedImports, name);
+
+ if (!result.isValid())
+ result = typeSearch(m_anonymousImports, name);
+
+ if (!result.isValid())
+ result = doQuery(m_anonymousCompositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeRecursionDetected = false;
+ const bool typeFound = m_imports.resolveType(
+ toHashedStringRef(name), &t, nullptr, &typeNamespace, &errors,
+ QQmlType::AnyRegistrationType,
+ recursionRestriction == QQmlImport::AllowRecursion
+ ? &typeRecursionDetected
+ : nullptr);
+ if (typeFound)
+ return Result(t);
+
+ }
+
+ return result;
+ }
+
+ template<typename Key, QueryNamespaced queryNamespaced>
+ Result doQuery(Key name, const QQmlImportRef *importNamespace) const
+ {
+ Q_ASSERT(importNamespace && importNamespace->scriptIndex == -1);
+
+ if constexpr (queryNamespaced == QueryNamespaced::Yes) {
+ QMap<const QQmlImportRef *, QStringHash<QQmlImportRef> >::const_iterator it
+ = m_namespacedImports.constFind(importNamespace);
+ if (it != m_namespacedImports.constEnd()) {
+ Result r = doQuery(*it, name);
+ if (r.isValid())
+ return r;
+ }
+ }
+
+ Result result = typeSearch(importNamespace->modules, name);
+
+ if (!result.isValid())
+ result = doQuery(importNamespace->compositeSingletons, name);
+
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ const QString qualifiedTypeName = importNamespace->m_qualifier + u'.' + toQString(name);
+ QQmlImportNamespace *typeNamespace = nullptr;
+ QList<QQmlError> errors;
+ QQmlType t;
+ bool typeFound = m_imports.resolveType(
+ qualifiedTypeName, &t, nullptr, &typeNamespace, &errors);
+ if (typeFound)
+ return Result(t);
+ }
+
+ return result;
+ }
+
template<typename Key>
- Result query(const QStringHash<QQmlImportRef> &imports, Key key) const
+ Result doQuery(const QStringHash<QQmlImportRef> &imports, Key key) const
{
QQmlImportRef *i = imports.value(key);
if (i) {
@@ -129,7 +244,7 @@ private:
}
template<typename Key>
- Result query(const QStringHash<QUrl> &urls, Key key) const
+ Result doQuery(const QStringHash<QUrl> &urls, Key key) const
{
QUrl *url = urls.value(key);
if (url) {
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
index c4d2d82a50..0580af56f0 100644
--- a/src/qml/qml/qqmltypewrapper.cpp
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -111,11 +111,14 @@ QObject* QQmlTypeWrapper::singletonObject() const
QVariant QQmlTypeWrapper::toVariant() const
{
- if (!isSingleton())
- return QVariant::fromValue<QObject *>(d()->object);
-
QQmlEnginePrivate *e = QQmlEnginePrivate::get(engine()->qmlEngine());
const QQmlType type = d()->type();
+
+ if (!isSingleton()) {
+ return QVariant::fromValue(qmlAttachedPropertiesObject(
+ d()->object, type.attachedPropertiesFunction(e)));
+ }
+
if (type.isQJSValueSingleton())
return QVariant::fromValue<QJSValue>(e->singletonInstance<QJSValue>(type));
@@ -411,8 +414,10 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const
return Encode(false);
QQmlRefPointer<QQmlTypeData> td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl());
- ExecutableCompilationUnit *cu = td->compilationUnit();
- myQmlType = qenginepriv->metaObjectForType(cu->typeIds.id.id());
+ if (ExecutableCompilationUnit *cu = td->compilationUnit())
+ myQmlType = qenginepriv->metaObjectForType(cu->typeIds.id.id());
+ else
+ return Encode(false); // It seems myQmlType has some errors, so we could not compile it.
} else {
myQmlType = qenginepriv->metaObjectForType(myTypeId.id());
}
@@ -450,11 +455,8 @@ ReturnedValue QQmlTypeWrapper::virtualResolveLookupGetter(const Object *object,
QQmlPropertyData *property = ddata->propertyCache->property(name.getPointer(), qobjectSingleton, qmlContext);
if (property) {
ScopedValue val(scope, Value::fromReturnedValue(QV4::QObjectWrapper::wrap(engine, qobjectSingleton)));
- lookup->qobjectLookup.qmlTypeIc = This->internalClass();
- lookup->qobjectLookup.ic = val->objectValue()->internalClass();
- lookup->qobjectLookup.propertyCache = ddata->propertyCache;
- lookup->qobjectLookup.propertyCache->addref();
- lookup->qobjectLookup.propertyData = property;
+ setupQObjectLookup(lookup, ddata, property,
+ val->objectValue(), This);
lookup->getter = QQmlTypeWrapper::lookupSingletonProperty;
return lookup->getter(lookup, engine, *object);
}
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index c2bbd7f498..2cba0375e7 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -281,10 +281,27 @@ PropertyAttributes QQmlValueTypeWrapper::virtualGetOwnProperty(const Managed *m,
{
if (id.isString()) {
const QQmlValueTypeWrapper *r = static_cast<const QQmlValueTypeWrapper *>(m);
- QQmlPropertyData result = r->dataForPropertyKey(id);
- if (p && result.isValid())
- p->value = getGadgetProperty(r->engine(), r->d(), result.propType(), result.coreIndex(), result.isFunction(), result.isEnum());
- return result.isValid() ? Attr_Data : Attr_Invalid;
+ Q_ASSERT(r);
+
+ const QQmlPropertyData result = r->dataForPropertyKey(id);
+ if (!result.isValid())
+ return Attr_Invalid; // Property doesn't exist. Object shouldn't meddle with it.
+
+ if (!p)
+ return Attr_Data; // Property exists, but we're not interested in the value
+
+ const QQmlValueTypeReference *ref = r->as<const QQmlValueTypeReference>();
+ if (!ref || ref->readReferenceValue()) {
+ // Property exists, and we can retrieve it
+ p->value = getGadgetProperty(
+ r->engine(), r->d(), result.propType(), result.coreIndex(),
+ result.isFunction(), result.isEnum());
+ } else {
+ // Property exists, but we can't retrieve it. Make it undefined.
+ p->value = Encode::undefined();
+ }
+
+ return Attr_Data;
}
return QV4::Object::virtualGetOwnProperty(m, id, p);
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index e7248b038a..b6f68536ca 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -236,17 +236,18 @@ void QQmlVMEMetaObjectEndpoint::tryConnect()
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
if (!aliasData->isObjectAlias()) {
QQmlRefPointer<QQmlContextData> ctxt = metaObject->ctxt;
- QObject *target = ctxt->idValue(aliasData->targetObjectId);
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return;
- QQmlData *targetDData = QQmlData::get(target, /*create*/false);
- if (!targetDData)
- return;
QQmlPropertyIndex encodedIndex = QQmlPropertyIndex::fromEncoded(aliasData->encodedMetaPropertyIndex);
int coreIndex = encodedIndex.coreIndex();
int valueTypeIndex = encodedIndex.valueTypeIndex();
- const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
+ QJSEngine *engine = qjsEngine(target);
+ if (!engine)
+ return; // dont crash
+ const QQmlPropertyData *pd =
+ QQmlData::ensurePropertyCache(engine, target)->property(coreIndex);
if (pd && valueTypeIndex != -1 && !QQmlMetaType::valueType(pd->propType())) {
// deep alias
QQmlEnginePrivate *enginePriv = QQmlEnginePrivate::get(metaObject->compilationUnit->engine->qmlEngine());
@@ -767,7 +768,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
}
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
+ if (property.isList()) {
// when reading from the list, we need to find the correct MetaObject,
// namely this. However, obejct->metaObject might point to any MetaObject
// down the inheritance hierarchy, so we need to store how far we have
@@ -872,7 +873,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
break;
case QV4::CompiledData::BuiltinType::InvalidBuiltin:
- if (property.isList) {
+ if (property.isList()) {
// Writing such a property is not supported. Content is added through the list property
// methods.
} else {
@@ -894,16 +895,18 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id < aliasCount) {
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
- if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
- *reinterpret_cast<void **>(a[0]) = nullptr;
+ if (aliasData->hasFlag(QV4::CompiledData::Alias::AliasPointsToPointerObject)
+ && c == QMetaObject::ReadProperty){
+ *reinterpret_cast<void **>(a[0]) = nullptr;
+ }
if (ctxt.isNull())
return -1;
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- QObject *target = ctxt->idValue(aliasData->targetObjectId);
+ QObject *target = ctxt->idValue(aliasData->targetObjectId());
if (!target)
return -1;
@@ -1006,7 +1009,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
auto arguments = methodData->hasArguments() ? methodData->arguments() : nullptr;
if (arguments && arguments->names) {
- const auto parameterCount = arguments->names->count();
+ const quint32 parameterCount = arguments->names->count();
Q_ASSERT(parameterCount == function->formalParameterCount());
if (void *result = a[0])
arguments->types[0].destruct(result);
@@ -1250,9 +1253,9 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
- while (aliasData->aliasToLocalAlias)
+ while (aliasData->isAliasToLocalAlias())
aliasData = &compiledObject->aliasTable()[aliasData->localAliasIndex];
- *target = ctxt->idValue(aliasData->targetObjectId);
+ *target = ctxt->idValue(aliasData->targetObjectId());
if (!*target)
return false;
@@ -1280,7 +1283,7 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
- endpoint->connect(ctxt->idValueBindings(aliasData->targetObjectId));
+ endpoint->connect(ctxt->idValueBindings(aliasData->targetObjectId()));
endpoint->tryConnect();
}
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index f15c3aa201..46dc108b9e 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -375,26 +375,10 @@ QVariant QtObject::quaternion(double scalar, double x, double y, double z) const
}
/*!
- \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
-
- Returns a matrix4x4 with the specified values.
-
- The arguments correspond to their positions in the matrix:
+ \qmlmethod matrix4x4 Qt::matrix4x4()
- \table
- \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
- \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
- \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
- \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
- \endtable
-
- Alternatively, the function may be called with a single argument
- where that argument is a JavaScript array which contains the sixteen
- matrix values.
-
- Finally, the function may be called with no arguments and the resulting
- matrix will be the identity matrix.
-*/
+ Returns an identity matrix4x4.
+ */
QVariant QtObject::matrix4x4() const
{
QVariant variant;
@@ -402,6 +386,21 @@ QVariant QtObject::matrix4x4() const
return variant;
}
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(var values)
+
+ Returns a matrix4x4 with the specified \a values. \a values is expected to
+ be a JavaScript array with 16 entries.
+
+ The array indices correspond to positions in the matrix as follows:
+
+ \table
+ \row \li 0 \li 1 \li 2 \li 3
+ \row \li 4 \li 5 \li 6 \li 7
+ \row \li 8 \li 9 \li 10 \li 11
+ \row \li 12 \li 13 \li 14 \li 15
+ \endtable
+*/
QVariant QtObject::matrix4x4(const QJSValue &value) const
{
if (value.isObject()) {
@@ -415,6 +414,20 @@ QVariant QtObject::matrix4x4(const QJSValue &value) const
return QVariant();
}
+/*!
+ \qmlmethod matrix4x4 Qt::matrix4x4(real m11, real m12, real m13, real m14, real m21, real m22, real m23, real m24, real m31, real m32, real m33, real m34, real m41, real m42, real m43, real m44)
+
+ Returns a matrix4x4 with the specified values.
+
+ The arguments correspond to their positions in the matrix:
+
+ \table
+ \row \li \a m11 \li \a m12 \li \a m13 \li \a m14
+ \row \li \a m21 \li \a m22 \li \a m23 \li \a m24
+ \row \li \a m31 \li \a m32 \li \a m33 \li \a m34
+ \row \li \a m41 \li \a m42 \li \a m43 \li \a m44
+ \endtable
+*/
QVariant QtObject::matrix4x4(double m11, double m12, double m13, double m14,
double m21, double m22, double m23, double m24,
double m31, double m32, double m33, double m34,
@@ -811,9 +824,30 @@ bool QtObject::openUrlExternally(const QUrl &url) const
}
/*!
+ \qmlmethod url Qt::url(url url)
+
+ Returns \a url verbatim. This can be used to force a type coercion to \c url.
+ In contrast to Qt.resolvedUrl() this retains any relative URLs. As strings
+ are implicitly converted to urls, the function can be called with a string
+ as argument, and will then return a url.
+
+ \sa resolvedUrl()
+*/
+QUrl QtObject::url(const QUrl &url) const
+{
+ return url;
+}
+
+/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
+
+ If there is no caller or the caller is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If the QML
+ engine has no base URL, just returns \a url.
+
+ \sa url()
*/
QUrl QtObject::resolvedUrl(const QUrl &url) const
{
@@ -825,6 +859,29 @@ QUrl QtObject::resolvedUrl(const QUrl &url) const
}
/*!
+ \qmlmethod url Qt::resolvedUrl(url url, object context)
+
+ Returns \a url resolved relative to the URL of the QML context of
+ \a context. If \a context is not associated with a QML context,
+ returns \a url resolved relative to the QML engine's base URL. If
+ the QML engine has no base URL, just returns \a url.
+
+ \sa url()
+*/
+QUrl QtObject::resolvedUrl(const QUrl &url, QObject *context) const
+{
+ if (context) {
+ QQmlData *data = QQmlData::get(context);
+ if (data && data->outerContext)
+ return data->outerContext->resolvedUrl(url);
+ }
+
+ if (QQmlEngine *engine = qmlEngine())
+ return engine->baseUrl().resolved(url);
+ return url;
+}
+
+/*!
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
@@ -1031,7 +1088,7 @@ QObject *QtObject::createQmlObject(const QString &qml, QObject *parent, const QU
}
/*!
-\qmlmethod object Qt::createComponent(url, mode, parent)
+\qmlmethod Component Qt::createComponent(url url, enumeration mode, QtObject parent)
Returns a \l Component object created using the QML file at the specified \a url,
or \c null if an empty string was given.
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index 972a0d0b31..7f40a34ddd 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -144,7 +144,9 @@ public:
Q_INVOKABLE QLocale locale(const QString &name) const;
#endif
+ Q_INVOKABLE QUrl url(const QUrl &url) const;
Q_INVOKABLE QUrl resolvedUrl(const QUrl &url) const;
+ Q_INVOKABLE QUrl resolvedUrl(const QUrl &url, QObject *context) const;
Q_INVOKABLE bool openUrlExternally(const QUrl &url) const;
Q_INVOKABLE QVariant font(const QJSValue &fontSpecifier) const;
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 1dbf35f1d3..ae6edde3c0 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -85,6 +85,7 @@ void QQmlDirParser::clear()
_designerSupported = false;
_typeInfos.clear();
_classNames.clear();
+ _linkTarget.clear();
}
inline static void scanSpace(const QChar *&ch) {
@@ -321,6 +322,24 @@ bool QQmlDirParser::parse(const QString &source)
}
_preferredPath = sections[1];
+ } else if (sections[0] == QLatin1String("linktarget")) {
+ if (sectionCount < 2) {
+ reportError(lineNumber, 0,
+ QStringLiteral("linktarget directive requires an argument, "
+ "but %1 were provided")
+ .arg(sectionCount - 1));
+ continue;
+ }
+
+ if (!_linkTarget.isEmpty()) {
+ reportError(
+ lineNumber, 0,
+ QStringLiteral(
+ "only one linktarget directive may be defined in a qmldir file"));
+ continue;
+ }
+
+ _linkTarget = sections[1];
} else if (sectionCount == 2) {
// No version specified (should only be used for relative qmldir files)
const Component entry(sections[0], sections[1], QTypeRevision());
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index eabaceae91..22073d26c5 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -161,6 +161,7 @@ public:
QStringList typeInfos() const;
QStringList classNames() const;
QString preferredPath() const;
+ QString linkTarget() const { return _linkTarget; }
private:
bool maybeAddComponent(const QString &typeName, const QString &fileName, const QString &version, QHash<QString,Component> &hash, int lineNumber = -1, bool multi = true);
@@ -178,6 +179,7 @@ private:
bool _designerSupported = false;
QStringList _typeInfos;
QStringList _classNames;
+ QString _linkTarget;
};
using QQmlDirComponents = QMultiHash<QString,QQmlDirParser::Component>;
diff --git a/src/qml/qmldirparser/qqmlimportresolver_p.h b/src/qml/qmldirparser/qqmlimportresolver_p.h
index c2f49ee4ec..743e9f5526 100644
--- a/src/qml/qmldirparser/qqmlimportresolver_p.h
+++ b/src/qml/qmldirparser/qqmlimportresolver_p.h
@@ -51,13 +51,15 @@
// We mean it.
//
+#include <private/qtqmlcompilerglobal_p.h>
+
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qversionnumber.h>
QT_BEGIN_NAMESPACE
-QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
+Q_QMLCOMPILER_PRIVATE_EXPORT QStringList qQmlResolveImportPaths(QStringView uri, const QStringList &basePaths,
QTypeRevision version);
QT_END_NAMESPACE
diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp
index 8e74711776..17e3e88f9b 100644
--- a/src/qml/types/qqmlbind.cpp
+++ b/src/qml/types/qqmlbind.cpp
@@ -368,12 +368,8 @@ void QQmlBind::setDelayed(bool delayed)
The default value is \c Binding.RestoreBindingOrValue.
- If you rely on any specific behavior regarding the restoration of plain
- values when bindings get disabled you should migrate to explicitly set the
- restoreMode.
-
- Reliance on a restoreMode that doesn't restore the previous binding or value
- for a specific property results in a run-time warning.
+ \note This property exists for backwards compatibility with earlier versions
+ of Qt. Don't use it in new code.
*/
QQmlBind::RestorationMode QQmlBind::restoreMode() const
{
diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp
index 7767909169..70e048b0ea 100644
--- a/src/qml/types/qqmlconnections.cpp
+++ b/src/qml/types/qqmlconnections.cpp
@@ -60,15 +60,13 @@ Q_LOGGING_CATEGORY(lcQmlConnections, "qt.qml.connections")
class QQmlConnectionsPrivate : public QObjectPrivate
{
public:
- QQmlConnectionsPrivate() : target(nullptr), enabled(true), targetSet(false), ignoreUnknownSignals(false), componentcomplete(true) {}
-
QList<QQmlBoundSignal*> boundsignals;
- QObject *target;
+ QQmlGuard<QObject> target;
- bool enabled;
- bool targetSet;
- bool ignoreUnknownSignals;
- bool componentcomplete;
+ bool enabled = true;
+ bool targetSet = false;
+ bool ignoreUnknownSignals = false;
+ bool componentcomplete = true;
QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
QList<const QV4::CompiledData::Binding *> bindings;
@@ -130,6 +128,12 @@ public:
}
\endqml
+ \note For backwards compatibility you can also specify the signal handlers
+ without \c{function}, like you would specify them directly in the target
+ object. This is not recommended. If you specify one signal handler this way,
+ then all signal handlers specified as \c{function} in the same Connections
+ object are ignored.
+
\sa {Qt QML}
*/
QQmlConnections::QQmlConnections(QObject *parent) :
@@ -153,7 +157,7 @@ QQmlConnections::~QQmlConnections()
QObject *QQmlConnections::target() const
{
Q_D(const QQmlConnections);
- return d->targetSet ? d->target : parent();
+ return d->targetSet ? d->target.data() : parent();
}
class QQmlBoundSignalDeleter : public QObject
@@ -248,17 +252,20 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableC
return;
}
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script)
+ continue;
+
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const QV4::CompiledData::Object *target = compilationUnit->objectAt(binding->value.objectIndex);
if (!compilationUnit->stringAt(target->inheritedTypeNameIndex).isEmpty())
error(binding, QQmlConnections::tr("Connections: nested objects not allowed"));
else
error(binding, QQmlConnections::tr("Connections: syntax error"));
return;
- } if (binding->type != QV4::CompiledData::Binding::Type_Script) {
- error(binding, QQmlConnections::tr("Connections: script expected"));
- return;
}
+
+ error(binding, QQmlConnections::tr("Connections: script expected"));
+ return;
}
}
@@ -353,7 +360,7 @@ void QQmlConnections::connectSignalsToBindings()
QQmlRefPointer<QQmlContextData> ctxtdata = ddata ? ddata->outerContext : nullptr;
for (const QV4::CompiledData::Binding *binding : qAsConst(d->bindings)) {
- Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
+ Q_ASSERT(binding->type() == QV4::CompiledData::Binding::Type_Script);
QString propName = d->compilationUnit->stringAt(binding->propertyNameIndex);
QQmlProperty prop(target, propName);
diff --git a/src/qml/util/qqmlpropertymap.cpp b/src/qml/util/qqmlpropertymap.cpp
index 2bf8ab0190..23bf1b307c 100644
--- a/src/qml/util/qqmlpropertymap.cpp
+++ b/src/qml/util/qqmlpropertymap.cpp
@@ -409,3 +409,5 @@ QQmlPropertyMap::QQmlPropertyMap(const QMetaObject *staticMetaObject, QObject *p
*/
QT_END_NAMESPACE
+
+#include "moc_qqmlpropertymap.cpp"
diff --git a/src/qmlcompiler/CMakeLists.txt b/src/qmlcompiler/CMakeLists.txt
index 311652cca7..45a66bab33 100644
--- a/src/qmlcompiler/CMakeLists.txt
+++ b/src/qmlcompiler/CMakeLists.txt
@@ -1,9 +1,3 @@
-# Generated from qmlcompiler.pro.
-
-#####################################################################
-## QmlCompilerPrivate Module:
-#####################################################################
-
qt_internal_add_module(QmlCompilerPrivate
STATIC
INTERNAL_MODULE
@@ -18,6 +12,7 @@ qt_internal_add_module(QmlCompilerPrivate
qqmljsmetatypes_p.h
qqmljsresourcefilemapper.cpp qqmljsresourcefilemapper_p.h
qqmljsscope.cpp qqmljsscope_p.h
+ qqmljsscopesbyid_p.h
qqmljsstreamwriter.cpp qqmljsstreamwriter_p.h
qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h
qqmljstypereader.cpp qqmljstypereader_p.h
@@ -25,8 +20,19 @@ qt_internal_add_module(QmlCompilerPrivate
qqmljsannotation_p.h qqmljsannotation.cpp
PUBLIC_LIBRARIES
Qt::CorePrivate
- Qt::QmlDevToolsPrivate
)
-#### Keys ignored in scope 1:.:.:qmlcompiler.pro:<TRUE>:
-# _OPTION = "host_build"
+qt_internal_add_resource(QmlCompilerPrivate "builtins"
+ PREFIX
+ "/qt-project.org/qml/builtins"
+ BASE
+ "${CMAKE_CURRENT_SOURCE_DIR}/../imports/builtins/"
+ FILES
+ "${CMAKE_CURRENT_SOURCE_DIR}/../imports/builtins/builtins.qmltypes"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../imports/builtins/jsroot.qmltypes"
+)
+
+add_dependencies(QmlCompilerPrivate QmlDevToolsPrivate)
+get_target_property(devtools_includes QmlDevToolsPrivate EXTRA_INCLUDE_DIRECTORIES)
+target_include_directories(QmlCompilerPrivate PUBLIC ${devtools_includes})
+target_compile_definitions(QmlCompilerPrivate PUBLIC QT_QMLDEVTOOLS_LIB)
diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h
index 503b205d6a..125c24c3d0 100644
--- a/src/qmlcompiler/qdeferredpointer_p.h
+++ b/src/qmlcompiler/qdeferredpointer_p.h
@@ -45,15 +45,24 @@
QT_BEGIN_NAMESPACE
template<typename T>
+class QDeferredSharedPointer;
+
+template<typename T>
+class QDeferredWeakPointer;
+
+template<typename T>
class QDeferredFactory
{
public:
- T create() const;
bool isValid() const;
-};
-template<typename T>
-class QDeferredWeakPointer;
+private:
+ friend class QDeferredSharedPointer<const T>;
+ friend class QDeferredWeakPointer<const T>;
+ friend class QDeferredSharedPointer<T>;
+ friend class QDeferredWeakPointer<T>;
+ void populate(const QSharedPointer<T> &) const;
+};
template<typename T>
class QDeferredSharedPointer
@@ -101,14 +110,14 @@ public:
friend size_t qHash(const QDeferredSharedPointer &ptr, size_t seed = 0)
{
ptr.lazyLoad();
- return qHashMulti(seed, ptr.m_factory, ptr.m_data);
+ return qHashMulti(seed, ptr.m_data);
}
friend bool operator==(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
{
a.lazyLoad();
b.lazyLoad();
- return a.m_factory == b.m_factory && a.m_data == b.m_data;
+ return a.m_data == b.m_data;
}
friend bool operator!=(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b)
@@ -116,6 +125,31 @@ public:
return !(a == b);
}
+ template <typename U>
+ friend bool operator==(const QDeferredSharedPointer &a, const QSharedPointer<U> &b)
+ {
+ a.lazyLoad();
+ return a.m_data == b;
+ }
+
+ template <typename U>
+ friend bool operator!=(const QDeferredSharedPointer &a, const QSharedPointer<U> &b)
+ {
+ return !(a == b);
+ }
+
+ template <typename U>
+ friend bool operator==(const QSharedPointer<U> &a, const QDeferredSharedPointer &b)
+ {
+ return b == a;
+ }
+
+ template <typename U>
+ friend bool operator!=(const QSharedPointer<U> &a, const QDeferredSharedPointer &b)
+ {
+ return b != a;
+ }
+
private:
friend class QDeferredWeakPointer<T>;
@@ -124,7 +158,7 @@ private:
if (m_factory && m_factory->isValid()) {
Factory localFactory;
std::swap(localFactory, *m_factory); // Swap before executing, to avoid recursion
- const_cast<std::remove_const_t<T> &>(*m_data) = localFactory.create();
+ localFactory.populate(m_data.template constCast<std::remove_const_t<T>>());
}
}
@@ -181,14 +215,14 @@ public:
friend size_t qHash(const QDeferredWeakPointer &ptr, size_t seed = 0)
{
ptr.lazyLoad();
- return qHashMulti(seed, ptr.m_factory, ptr.m_data);
+ return qHashMulti(seed, ptr.m_data);
}
friend bool operator==(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
{
a.lazyLoad();
b.lazyLoad();
- return a.m_factory == b.m_factory && a.m_data == b.m_data;
+ return a.m_data == b.m_data;
}
friend bool operator!=(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b)
@@ -204,8 +238,8 @@ private:
if (factory->isValid()) {
Factory localFactory;
std::swap(localFactory, *factory); // Swap before executing, to avoid recursion
- const_cast<std::remove_const_t<T> &>(*(m_data.toStrongRef()))
- = localFactory.create();
+ localFactory.populate(
+ m_data.toStrongRef().template constCast<std::remove_const_t<T>>());
}
}
}
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index c888ddcf87..e8900a0d69 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -123,7 +123,7 @@ static void annotateListElements(QmlIR::Document *document)
if (!listElementNames.contains(document->stringAt(object->inheritedTypeNameIndex)))
continue;
for (QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
binding->stringIndex = document->registerString(object->bindingAsString(document, binding->value.compiledScriptIndex));
}
@@ -135,7 +135,7 @@ static bool checkArgumentsObjectUseInSignalHandlers(const QmlIR::Document &doc,
{
for (QmlIR::Object *object: qAsConst(doc.objects)) {
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
- if (binding->type != QV4::CompiledData::Binding::Type_Script)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Script)
continue;
const QString propName = doc.stringAt(binding->propertyNameIndex);
if (!propName.startsWith(QLatin1String("on"))
@@ -238,18 +238,13 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
if (object->functionsAndExpressions->count == 0 && object->bindingCount() == 0)
continue;
- QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
- for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next)
- functionsToCompile << *foe;
- const QVector<int> runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile);
- if (v4CodeGen.hasError()) {
+
+ if (!v4CodeGen.generateRuntimeFunctions(object)) {
+ Q_ASSERT(v4CodeGen.hasError());
error->appendDiagnostic(inputFileName, v4CodeGen.error());
return false;
}
- QQmlJS::MemoryPool *pool = irDocument.jsParserEngine.pool();
- object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
-
if (!aotCompiler)
continue;
@@ -270,6 +265,12 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
std::copy(object->functionsBegin(), object->functionsEnd(),
std::back_inserter(bindingsAndFunctions));
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first;
+ foe; foe = foe->next) {
+ functionsToCompile << *foe;
+ }
+
// AOT-compile bindings and functions in the same order as above so that the runtime
// class indices match
std::sort(bindingsAndFunctions.begin(), bindingsAndFunctions.end());
@@ -278,7 +279,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
std::variant<QQmlJSAotFunction, QQmlJS::DiagnosticMessage> result;
auto *module = v4CodeGen.module();
if (const auto *binding = bindingOrFunction.binding()) {
- switch (binding->type) {
+ switch (binding->type()) {
case QmlIR::Binding::Type_AttachedProperty:
case QmlIR::Binding::Type_GroupProperty:
effectiveScopes.insert(
@@ -296,7 +297,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
break;
}
- Q_ASSERT(functionsToCompile.length() > binding->value.compiledScriptIndex);
+ Q_ASSERT(quint32(functionsToCompile.length()) > binding->value.compiledScriptIndex);
auto *node = functionsToCompile[binding->value.compiledScriptIndex].parentNode;
Q_ASSERT(node);
Q_ASSERT(module->contextMap.contains(node));
@@ -307,7 +308,7 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
<< irDocument.stringAt(binding->propertyNameIndex);
result = aotCompiler->compileBinding(context, *binding);
} else if (const auto *function = bindingOrFunction.function()) {
- Q_ASSERT(functionsToCompile.length() > function->index);
+ Q_ASSERT(quint32(functionsToCompile.length()) > function->index);
auto *node = functionsToCompile[function->index].node;
Q_ASSERT(node);
Q_ASSERT(module->contextMap.contains(node));
@@ -326,7 +327,8 @@ bool qCompileQmlFile(QmlIR::Document &irDocument, const QString &inputFileName,
<< diagnosticErrorMessage(inputFileName, *error);
} else if (auto *func = std::get_if<QQmlJSAotFunction>(&result)) {
qCInfo(lcAotCompiler) << "Generated code:" << func->code;
- aotFunctionsByIndex[runtimeFunctionIndices[bindingOrFunction.index()]] = *func;
+ aotFunctionsByIndex[object->runtimeFunctionIndices[bindingOrFunction.index()]] =
+ *func;
}
});
}
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index 8a59725a97..a9ee30de49 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -151,15 +151,15 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
continue;
}
- auto mo = qmlComponents.find(it.key());
+ auto mo = qmlComponents.find(it->fileName);
if (mo == qmlComponents.end()) {
QQmlJSScope::Ptr imported = localFile2ScopeTree(filePath);
if (it->singleton)
imported->setIsSingleton(true);
- mo = qmlComponents.insert(it.key(), imported);
+ mo = qmlComponents.insert(it->fileName, imported);
}
- (*mo)->addExport(it.key(), reader.typeNamespace(), it->version);
+ (*mo)->addExport(it.key(), reader.typeNamespace(), it->version, QTypeRevision());
}
for (auto it = qmlComponents.begin(), end = qmlComponents.end(); it != end; ++it)
result.objects.insert(it.key(), it.value());
@@ -187,79 +187,146 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
const auto scripts = reader.scripts();
for (const auto &script : scripts) {
const QString filePath = path + QLatin1Char('/') + script.fileName;
- result.scripts.insert(script.nameSpace, localFile2ScopeTree(filePath));
+ auto mo = result.scripts.find(script.fileName);
+ if (mo == result.scripts.end())
+ mo = result.scripts.insert(script.fileName, localFile2ScopeTree(filePath));
+ (*mo)->addExport(script.nameSpace, reader.typeNamespace(), script.version, QTypeRevision());
}
return result;
}
-void QQmlJSImporter::importDependencies(
- const QQmlJSImporter::Import &import,
- QQmlJSImporter::AvailableTypes *types, const QString &prefix, QTypeRevision version)
+void QQmlJSImporter::importDependencies(const QQmlJSImporter::Import &import,
+ QQmlJSImporter::AvailableTypes *types,
+ const QString &prefix, QTypeRevision version,
+ bool isDependency)
{
// Import the dependencies with an invalid prefix. The prefix will never be matched by actual
// QML code but the C++ types will be visible.
- const QString invalidPrefix = QString::fromLatin1("$dependency$");
for (auto const &dependency : qAsConst(import.dependencies))
- importHelper(dependency.module, types, invalidPrefix, dependency.version);
+ importHelper(dependency.module, types, QString(), dependency.version, true);
for (auto const &import : qAsConst(import.imports)) {
- importHelper(import.module, types, prefix,
- (import.flags & QQmlDirParser::Import::Auto) ? version : import.version);
+ importHelper(import.module, types, isDependency ? QString() : prefix,
+ (import.flags & QQmlDirParser::Import::Auto) ? version : import.version,
+ isDependency);
}
}
+static bool isVersionAllowed(const QQmlJSScope::Export &exportEntry,
+ const QTypeRevision &importVersion)
+{
+ return !importVersion.isValid() || exportEntry.version() <= importVersion;
+}
+
void QQmlJSImporter::processImport(const QQmlJSImporter::Import &import,
QQmlJSImporter::AvailableTypes *types, const QString &prefix,
QTypeRevision version)
{
const QString anonPrefix = QStringLiteral("$anonymous$");
+ QHash<QString, QList<QQmlJSScope::Export>> seenExports;
- if (!prefix.isEmpty())
- types->qmlNames.insert(prefix, {}); // Empty type means "this is the prefix"
-
- for (auto it = import.scripts.begin(); it != import.scripts.end(); ++it)
- types->qmlNames.insert(prefixedName(prefix, it.key()), it.value());
-
- // add objects
- for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
- const auto &val = it.value();
- types->cppNames.insert(val->internalName(), val);
+ const auto insertExports = [&](const QQmlJSScope::ConstPtr &val, const QString &cppName) {
+ QQmlJSScope::Export bestExport;
+ // Resolve conflicting qmlNames within an import
const auto exports = val->exports();
- if (exports.isEmpty()) {
- types->qmlNames.insert(
- prefixedName(prefix, prefixedName(anonPrefix, val->internalName())), val);
- }
-
for (const auto &valExport : exports) {
- const QString &name = prefixedName(prefix, valExport.type());
- // Resolve conflicting qmlNames within an import
- if (types->qmlNames.contains(name)) {
- const auto &existing = types->qmlNames[name];
-
- if (existing == val)
+ const QString qmlName = prefixedName(prefix, valExport.type());
+ if (!isVersionAllowed(valExport, version))
+ continue;
+
+ // Even if the QML name is overridden by some other type, we still want
+ // to insert the C++ type, with the highest revision available.
+ if (!bestExport.isValid() || valExport.version() > bestExport.version())
+ bestExport = valExport;
+
+ const auto it = types->qmlNames.find(qmlName);
+ if (it != types->qmlNames.end()) {
+
+ // The same set of exports can declare the same name multiple times for different
+ // versions. That's the common thing and we would just continue here when we hit
+ // it again after having inserted successfully once.
+ // However, it can also declare *different* names. Then we need to do the whole
+ // thing again.
+ if (it->scope == val && it->revision == valExport.version())
continue;
- if (valExport.version() > version)
- continue;
+ const auto existingExports = seenExports.value(qmlName);
+ enum { LowerVersion, SameVersion, HigherVersion } seenVersion = LowerVersion;
+ for (const QQmlJSScope::Export &entry : existingExports) {
+ if (!isVersionAllowed(entry, version))
+ continue;
- const auto existingExports = existing->exports();
+ if (valExport.version() < entry.version()) {
+ seenVersion = HigherVersion;
+ break;
+ }
- auto betterExport =
- std::find_if(existingExports.constBegin(), existingExports.constEnd(),
- [&](const QQmlJSScope::Export &exportEntry) {
- return exportEntry.type() == name
- && exportEntry.version()
- <= version // Ensure that the entry isn't newer
- // than the module version
- && valExport.version() < exportEntry.version();
- });
+ if (seenVersion == LowerVersion && valExport.version() == entry.version())
+ seenVersion = SameVersion;
+ }
- if (betterExport != existingExports.constEnd())
+ switch (seenVersion) {
+ case LowerVersion:
+ break;
+ case SameVersion: {
+ m_warnings.append({
+ QStringLiteral("Ambiguous type detected. "
+ "%1 %2.%3 is defined multiple times.")
+ .arg(qmlName)
+ .arg(valExport.version().majorVersion())
+ .arg(valExport.version().minorVersion()),
+ QtCriticalMsg,
+ QQmlJS::SourceLocation()
+ });
+
+ // Invalidate the type. We don't know which one to use.
+ it->scope = QQmlJSScope::ConstPtr();
+ continue;
+ }
+ case HigherVersion:
continue;
+ }
}
- types->qmlNames.insert(name, val);
+ types->qmlNames.insert(qmlName, { val, valExport.version() });
+ seenExports[qmlName].append(valExport);
+ }
+
+ types->cppNames.insert(
+ cppName, {
+ val,
+ bestExport.isValid() ? bestExport.revision() : QTypeRevision::zero()
+ }
+ );
+ };
+
+ if (!prefix.isEmpty())
+ types->qmlNames.insert(prefix, {}); // Empty type means "this is the prefix"
+
+ for (auto it = import.scripts.begin(); it != import.scripts.end(); ++it) {
+ // You cannot have a script without an export
+ Q_ASSERT(!(*it)->exports().isEmpty());
+ insertExports(*it, prefixedName(anonPrefix, (*it)->internalName()));
+ }
+
+ // add objects
+ for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
+ const auto &val = it.value();
+
+ const QString cppName = val->isComposite()
+ ? prefixedName(anonPrefix, val->internalName())
+ : val->internalName();
+
+ const auto exports = val->exports();
+ if (exports.isEmpty()) {
+ // Insert an unresolvable dummy name
+ types->qmlNames.insert(
+ prefixedName(prefix, prefixedName(anonPrefix, val->internalName())),
+ { val, QTypeRevision() });
+ types->cppNames.insert(cppName, { val, QTypeRevision() });
+ } else {
+ insertExports(val, cppName);
}
}
@@ -287,10 +354,32 @@ void QQmlJSImporter::processImport(const QQmlJSImporter::Import &import,
QQmlJSImporter::AvailableTypes tempTypes(builtinImportHelper().cppNames);
tempTypes.cppNames.insert(types->cppNames);
+ // At present, there are corner cases that couldn't be resolved in a single
+ // pass of resolveTypes() (e.g. QQmlEasingEnums::Type). However, such cases
+ // only happen when enumerations are involved, thus the strategy is to
+ // resolve enumerations (which can potentially create new child scopes)
+ // before resolving the type fully
+ const QQmlJSScope::ConstPtr intType = tempTypes.cppNames.value(u"int"_qs).scope;
+ for (auto it = import.objects.begin(); it != import.objects.end(); ++it)
+ QQmlJSScope::resolveEnums(it.value(), intType);
+
for (auto it = import.objects.begin(); it != import.objects.end(); ++it) {
const auto &val = it.value();
- if (val->baseType().isNull()) // Otherwise we have already done it in localFile2ScopeTree()
- QQmlJSScope::resolveTypes(val, tempTypes.cppNames);
+ if (val->baseType().isNull()) { // Otherwise we have already done it in localFile2ScopeTree()
+ // Composite types use QML names, and we should have resolved those already.
+ // ... except that old qmltypes files might specify composite types with C++ names.
+ // Warn about those.
+ if (val->isComposite()) {
+ m_warnings.append({
+ QStringLiteral("Found incomplete composite type %1. Do not use qmlplugindump.")
+ .arg(val->internalName()),
+ QtWarningMsg,
+ QQmlJS::SourceLocation()
+ });
+ }
+
+ QQmlJSScope::resolveNonEnumTypes(val, tempTypes.cppNames);
+ }
}
}
@@ -312,18 +401,40 @@ QQmlJSImporter::AvailableTypes QQmlJSImporter::builtinImportHelper()
QStringList qmltypesFiles = { QStringLiteral("builtins.qmltypes"),
QStringLiteral("jsroot.qmltypes") };
+ const auto importBuiltins = [&](const QStringList &imports) {
+ for (auto const &dir : imports) {
+ QDirIterator it { dir, qmltypesFiles, QDir::NoFilter, QDirIterator::Subdirectories };
+ while (it.hasNext() && !qmltypesFiles.isEmpty()) {
+ readQmltypes(it.next(), &result.objects, &result.dependencies);
+ qmltypesFiles.removeOne(it.fileName());
+ }
+
+ importDependencies(result, &m_builtins);
- for (auto const &dir : m_importPaths) {
- QDirIterator it { dir, qmltypesFiles, QDir::NoFilter, QDirIterator::Subdirectories };
- while (it.hasNext() && !qmltypesFiles.isEmpty()) {
- readQmltypes(it.next(), &result.objects, &result.dependencies);
- qmltypesFiles.removeOne(it.fileName());
+ if (qmltypesFiles.isEmpty())
+ return;
}
+ };
- importDependencies(result, &m_builtins);
+ importBuiltins(m_importPaths);
+ if (!qmltypesFiles.isEmpty()) {
+ const QString pathsString =
+ m_importPaths.isEmpty() ? u"<empty>"_qs : m_importPaths.join(u"\n\t");
+ m_warnings.append({ QStringLiteral("Failed to find the following builtins: %1 (so will use "
+ "qrc). Import paths used:\n\t%2")
+ .arg(qmltypesFiles.join(u", "), pathsString),
+ QtWarningMsg, QQmlJS::SourceLocation() });
+ importBuiltins({ u":/qt-project.org/qml/builtins"_qs }); // use qrc as a "last resort"
+ }
+ Q_ASSERT(qmltypesFiles.isEmpty()); // since qrc must cover it in all the bad cases
- if (qmltypesFiles.isEmpty())
- break;
+ if (!qmltypesFiles.isEmpty()) {
+ m_warnings.append({
+ QStringLiteral("Failed to find the following builtins: %1").arg(qmltypesFiles.join(u", ")),
+ QtWarningMsg,
+ QQmlJS::SourceLocation()
+ });
+ return m_builtins;
}
// Process them together since there they have interdependencies that wouldn't get resolved
@@ -379,16 +490,16 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::builtinInternalNames()
}
bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
- const QString &prefix, QTypeRevision version)
+ const QString &prefix, QTypeRevision version, bool isDependency,
+ bool isFile)
{
- const bool isDependency = prefix == QStringLiteral("$dependency$");
-
// QtQuick/Controls and QtQuick.Controls are the same module
const QString moduleCacheName = QString(module).replace(u'/', u'.');
- const auto cacheKey = QPair<QString, QTypeRevision> {
- (isDependency ? QString() : prefix) + u'|' + moduleCacheName, version
- };
+ if (isDependency)
+ Q_ASSERT(prefix.isEmpty());
+
+ const CacheKey cacheKey = { prefix, moduleCacheName, version, isFile, isDependency };
auto getTypesFromCache = [&]() -> bool {
if (!m_cachedImportTypes.contains(cacheKey))
@@ -413,7 +524,8 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
if (getTypesFromCache())
return true;
- auto cacheTypes = QSharedPointer<QQmlJSImporter::AvailableTypes>(new QQmlJSImporter::AvailableTypes({}));
+ auto cacheTypes =
+ QSharedPointer<QQmlJSImporter::AvailableTypes>(new QQmlJSImporter::AvailableTypes({}));
m_cachedImportTypes[cacheKey] = cacheTypes;
const QPair<QString, QTypeRevision> importId { module, version };
@@ -423,26 +535,29 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
if (it->isEmpty())
return false;
- const auto import = m_seenQmldirFiles.constFind(*it);
- Q_ASSERT(import != m_seenQmldirFiles.constEnd());
+ Q_ASSERT(m_seenQmldirFiles.contains(*it));
+ const QQmlJSImporter::Import import = m_seenQmldirFiles.value(*it);
- importDependencies(*import, cacheTypes.get(), prefix, version);
- processImport(*import, cacheTypes.get(), prefix, version);
+ importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
+ processImport(import, cacheTypes.get(), prefix, version);
const bool typesFromCache = getTypesFromCache();
Q_ASSERT(typesFromCache);
return typesFromCache;
}
- const auto modulePaths = qQmlResolveImportPaths(module, m_importPaths, version);
+ const auto modulePaths = isFile ? QStringList { module }
+ : qQmlResolveImportPaths(module, m_importPaths, version);
+
for (auto const &modulePath : modulePaths) {
const QString qmldirPath = modulePath + SlashQmldir;
const auto it = m_seenQmldirFiles.constFind(qmldirPath);
if (it != m_seenQmldirFiles.constEnd()) {
+ const QQmlJSImporter::Import import = *it;
m_seenImports.insert(importId, qmldirPath);
- importDependencies(*it, cacheTypes.get(), prefix, version);
- processImport(*it, cacheTypes.get(), prefix, version);
+ importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
+ processImport(import, cacheTypes.get(), prefix, version);
const bool typesFromCache = getTypesFromCache();
Q_ASSERT(typesFromCache);
@@ -454,7 +569,7 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
const auto import = readQmldir(file.canonicalPath());
m_seenQmldirFiles.insert(qmldirPath, import);
m_seenImports.insert(importId, qmldirPath);
- importDependencies(import, cacheTypes.get(), prefix, version);
+ importDependencies(import, cacheTypes.get(), prefix, version, isDependency);
processImport(import, cacheTypes.get(), prefix, version);
const bool typesFromCache = getTypesFromCache();
@@ -489,7 +604,7 @@ QQmlJSScope::Ptr QQmlJSImporter::importFile(const QString &file)
QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
const QString &directory, const QString &prefix)
{
- QHash<QString, QQmlJSScope::ConstPtr> qmlNames;
+ QQmlJSImporter::AvailableTypes types({});
if (directory.startsWith(u':')) {
if (m_mapper) {
@@ -498,12 +613,16 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
for (const auto &entry : resources) {
const QString name = QFileInfo(entry.resourcePath).baseName();
if (name.front().isUpper()) {
- qmlNames.insert(prefixedName(prefix, name),
- localFile2ScopeTree(entry.filePath));
+ types.qmlNames.insert(
+ prefixedName(prefix, name),
+ { localFile2ScopeTree(entry.filePath), QTypeRevision() });
}
}
}
- return qmlNames;
+
+ importHelper(directory, &types, QString(), QTypeRevision(), false, true);
+
+ return types.qmlNames;
}
QDirIterator it {
@@ -516,11 +635,14 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory(
if (!it.fileName().front().isUpper())
continue; // Non-uppercase names cannot be imported anyway.
- qmlNames.insert(prefixedName(prefix, QFileInfo(it.filePath()).baseName()),
- localFile2ScopeTree(it.filePath()));
+ types.qmlNames.insert(
+ prefixedName(prefix, QFileInfo(it.filePath()).baseName()),
+ { localFile2ScopeTree(it.filePath()), QTypeRevision() });
}
- return qmlNames;
+ importHelper(directory, &types, QString(), QTypeRevision(), false, true);
+
+ return types.qmlNames;
}
void QQmlJSImporter::setImportPaths(const QStringList &importPaths)
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h
index 01d1b30ba1..93e5ff7688 100644
--- a/src/qmlcompiler/qqmljsimporter_p.h
+++ b/src/qmlcompiler/qqmljsimporter_p.h
@@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE
class QQmlJSImporter
{
public:
- using ImportedTypes = QHash<QString, QQmlJSScope::ConstPtr>;
+ using ImportedTypes = QHash<QString, QQmlJSImportedScope>;
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper)
: m_importPaths(importPaths)
@@ -86,15 +86,15 @@ private:
struct AvailableTypes
{
- AvailableTypes(QHash<QString, QQmlJSScope::ConstPtr> builtins)
+ AvailableTypes(ImportedTypes builtins)
: cppNames(std::move(builtins))
{}
// C++ names used in qmltypes files for non-composite types
- QHash<QString, QQmlJSScope::ConstPtr> cppNames;
+ ImportedTypes cppNames;
// Names the importing component sees, including any prefixes
- QHash<QString, QQmlJSScope::ConstPtr> qmlNames;
+ ImportedTypes qmlNames;
};
struct Import {
@@ -106,14 +106,13 @@ private:
AvailableTypes builtinImportHelper();
bool importHelper(const QString &module, AvailableTypes *types,
- const QString &prefix = QString(),
- QTypeRevision version = QTypeRevision());
+ const QString &prefix = QString(), QTypeRevision version = QTypeRevision(),
+ bool isDependency = false, bool isFile = false);
void processImport(const Import &import, AvailableTypes *types,
const QString &prefix = QString(), QTypeRevision version = QTypeRevision());
- void importDependencies(const QQmlJSImporter::Import &import,
- AvailableTypes *types,
+ void importDependencies(const QQmlJSImporter::Import &import, AvailableTypes *types,
const QString &prefix = QString(),
- QTypeRevision version = QTypeRevision());
+ QTypeRevision version = QTypeRevision(), bool isDependency = false);
void readQmltypes(const QString &filename, QHash<QString, QQmlJSScope::Ptr> *objects,
QList<QQmlDirParser::Import> *dependencies);
Import readQmldir(const QString &dirname);
@@ -121,8 +120,29 @@ private:
QStringList m_importPaths;
+ struct CacheKey
+ {
+ QString prefix;
+ QString name;
+ QTypeRevision version;
+ bool isFile = false;
+ bool isDependency = false;
+
+ friend inline size_t qHash(const CacheKey &key, size_t seed = 0) noexcept
+ {
+ return qHashMulti(seed, key.prefix, key.name, key.version,
+ key.isFile, key.isDependency);
+ }
+
+ friend inline bool operator==(const CacheKey &a, const CacheKey &b)
+ {
+ return a.prefix == b.prefix && a.name == b.name && a.version == b.version
+ && a.isFile == b.isFile && a.isDependency == b.isDependency;
+ }
+ };
+
QHash<QPair<QString, QTypeRevision>, QString> m_seenImports;
- QHash<QPair<QString, QTypeRevision>, QSharedPointer<AvailableTypes>> m_cachedImportTypes;
+ QHash<CacheKey, QSharedPointer<AvailableTypes>> m_cachedImportTypes;
QHash<QString, Import> m_seenQmldirFiles;
QHash<QString, QQmlJSScope::Ptr> m_importedFiles;
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 3a3fd5d2ce..733cb3b2c0 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -35,6 +35,7 @@
#include <QtCore/qscopedvaluerollback.h>
#include <QtQml/private/qv4codegen_p.h>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <algorithm>
@@ -68,19 +69,21 @@ inline QString getScopeName(const QQmlJSScope::ConstPtr &scope, QQmlJSScope::Sco
return scope->baseTypeName();
}
-QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer,
- const QString &implicitImportDirectory,
- const QStringList &qmltypesFiles, const QString &fileName,
- const QString &code, bool silent)
+QQmlJSImportVisitor::QQmlJSImportVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer,
+ const QString &implicitImportDirectory, const QStringList &qmltypesFiles,
+ const QString &fileName, const QString &code, bool silent)
: m_implicitImportDirectory(implicitImportDirectory),
m_code(code),
m_filePath(fileName),
m_rootId(u"<id>"_qs),
m_qmltypesFiles(qmltypesFiles),
- m_currentScope(QQmlJSScope::create(QQmlJSScope::JSFunctionScope)),
+ m_currentScope(QQmlJSScope::create()),
+ m_exportedRootScope(target),
m_importer(importer),
m_logger(fileName, code, silent)
{
+ m_currentScope->setScopeType(QQmlJSScope::JSFunctionScope);
m_globalScope = m_currentScope;
m_currentScope->setIsComposite(true);
@@ -110,13 +113,30 @@ QQmlJSImportVisitor::QQmlJSImportVisitor(QQmlJSImporter *importer,
m_currentScope->insertJSIdentifier(jsGlobVar, globalJavaScript);
}
-void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
- const QQmlJS::SourceLocation &location)
+void QQmlJSImportVisitor::populateCurrentScope(
+ QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
{
- m_currentScope = QQmlJSScope::create(type, m_currentScope);
+ m_currentScope->setScopeType(type);
setScopeName(m_currentScope, type, name);
m_currentScope->setIsComposite(true);
m_currentScope->setSourceLocation(location);
+ m_scopesByIrLocation.insert({ location.startLine, location.startColumn }, m_currentScope);
+}
+
+void QQmlJSImportVisitor::enterRootScope(QQmlJSScope::ScopeType type, const QString &name, const QQmlJS::SourceLocation &location)
+{
+ QQmlJSScope::reparent(m_currentScope, m_exportedRootScope);
+ m_currentScope = m_exportedRootScope;
+ populateCurrentScope(type, name, location);
+}
+
+void QQmlJSImportVisitor::enterEnvironment(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location)
+{
+ QQmlJSScope::Ptr newScope = QQmlJSScope::create();
+ QQmlJSScope::reparent(m_currentScope, newScope);
+ m_currentScope = std::move(newScope);
+ populateCurrentScope(type, name, location);
}
bool QQmlJSImportVisitor::enterEnvironmentNonUnique(QQmlJSScope::ScopeType type,
@@ -141,6 +161,7 @@ bool QQmlJSImportVisitor::enterEnvironmentNonUnique(QQmlJSScope::ScopeType type,
return false;
}
// enter found scope
+ m_scopesByIrLocation.insert({ location.startLine, location.startColumn }, *it);
m_currentScope = *it;
return true;
}
@@ -167,14 +188,14 @@ void QQmlJSImportVisitor::resolveAliases()
if (!property.isAlias() || !property.type().isNull())
continue;
- QStringList components = property.typeName().split(u'.');
- QQmlJSScope::ConstPtr type;
+ QStringList components = property.typeName().split(u'.', Qt::SkipEmptyParts);
QQmlJSMetaProperty targetProperty;
// The first component has to be an ID. Find the object it refers to.
- const auto it = m_scopesById.find(components.takeFirst());
- if (it != m_scopesById.end()) {
- type = *it;
+ QQmlJSScope::ConstPtr type = components.isEmpty()
+ ? QQmlJSScope::ConstPtr()
+ : m_scopesById.scope(components.takeFirst(), object);
+ if (!type.isNull()) {
// Any further components are nested properties of that object.
// Technically we can only resolve a limited depth in the engine, but the rules
@@ -237,11 +258,6 @@ void QQmlJSImportVisitor::resolveAliases()
}
}
-QQmlJSScope::Ptr QQmlJSImportVisitor::result() const
-{
- return m_exportedRootScope;
-}
-
QString QQmlJSImportVisitor::implicitImportDirectory(
const QString &localFile, QQmlJSResourceFileMapper *mapper)
{
@@ -259,10 +275,10 @@ QString QQmlJSImportVisitor::implicitImportDirectory(
return QFileInfo(localFile).canonicalPath() + u'/';
}
-void QQmlJSImportVisitor::processImportWarnings(const QString &what, const QQmlJS::SourceLocation &srcLocation)
+void QQmlJSImportVisitor::processImportWarnings(
+ const QString &what, const QQmlJS::SourceLocation &srcLocation)
{
const auto warnings = m_importer->takeWarnings();
-
if (warnings.isEmpty())
return;
@@ -283,7 +299,11 @@ void QQmlJSImportVisitor::importBaseModules()
if (!m_qmltypesFiles.isEmpty())
m_importer->importQmltypes(m_qmltypesFiles);
- m_rootScopeImports.insert(m_importer->importDirectory(m_implicitImportDirectory));
+ // Pulling in the modules and neighboring qml files of the qmltypes we're trying to lint is not
+ // something we need to do.
+ if (!m_filePath.endsWith(u".qmltypes"_qs))
+ m_rootScopeImports.insert(m_importer->importDirectory(m_implicitImportDirectory));
+
processImportWarnings(QStringLiteral("base modules"));
}
@@ -303,12 +323,15 @@ void QQmlJSImportVisitor::endVisit(UiProgram *)
processPropertyBindingObjects();
checkRequiredProperties();
- for (const auto &scope : m_objectBindingScopes)
- checkInheritanceCycle(scope);
+ for (const auto &scope : m_objectBindingScopes) {
+ breakInheritanceCycles(scope);
+ checkDeprecation(scope);
+ }
for (const auto &scope : m_objectDefinitionScopes) {
checkGroupedAndAttachedScopes(scope);
- checkInheritanceCycle(scope);
+ breakInheritanceCycles(scope);
+ checkDeprecation(scope);
}
auto unusedImports = m_importLocations;
@@ -449,10 +472,10 @@ void QQmlJSImportVisitor::processDefaultProperties()
// TODO: Currently we only support binding one scope, adjust this once this is no longer
// true
- const QQmlJSScope::ConstPtr scope = it.value().constFirst();
+ QQmlJSScope::Ptr scope = it.value().first();
QQmlJSMetaPropertyBinding binding(defaultProp);
- binding.setValue(scope);
+ binding.setValue(static_cast<QQmlJSScope::ConstPtr>(scope));
binding.setValueTypeName(getScopeName(scope, QQmlJSScope::QMLScope));
it.key()->addOwnPropertyBinding(binding);
@@ -464,8 +487,13 @@ void QQmlJSImportVisitor::processDefaultProperties()
// Assigning any element to a QQmlComponent property implicitly wraps it into a Component
// Check whether the property can be assigned the scope
- if (propType->canAssign(scope))
- return;
+ if (propType->canAssign(scope)) {
+ if (propType->causesImplicitComponentWrapping()) {
+ // mark the scope as implicitly wrapped, unless it is a Component
+ scope->setIsWrappedInImplicitComponent(!scope->causesImplicitComponentWrapping());
+ }
+ continue;
+ }
m_logger.log(QStringLiteral("Cannot assign to default property of incompatible type"),
Log_Property, scope->sourceLocation());
@@ -479,7 +507,7 @@ void QQmlJSImportVisitor::processPropertyTypes()
auto property = type.scope->ownProperty(type.name);
- if (const auto propertyType = m_rootScopeImports.value(property.typeName())) {
+ if (const auto propertyType = m_rootScopeImports.value(property.typeName()).scope) {
property.setType(propertyType);
type.scope->addOwnProperty(property);
} else {
@@ -501,6 +529,10 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
if (property.isValid() && !property.type().isNull()
&& (objectBinding.onToken || property.type()->canAssign(objectBinding.childScope))) {
+
+ if (property.type()->causesImplicitComponentWrapping())
+ objectBinding.childScope->setIsWrappedInImplicitComponent(!objectBinding.childScope->causesImplicitComponentWrapping());
+
QQmlJSMetaPropertyBinding binding =
objectBinding.scope->hasOwnPropertyBinding(propertyName)
? objectBinding.scope->ownPropertyBinding(propertyName)
@@ -597,11 +629,13 @@ void QQmlJSImportVisitor::checkRequiredProperties()
}
for (const auto &defScope : m_objectDefinitionScopes) {
- if (defScope->parentScope() == m_globalScope || defScope->isInlineComponent())
+ if (defScope->parentScope() == m_globalScope || defScope->isInlineComponent() || defScope->isComponentRootElement())
continue;
QVector<QQmlJSScope::ConstPtr> scopesToSearch;
- for (QQmlJSScope::ConstPtr scope = defScope; scope; scope = scope->baseType()) {
+ QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
+ for (QQmlJSScope::ConstPtr scope = defScope; scope && !seen.hasSeen(scope);
+ scope = scope->baseType()) {
scopesToSearch << scope;
const auto ownProperties = scope->ownProperties();
for (auto propertyIt = ownProperties.constBegin();
@@ -649,10 +683,8 @@ void QQmlJSImportVisitor::checkRequiredProperties()
void QQmlJSImportVisitor::processPropertyBindings()
{
for (auto it = m_propertyBindings.constBegin(); it != m_propertyBindings.constEnd(); ++it) {
- QQmlJSScope::Ptr propertyScope = it.key();
- QQmlJSScope::Ptr scope = propertyScope->parentScope();
-
- for (const QString &name : it.value()) {
+ QQmlJSScope::Ptr scope = it.key();
+ for (auto &[visibilityScope, location, name] : it.value()) {
if (!scope->hasProperty(name)) {
// These warnings do not apply for custom parsers and their children and need to be
// handled on a case by case basis
@@ -664,7 +696,7 @@ void QQmlJSImportVisitor::processPropertyBindings()
m_logger.log(QStringLiteral("Binding assigned to \"%1\", but no property \"%1\" "
"exists in the current element.")
.arg(name),
- Log_Type, propertyScope->sourceLocation());
+ Log_Type, location);
continue;
}
@@ -674,7 +706,7 @@ void QQmlJSImportVisitor::processPropertyBindings()
"to a missing import statement or incomplete "
"qmltypes files.")
.arg(name),
- Log_Type, propertyScope->sourceLocation());
+ Log_Type, location);
}
const auto &annotations = property.annotations();
@@ -692,14 +724,14 @@ void QQmlJSImportVisitor::processPropertyBindings()
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- m_logger.log(message, Log_Deprecation, propertyScope->sourceLocation());
+ m_logger.log(message, Log_Deprecation, location);
}
QQmlJSMetaPropertyBinding binding(property);
// TODO: Actually store the value
- scope->addOwnPropertyBinding(binding);
+ visibilityScope->addOwnPropertyBinding(binding);
}
}
}
@@ -724,13 +756,15 @@ static QString signalName(QStringView handlerName)
void QQmlJSImportVisitor::checkSignals()
{
for (auto it = m_signals.constBegin(); it != m_signals.constEnd(); ++it) {
- for (const auto &pair : it.value()) {
+ for (const auto &scopeAndPair : it.value()) {
+ const auto location = scopeAndPair.dataLocation;
+ const auto &pair = scopeAndPair.data;
const QString signal = signalName(pair.first);
if (!it.key()->hasMethod(signal)) {
m_logger.log(QStringLiteral("no matching signal found for handler \"%1\"")
.arg(pair.first),
- Log_UnqualifiedAccess, m_currentScope->sourceLocation());
+ Log_UnqualifiedAccess, location);
continue;
}
@@ -752,7 +786,7 @@ void QQmlJSImportVisitor::checkSignals()
m_logger.log(QStringLiteral("Signal handler for \"%2\" has more formal"
" parameters than the signal it handles.")
.arg(pair.first),
- Log_Signal, it.key()->sourceLocation());
+ Log_Signal, location);
continue;
}
@@ -768,7 +802,7 @@ void QQmlJSImportVisitor::checkSignals()
.arg(i + 1)
.arg(pair.first, handlerParameter)
.arg(j + 1),
- Log_Signal, it.key()->sourceLocation());
+ Log_Signal, location);
}
}
}
@@ -783,11 +817,47 @@ void QQmlJSImportVisitor::addDefaultProperties()
m_pendingDefaultProperties[m_currentScope->parentScope()] << m_currentScope;
}
-void QQmlJSImportVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
+void QQmlJSImportVisitor::breakInheritanceCycles(const QQmlJSScope::Ptr &originalScope)
{
- QQmlJSScope::ConstPtr originalScope = scope;
QList<QQmlJSScope::ConstPtr> scopes;
- while (!scope.isNull()) {
+ for (QQmlJSScope::ConstPtr scope = originalScope; scope;) {
+ if (scopes.contains(scope)) {
+ QString inheritenceCycle;
+ for (const auto &seen : qAsConst(scopes)) {
+ inheritenceCycle.append(seen->baseTypeName());
+ inheritenceCycle.append(QLatin1String(" -> "));
+ }
+ inheritenceCycle.append(scopes.first()->baseTypeName());
+
+ const QString message = QStringLiteral("%1 is part of an inheritance cycle: %2")
+ .arg(scope->internalName(), inheritenceCycle);
+ m_logger.log(message, Log_InheritanceCycle);
+ originalScope->clearBaseType();
+ originalScope->setBaseTypeError(message);
+ break;
+ }
+
+ scopes.append(scope);
+
+ const auto newScope = scope->baseType();
+ if (newScope.isNull()) {
+ const QString error = scope->baseTypeError();
+ const QString name = scope->baseTypeName();
+ if (!error.isEmpty()) {
+ m_logger.log(error, Log_Import);
+ } else if (!name.isEmpty()) {
+ m_logger.log(name + QStringLiteral(" was not found. Did you add all import paths?"),
+ Log_Import);
+ }
+ }
+
+ scope = newScope;
+ }
+}
+
+void QQmlJSImportVisitor::checkDeprecation(const QQmlJSScope::ConstPtr &originalScope)
+{
+ for (QQmlJSScope::ConstPtr scope = originalScope; scope; scope = scope->baseType()) {
for (const QQmlJSAnnotation &annotation : scope->annotations()) {
if (annotation.isDeprecation()) {
QQQmlJSDeprecation deprecation = annotation.deprecation();
@@ -801,34 +871,6 @@ void QQmlJSImportVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
m_logger.log(message, Log_Deprecation, originalScope->sourceLocation());
}
}
-
- if (scopes.contains(scope)) {
- QString inheritenceCycle;
- for (const auto &seen : qAsConst(scopes)) {
- if (!inheritenceCycle.isEmpty())
- inheritenceCycle.append(QLatin1String(" -> "));
- inheritenceCycle.append(seen->baseTypeName());
- }
-
- m_logger.log(QStringLiteral("%1 is part of an inheritance cycle: %2")
- .arg(scope->internalName())
- .arg(inheritenceCycle),
- Log_InheritanceCycle);
- break;
- }
-
- scopes.append(scope);
-
- if (scope->baseTypeName().isEmpty()) {
- break;
- } else if (auto newScope = scope->baseType()) {
- scope = newScope;
- } else {
- m_logger.log(scope->baseTypeName()
- + QStringLiteral(" was not found. Did you add all import paths?"),
- Log_Import);
- break;
- }
}
}
@@ -912,19 +954,30 @@ bool QQmlJSImportVisitor::visit(UiObjectDefinition *definition)
superType.append(u'.');
superType.append(segment->name.toString());
}
- enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
- if (!m_exportedRootScope)
- m_exportedRootScope = m_currentScope;
-
- m_currentScope->setAnnotations(parseAnnotations(definition->annotations));
- if (m_nextIsInlineComponent) {
- m_currentScope->setIsInlineComponent(true);
- m_rootScopeImports.insert(m_inlineComponentName.toString(), m_currentScope);
- m_nextIsInlineComponent = false;
+ Q_ASSERT(!superType.isEmpty());
+ if (superType.front().isUpper()) {
+ if (rootScopeIsValid())
+ enterEnvironment(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
+ else
+ enterRootScope(QQmlJSScope::QMLScope, superType, definition->firstSourceLocation());
+
+ const QTypeRevision revision = QQmlJSScope::resolveTypes(
+ m_currentScope, m_rootScopeImports, &m_usedTypes);
+ if (m_nextIsInlineComponent) {
+ m_currentScope->setIsInlineComponent(true);
+ m_rootScopeImports.insert(
+ m_inlineComponentName.toString(), { m_currentScope, revision });
+ m_nextIsInlineComponent = false;
+ }
+ } else {
+ enterEnvironmentNonUnique(QQmlJSScope::GroupedPropertyScope, superType,
+ definition->firstSourceLocation());
+ Q_ASSERT(rootScopeIsValid());
+ QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
}
- QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
+ m_currentScope->setAnnotations(parseAnnotations(definition->annotations));
return true;
}
@@ -994,7 +1047,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
}
} else {
const auto name = publicMember->memberType->name.toString();
- if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].isNull()) {
+ if (m_rootScopeImports.contains(name) && !m_rootScopeImports[name].scope.isNull()) {
if (m_importTypeLocationMap.contains(name))
m_usedTypes.insert(name);
}
@@ -1004,7 +1057,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
prop.setIsList(publicMember->typeModifier == QLatin1String("list"));
prop.setIsWritable(!publicMember->isReadonlyMember);
prop.setIsAlias(isAlias);
- if (const auto type = m_rootScopeImports.value(typeName)) {
+ if (const auto type = m_rootScopeImports.value(typeName).scope) {
prop.setType(type);
const QString internalName = type->internalName();
prop.setTypeName(internalName.isEmpty() ? typeName : internalName);
@@ -1053,17 +1106,31 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp
m_pendingMethodAnnotations.clear();
}
+ bool anyFormalTyped = false;
if (const auto *formals = fexpr->formals) {
const auto parameters = formals->formals();
for (const auto &parameter : parameters) {
const QString type = parameter.typeName();
- method.addParameter(parameter.id,
- type.isEmpty() ? QStringLiteral("var") : type);
+ if (type.isEmpty()) {
+ method.addParameter(parameter.id, QStringLiteral("var"));
+ } else {
+ anyFormalTyped = true;
+ method.addParameter(parameter.id, type);
+ }
}
}
- method.setReturnTypeName(fexpr->typeAnnotation
- ? fexpr->typeAnnotation->type->toString()
- : QStringLiteral("var"));
+
+ // Methods with explicit return type return that.
+ // Methods with only untyped arguments return an untyped value.
+ // Methods with at least one typed argument but no explicit return type return void.
+ // In order to make a function without arguments return void, you have to specify that.
+ if (fexpr->typeAnnotation)
+ method.setReturnTypeName(fexpr->typeAnnotation->type->toString());
+ else if (anyFormalTyped)
+ method.setReturnTypeName(QStringLiteral("void"));
+ else
+ method.setReturnTypeName(QStringLiteral("var"));
+
m_currentScope->addOwnMethod(method);
if (m_currentScope->scopeType() != QQmlJSScope::QMLScope) {
@@ -1123,15 +1190,39 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::ClassExpression *)
leaveEnvironment();
}
+bool QQmlJSImportVisitor::isImportPrefix(QString prefix) const
+{
+ if (prefix.isEmpty() || !prefix.front().isUpper())
+ return false;
+
+ auto it = m_rootScopeImports.find(prefix);
+
+ if (it == m_rootScopeImports.end())
+ return false;
+
+ return it->scope.isNull();
+}
+
bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
{
- auto scope = m_currentScope;
+ m_savedBindingOuterScope = m_currentScope;
const auto id = scriptBinding->qualifiedId;
const auto *statement = cast<ExpressionStatement *>(scriptBinding->statement);
if (!id->next && id->name == QLatin1String("id")) {
- const auto *idExpression = cast<IdentifierExpression *>(statement->expression);
- const QString &name = idExpression->name.toString();
- m_scopesById.insert(name, m_currentScope);
+ const QString name = [&]() {
+ if (const auto *idExpression = cast<IdentifierExpression *>(statement->expression)) {
+ return idExpression->name.toString();
+ } else if (const auto *idString = cast<StringLiteral *>(statement->expression)) {
+ m_logger.log(u"ids do not need quotation marks"_qs, Log_Syntax,
+ idString->firstSourceLocation());
+ return idString->value.toString();
+ }
+ m_logger.log(u"Failed to parse id"_qs, Log_Syntax,
+ statement->expression->firstSourceLocation());
+ return QString();
+ }();
+ if (!name.isEmpty())
+ m_scopesById.insert(name, m_currentScope);
// TODO: Discard this once we properly store binding values and can just use
// QQmlJSScope::property() to obtain this
@@ -1141,42 +1232,32 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
return true;
}
- for (auto group = id; group->next; group = group->next) {
- const QString name = group->name.toString();
+ auto group = id;
+
+ QString prefix;
+ for (; group->next; group = group->next) {
+ const QString name = group->name.toString();
if (name.isEmpty())
break;
+ if (group == id && isImportPrefix(name)) {
+ prefix = name + u'.';
+ continue;
+ }
+
enterEnvironmentNonUnique(name.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
: QQmlJSScope::GroupedPropertyScope,
- name, group->firstSourceLocation());
- }
-
- // TODO: remember the actual binding, once we can process it.
-
- while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope
- || m_currentScope->scopeType() == QQmlJSScope::AttachedPropertyScope) {
- leaveEnvironment();
- }
-
- if (!statement || !statement->expression->asFunctionDefinition()) {
- enterEnvironment(QQmlJSScope::JSFunctionScope, QStringLiteral("binding"),
- scriptBinding->statement->firstSourceLocation());
+ prefix + name, group->firstSourceLocation());
+ prefix.clear();
}
- auto name = id->name;
-
+ auto name = group->name;
const QString signal = signalName(name);
- if (signal.isEmpty()) {
- for (const auto &childScope : scope->childScopes()) {
- if ((childScope->scopeType() == QQmlJSScope::AttachedPropertyScope
- || childScope->scopeType() == QQmlJSScope::GroupedPropertyScope)
- && childScope->internalName() == name) {
- return true;
- }
- }
- m_propertyBindings[m_currentScope] << name.toString();
+ if (signal.isEmpty()) {
+ m_propertyBindings[m_currentScope].append(
+ { m_savedBindingOuterScope, group->firstSourceLocation(), name.toString() });
} else {
const auto statement = scriptBinding->statement;
QStringList signalParameters;
@@ -1187,10 +1268,12 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
signalParameters << formal->element->bindingIdentifier.toString();
}
}
- m_signals[scope] << QPair<QString, QStringList> { name.toString(), signalParameters };
+ m_signals[m_currentScope].append({ m_savedBindingOuterScope, group->firstSourceLocation(),
+ qMakePair(name.toString(), signalParameters) });
QQmlJSMetaMethod scopeSignal;
- for (QQmlJSScope::ConstPtr qmlScope = scope; qmlScope; qmlScope = qmlScope->baseType()) {
+ for (QQmlJSScope::ConstPtr qmlScope = m_savedBindingOuterScope;
+ qmlScope; qmlScope = qmlScope->baseType()) {
const auto methods = qmlScope->ownMethods();
const auto methodsRange = methods.equal_range(signal);
for (auto method = methodsRange.first; method != methodsRange.second; ++method) {
@@ -1209,16 +1292,25 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
{ scopeSignal.parameterNames(), hasMultilineStatementBody });
}
+ // Leave any group/attached scopes so that the binding scope doesn't see its properties.
+ while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope
+ || m_currentScope->scopeType() == QQmlJSScope::AttachedPropertyScope) {
+ leaveEnvironment();
+ }
+
+ if (!statement || !statement->expression->asFunctionDefinition()) {
+ enterEnvironment(QQmlJSScope::JSFunctionScope, QStringLiteral("binding"),
+ scriptBinding->statement->firstSourceLocation());
+ }
+
return true;
}
-void QQmlJSImportVisitor::endVisit(UiScriptBinding *scriptBinding)
+void QQmlJSImportVisitor::endVisit(UiScriptBinding *)
{
- const auto id = scriptBinding->qualifiedId;
- if (id->next || id->name != QLatin1String("id")) {
- const auto *statement = cast<ExpressionStatement *>(scriptBinding->statement);
- if (!statement || !statement->expression->asFunctionDefinition())
- leaveEnvironment();
+ if (m_savedBindingOuterScope) {
+ m_currentScope = m_savedBindingOuterScope;
+ m_savedBindingOuterScope = {};
}
}
@@ -1233,6 +1325,8 @@ bool QQmlJSImportVisitor::visit(UiArrayBinding *arrayBinding)
enterEnvironment(QQmlJSScope::QMLScope, name, arrayBinding->firstSourceLocation());
m_currentScope->setIsArrayScope(true);
+ // TODO: support group/attached properties
+
return true;
}
@@ -1291,7 +1385,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
const QString actualPrefix = prefix.isEmpty()
? QFileInfo(entry.resourcePath).baseName()
: prefix;
- m_rootScopeImports.insert(actualPrefix, scope);
+ m_rootScopeImports.insert(actualPrefix, { scope, QTypeRevision() });
addImportLocation(actualPrefix);
} else {
@@ -1315,7 +1409,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
} else if (path.isFile()) {
const auto scope = m_importer->importFile(path.canonicalFilePath());
const QString actualPrefix = prefix.isEmpty() ? scope->internalName() : prefix;
- m_rootScopeImports.insert(actualPrefix, scope);
+ m_rootScopeImports.insert(actualPrefix, { scope, QTypeRevision() });
addImportLocation(actualPrefix);
}
@@ -1488,20 +1582,30 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
name.chop(1);
bool needsResolution = false;
+ int scopesEnteredCounter = 0;
+
+ QString prefix;
for (auto group = uiob->qualifiedId; group->next; group = group->next) {
const QString idName = group->name.toString();
if (idName.isEmpty())
break;
+ if (group == uiob->qualifiedId && isImportPrefix(idName)) {
+ prefix = idName + u'.';
+ continue;
+ }
+
const auto scopeKind = idName.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
: QQmlJSScope::GroupedPropertyScope;
- bool exists = enterEnvironmentNonUnique(scopeKind, idName, group->firstSourceLocation());
+ bool exists = enterEnvironmentNonUnique(scopeKind, prefix + idName, group->firstSourceLocation());
+ ++scopesEnteredCounter;
needsResolution = needsResolution || !exists;
+
+ prefix.clear();
}
- while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope
- || m_currentScope->scopeType() == QQmlJSScope::AttachedPropertyScope) {
+ for (int i=0; i < scopesEnteredCounter; ++i) { // leave the scopes we entered again
leaveEnvironment();
}
@@ -1520,20 +1624,34 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
{
QQmlJSScope::resolveTypes(m_currentScope, m_rootScopeImports, &m_usedTypes);
- const QQmlJSScope::ConstPtr childScope = m_currentScope;
+ // must be mutable, as we might mark it as implicitly wrapped in a component
+ const QQmlJSScope::Ptr childScope = m_currentScope;
leaveEnvironment();
auto group = uiob->qualifiedId;
+ int scopesEnteredCounter = 0;
+
+ QString prefix;
for (; group->next; group = group->next) {
const QString idName = group->name.toString();
if (idName.isEmpty())
break;
+ if (group == uiob->qualifiedId && isImportPrefix(idName)) {
+ prefix = idName + u'.';
+ continue;
+ }
+
const auto scopeKind = idName.front().isUpper() ? QQmlJSScope::AttachedPropertyScope
: QQmlJSScope::GroupedPropertyScope;
// definitely exists
- enterEnvironmentNonUnique(scopeKind, idName, group->firstSourceLocation());
+ [[maybe_unused]] bool exists =
+ enterEnvironmentNonUnique(scopeKind, prefix + idName, group->firstSourceLocation());
+ Q_ASSERT(exists);
+ scopesEnteredCounter++;
+
+ prefix.clear();
}
// on ending the visit to UiObjectBinding, set the property type to the
@@ -1550,15 +1668,13 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
uiob->firstSourceLocation(), uiob->hasOnToken };
}
- while (m_currentScope->scopeType() == QQmlJSScope::GroupedPropertyScope
- || m_currentScope->scopeType() == QQmlJSScope::AttachedPropertyScope) {
+ for (int i = 0; i < scopesEnteredCounter; ++i)
leaveEnvironment();
- }
}
bool QQmlJSImportVisitor::visit(ExportDeclaration *)
{
- Q_ASSERT(!m_exportedRootScope.isNull());
+ Q_ASSERT(rootScopeIsValid());
Q_ASSERT(m_exportedRootScope != m_globalScope);
Q_ASSERT(m_currentScope == m_globalScope);
m_currentScope = m_exportedRootScope;
@@ -1567,18 +1683,17 @@ bool QQmlJSImportVisitor::visit(ExportDeclaration *)
void QQmlJSImportVisitor::endVisit(ExportDeclaration *)
{
- Q_ASSERT(!m_exportedRootScope.isNull());
+ Q_ASSERT(rootScopeIsValid());
m_currentScope = m_exportedRootScope->parentScope();
Q_ASSERT(m_currentScope == m_globalScope);
}
bool QQmlJSImportVisitor::visit(ESModule *module)
{
- enterEnvironment(QQmlJSScope::JSLexicalScope, QStringLiteral("module"),
- module->firstSourceLocation());
- Q_ASSERT(m_exportedRootScope.isNull());
- m_exportedRootScope = m_currentScope;
- m_exportedRootScope->setIsScript(true);
+ Q_ASSERT(!rootScopeIsValid());
+ enterRootScope(
+ QQmlJSScope::JSLexicalScope, QStringLiteral("module"), module->firstSourceLocation());
+ m_currentScope->setIsScript(true);
importBaseModules();
leaveEnvironment();
return true;
@@ -1592,9 +1707,10 @@ void QQmlJSImportVisitor::endVisit(ESModule *)
bool QQmlJSImportVisitor::visit(Program *)
{
Q_ASSERT(m_globalScope == m_currentScope);
- Q_ASSERT(m_exportedRootScope.isNull());
- m_exportedRootScope = m_currentScope;
+ Q_ASSERT(!rootScopeIsValid());
+ *m_exportedRootScope = std::move(*QQmlJSScope::clone(m_currentScope));
m_exportedRootScope->setIsScript(true);
+ m_currentScope = m_exportedRootScope;
importBaseModules();
return true;
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index 66107f0921..19e96ebe99 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -42,11 +42,12 @@
#include "qqmljsscope_p.h"
#include "qqmljsannotation_p.h"
#include "qqmljslogger_p.h"
+#include "qqmljsscopesbyid_p.h"
#include <private/qqmljsast_p.h>
#include <private/qqmljsdiagnosticmessage_p.h>
#include <private/qqmljsimporter_p.h>
-
+#include <private/qv4compileddata_p.h>
QT_BEGIN_NAMESPACE
@@ -54,18 +55,25 @@ struct QQmlJSResourceFileMapper;
class QQmlJSImportVisitor : public QQmlJS::AST::Visitor
{
public:
- QQmlJSImportVisitor(QQmlJSImporter *importer, const QString &implicitImportDirectory,
- const QStringList &qmltypesFiles = QStringList(), const QString &fileName = QString(), const QString &code = QString(), bool silent = true);
+ QQmlJSImportVisitor(
+ const QQmlJSScope::Ptr &target, QQmlJSImporter *importer,
+ const QString &implicitImportDirectory,
+ const QStringList &qmltypesFiles = QStringList(), const QString &fileName = QString(),
+ const QString &code = QString(), bool silent = true);
- QQmlJSScope::Ptr result() const;
+ QQmlJSScope::Ptr result() const { return m_exportedRootScope; }
// TODO: Should be superseded by accessing the logger instead
QList<QQmlJS::DiagnosticMessage> errors() const { return m_logger.warnings() + m_logger.errors(); }
QQmlJSLogger &logger() { return m_logger; }
- QHash<QString, QQmlJSScope::ConstPtr> imports() const { return m_rootScopeImports; }
- QHash<QString, QQmlJSScope::ConstPtr> addressableScopes() const { return m_scopesById; }
+ QQmlJSImporter::ImportedTypes imports() const { return m_rootScopeImports; }
+ QQmlJSScopesById addressableScopes() const { return m_scopesById; }
+ QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> scopesBylocation() const
+ {
+ return m_scopesByIrLocation;
+ }
static QString implicitImportDirectory(
const QString &localFile, QQmlJSResourceFileMapper *mapper);
@@ -138,10 +146,15 @@ protected:
bool m_nextIsInlineComponent = false;
QStringList m_qmltypesFiles;
QQmlJSScope::Ptr m_currentScope;
- QQmlJSScope::Ptr m_exportedRootScope;
+ QQmlJSScope::Ptr m_savedBindingOuterScope;
+ const QQmlJSScope::Ptr m_exportedRootScope;
QQmlJSScope::ConstPtr m_globalScope;
- QHash<QString, QQmlJSScope::ConstPtr> m_scopesById;
- QHash<QString, QQmlJSScope::ConstPtr> m_rootScopeImports;
+ QQmlJSScopesById m_scopesById;
+ QQmlJSImporter::ImportedTypes m_rootScopeImports;
+
+ // We need to record the locations as IR locations because those contain less data.
+ // This way we can look up objects by IR location later.
+ QHash<QV4::CompiledData::Location, QQmlJSScope::ConstPtr> m_scopesByIrLocation;
// Maps all qmlNames to the source location of their import
QMultiHash<QString, QQmlJS::SourceLocation> m_importTypeLocationMap;
@@ -170,8 +183,14 @@ protected:
void checkSignals();
void flushPendingSignalParameters();
- void checkInheritanceCycle(QQmlJSScope::ConstPtr scope);
+ QQmlJSScope::ConstPtr scopeById(const QString &id, const QQmlJSScope::ConstPtr &current);
+
+ void breakInheritanceCycles(const QQmlJSScope::Ptr &scope);
+ void checkDeprecation(const QQmlJSScope::ConstPtr &scope);
void checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr scope);
+ bool rootScopeIsValid() const { return m_exportedRootScope->sourceLocation().isValid(); }
+
+ bool isImportPrefix(QString prefix) const;
QQmlJSLogger m_logger;
@@ -188,7 +207,7 @@ protected:
struct PendingPropertyObjectBinding
{
QQmlJSScope::Ptr scope;
- QQmlJSScope::ConstPtr childScope;
+ QQmlJSScope::Ptr childScope;
QString name;
QQmlJS::SourceLocation location;
bool onToken;
@@ -201,6 +220,25 @@ protected:
QQmlJS::SourceLocation location;
};
+ /*!
+ Utility wrapper that adds visibility scope to the data.
+
+ This wrapper becomes useful for binding processing where we need to know
+ both the property (or signal handler) owner and the scope in which the
+ binding is executed (the "visibility" scope).
+
+ As visibility scope (and data) does not typically have sufficient
+ information about a proper source location of that data, the location
+ also has to be provided to simplify the error reporting.
+ */
+ template<typename T>
+ struct WithVisibilityScope
+ {
+ QQmlJSScope::Ptr visibilityScope;
+ QQmlJS::SourceLocation dataLocation;
+ T data;
+ };
+
QHash<QQmlJSScope::Ptr, QVector<QQmlJSScope::Ptr>> m_pendingDefaultProperties;
QVector<PendingPropertyType> m_pendingPropertyTypes;
QVector<PendingPropertyObjectBinding> m_pendingPropertyObjectBindings;
@@ -208,8 +246,8 @@ protected:
QVector<QQmlJSScope::Ptr> m_objectBindingScopes;
QVector<QQmlJSScope::Ptr> m_objectDefinitionScopes;
- QHash<QQmlJSScope::Ptr, QVector<QString>> m_propertyBindings;
- QHash<QQmlJSScope::Ptr, QVector<QPair<QString, QStringList>>> m_signals;
+ QHash<QQmlJSScope::Ptr, QVector<WithVisibilityScope<QString>>> m_propertyBindings;
+ QHash<QQmlJSScope::Ptr, QVector<WithVisibilityScope<QPair<QString, QStringList>>>> m_signals;
QHash<QQmlJS::SourceLocation, QQmlJSMetaSignalHandler> m_signalHandlers;
QQmlJS::SourceLocation m_pendingSignalHandler;
@@ -227,9 +265,16 @@ protected:
private:
void importBaseModules();
void resolveAliases();
+
void visitFunctionExpressionHelper(QQmlJS::AST::FunctionExpression *fexpr);
- void processImportWarnings(const QString &what, const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
+ void processImportWarnings(
+ const QString &what,
+ const QQmlJS::SourceLocation &srcLocation = QQmlJS::SourceLocation());
void addImportWithLocation(const QString &name, const QQmlJS::SourceLocation &loc);
+ void populateCurrentScope(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location);
+ void enterRootScope(QQmlJSScope::ScopeType type, const QString &name,
+ const QQmlJS::SourceLocation &location);
};
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp
index 7f04e3b66e..833927e082 100644
--- a/src/qmlcompiler/qqmljslogger.cpp
+++ b/src/qmlcompiler/qqmljslogger.cpp
@@ -26,6 +26,17 @@
**
****************************************************************************/
+#include <qglobal.h>
+
+// GCC 11 thinks diagMsg.fixSuggestion.fixes.d.ptr is somehow uninitialized in
+// QList::emplaceBack(), probably called from QQmlJsLogger::log()
+// Ditto for GCC 12, but it emits a different warning
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wuninitialized")
+QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
+#include <qlist.h>
+QT_WARNING_POP
+
#include "qqmljslogger_p.h"
const QMap<QString, QQmlJSLogger::Option> &QQmlJSLogger::options() {
diff --git a/src/qmlcompiler/qqmljslogger_p.h b/src/qmlcompiler/qqmljslogger_p.h
index 5ccbe91045..2d63a860c3 100644
--- a/src/qmlcompiler/qqmljslogger_p.h
+++ b/src/qmlcompiler/qqmljslogger_p.h
@@ -63,7 +63,7 @@ public:
\param location: The location where an error occurred.
*/
IssueLocationWithContext(QStringView code, const QQmlJS::SourceLocation &location) {
- int before = qMax(0,code.lastIndexOf(QLatin1Char('\n'), location.offset));
+ quint32 before = qMax(0, code.lastIndexOf(QLatin1Char('\n'), location.offset));
if (before != 0) before++;
diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp
index 2276c10814..c817cd61be 100644
--- a/src/qmlcompiler/qqmljsscope.cpp
+++ b/src/qmlcompiler/qqmljsscope.cpp
@@ -34,6 +34,8 @@
#include <QtCore/qsharedpointer.h>
#include <QtCore/qfileinfo.h>
+#include <private/qduplicatetracker_p.h>
+
#include <algorithm>
#include <type_traits>
@@ -73,11 +75,12 @@ static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check
using T = decltype(
getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(std::declval<QQmlJSScope::ConstPtr>()));
- for (T scope = type; scope;
+ QDuplicateTracker<T> seen;
+ for (T scope = type; scope && !seen.hasSeen(scope);
scope = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->baseType())) {
// Extensions override their base types
for (T extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(scope->extensionType());
- extension;
+ extension && !seen.hasSeen(extension);
extension = getQQmlJSScopeFromSmartPtr<QQmlJSScopePtr>(extension->baseType())) {
if (check(extension))
return true;
@@ -90,15 +93,24 @@ static bool searchBaseAndExtensionTypes(QQmlJSScopePtr type, const Action &check
return false;
}
-QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope)
- : m_parentScope(parentScope), m_scopeType(type) {}
-
-QQmlJSScope::Ptr QQmlJSScope::create(ScopeType type, const QQmlJSScope::Ptr &parentScope)
+void QQmlJSScope::reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope)
{
- QSharedPointer<QQmlJSScope> childScope(new QQmlJSScope{type, parentScope});
+ if (const QQmlJSScope::Ptr parent = childScope->m_parentScope.toStrongRef())
+ parent->m_childScopes.removeOne(childScope);
if (parentScope)
- parentScope->m_childScopes.push_back(childScope);
- return childScope;
+ parentScope->m_childScopes.append(childScope);
+ childScope->m_parentScope = parentScope;
+}
+
+QQmlJSScope::Ptr QQmlJSScope::clone(const ConstPtr &origin)
+{
+ if (origin.isNull())
+ return QQmlJSScope::Ptr();
+ QQmlJSScope::Ptr cloned = create();
+ *cloned = *origin;
+ if (QQmlJSScope::Ptr parent = cloned->parentScope())
+ parent->m_childScopes.append(cloned);
+ return cloned;
}
void QQmlJSScope::insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier)
@@ -179,6 +191,45 @@ QQmlJSMetaEnum QQmlJSScope::enumeration(const QString &name) const
return result;
}
+/*!
+ Returns if assigning to a property of this type would cause
+ implicit component wrapping for non-Component types.
+
+ \note This method can also be used to check whether a type needs
+ to be implicitly wrapped: A type for which this function returns true
+ doesn't need to be actually wrapped.
+ */
+bool QQmlJSScope::causesImplicitComponentWrapping() const {
+ if (internalName() == u"QQmlComponent")
+ return true;
+ else if (isComposite()) // composite types are never treated as Component
+ return false;
+ // A class which is derived from component is not treated as a Component
+ // However isUsableComponent considers also QQmlAbstractDelegateComponent
+ // See isUsableComponent in qqmltypecompiler.cpp
+
+ for (auto cppBase = nonCompositeBaseType(baseType()); cppBase; cppBase = cppBase->baseType())
+ if (cppBase->internalName() == u"QQmlAbstractDelegateComponent")
+ return true;
+ return false;
+}
+
+/*!
+ \internal
+ Returns true if the scope is the outermost element of a separate Component
+ Either because it has been implicitly wrapped, e.g. due to an assignment to
+ a Component property, or because it is the first (and only) child of a
+ Component.
+ */
+bool QQmlJSScope::isComponentRootElement() const {
+ if (m_flags.testFlag(WrappedInImplicitComponent))
+ return true;
+ auto base = nonCompositeBaseType(parentScope()); // handles null parentScope()
+ if (!base)
+ return false;
+ return base->internalName() == u"QQmlComponent";
+}
+
bool QQmlJSScope::isIdInCurrentQmlScopes(const QString &id) const
{
if (m_scopeType == QQmlJSScope::QMLScope)
@@ -224,70 +275,61 @@ QQmlJSScope::findJSIdentifier(const QString &id) const
return std::optional<JavaScriptIdentifier>{};
}
-void QQmlJSScope::resolveTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, QQmlJSScope::ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes)
+QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
+ const QString &name, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
{
- auto findType = [&](const QString &name) -> QQmlJSScope::ConstPtr {
- auto type = contextualTypes.constFind(name);
+ auto type = contextualTypes.constFind(name);
- if (type != contextualTypes.constEnd()) {
- if (usedTypes != nullptr)
- usedTypes->insert(name);
- return *type;
- }
+ if (type != contextualTypes.constEnd()) {
+ if (usedTypes != nullptr)
+ usedTypes->insert(name);
+ return *type;
+ }
- const auto colonColon = name.indexOf(QStringLiteral("::"));
- if (colonColon > 0) {
- const QString outerTypeName = name.left(colonColon);
- const auto outerType = contextualTypes.constFind(outerTypeName);
- if (outerType != contextualTypes.constEnd()) {
- for (const auto &innerType : qAsConst((*outerType)->m_childScopes)) {
- if (innerType->m_internalName == name) {
- if (usedTypes != nullptr)
- usedTypes->insert(name);
- return innerType;
- }
+ const auto colonColon = name.indexOf(QStringLiteral("::"));
+ if (colonColon > 0) {
+ const QString outerTypeName = name.left(colonColon);
+ const auto outerType = contextualTypes.constFind(outerTypeName);
+ if (outerType != contextualTypes.constEnd()) {
+ for (const auto &innerType : qAsConst(outerType->scope->m_childScopes)) {
+ if (innerType->m_internalName == name) {
+ if (usedTypes != nullptr)
+ usedTypes->insert(name);
+ return { innerType, outerType->revision };
}
}
}
+ }
- return QQmlJSScope::ConstPtr();
- };
+ return {};
+}
- if (!self->m_baseType && !self->m_baseTypeName.isEmpty())
- self->m_baseType = findType(self->m_baseTypeName);
+QTypeRevision QQmlJSScope::resolveType(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
+ QSet<QString> *usedTypes)
+{
+ const QString baseTypeName = self->baseTypeName();
+ const auto baseType = findType(baseTypeName, context, usedTypes);
+ if (!self->m_baseType.scope && !baseTypeName.isEmpty())
+ self->m_baseType = { baseType.scope, baseType.revision };
if (!self->m_attachedType && !self->m_attachedTypeName.isEmpty())
- self->m_attachedType = findType(self->m_attachedTypeName);
+ self->m_attachedType = findType(self->m_attachedTypeName, context, usedTypes).scope;
if (!self->m_valueType && !self->m_valueTypeName.isEmpty())
- self->m_valueType = findType(self->m_valueTypeName);
+ self->m_valueType = findType(self->m_valueTypeName, context, usedTypes).scope;
if (!self->m_extensionType && !self->m_extensionTypeName.isEmpty())
- self->m_extensionType = findType(self->m_extensionTypeName);
-
- const auto intType = findType(QStringLiteral("int"));
- Q_ASSERT(intType); // There always has to be a builtin "int" type
- for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end();
- it != end; ++it) {
- if (it->type())
- continue;
- auto enumScope = QQmlJSScope::create(EnumScope, self);
- enumScope->m_baseTypeName = QStringLiteral("int");
- enumScope->m_baseType = intType;
- enumScope->m_semantics = AccessSemantics::Value;
- enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
- it->setType(ConstPtr(enumScope));
- }
+ self->m_extensionType = findType(self->m_extensionTypeName, context, usedTypes).scope;
for (auto it = self->m_properties.begin(), end = self->m_properties.end(); it != end; ++it) {
const QString typeName = it->typeName();
if (it->type() || typeName.isEmpty())
continue;
- if (const auto type = findType(typeName)) {
- it->setType(type);
+ if (const auto type = findType(typeName, context, usedTypes); type.scope) {
+ it->setType(type.scope);
continue;
}
@@ -298,8 +340,10 @@ void QQmlJSScope::resolveTypes(const QQmlJSScope::Ptr &self,
for (auto it = self->m_methods.begin(), end = self->m_methods.end(); it != end; ++it) {
const QString returnTypeName = it->returnTypeName();
- if (!it->returnType() && !returnTypeName.isEmpty())
- it->setReturnType(findType(returnTypeName));
+ if (!it->returnType() && !returnTypeName.isEmpty()) {
+ const auto returnType = findType(returnTypeName, context, usedTypes);
+ it->setReturnType(returnType.scope);
+ }
const auto paramTypeNames = it->parameterTypeNames();
QList<QSharedPointer<const QQmlJSScope>> paramTypes = it->parameterTypes();
@@ -309,37 +353,97 @@ void QQmlJSScope::resolveTypes(const QQmlJSScope::Ptr &self,
for (int i = 0, length = paramTypes.length(); i < length; ++i) {
auto &paramType = paramTypes[i];
const auto paramTypeName = paramTypeNames[i];
- if (!paramType && !paramTypeName.isEmpty())
- paramType = findType(paramTypeName);
+ if (!paramType && !paramTypeName.isEmpty()) {
+ const auto type = findType(paramTypeName, context, usedTypes);
+ paramType = type.scope;
+ }
}
it->setParameterTypes(paramTypes);
}
- for (auto it = self->m_childScopes.begin(), end = self->m_childScopes.end(); it != end; ++it) {
- QQmlJSScope::Ptr childScope = *it;
- switch (childScope->scopeType()) {
- case QQmlJSScope::GroupedPropertyScope:
- searchBaseAndExtensionTypes(self.data(), [&](const QQmlJSScope *type) {
- const auto propertyIt = type->m_properties.find(childScope->internalName());
- if (propertyIt != type->m_properties.end()) {
- childScope->m_baseType = QQmlJSScope::ConstPtr(propertyIt->type());
- childScope->m_baseTypeName = propertyIt->typeName();
- return true;
- }
- return false;
- });
- break;
- case QQmlJSScope::AttachedPropertyScope:
- if (const auto attachedBase = findType(childScope->internalName())) {
- childScope->m_baseType = attachedBase->attachedType();
- childScope->m_baseTypeName = attachedBase->attachedTypeName();
+ return baseType.revision;
+}
+
+void QQmlJSScope::updateChildScope(
+ const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
+{
+ switch (childScope->scopeType()) {
+ case QQmlJSScope::GroupedPropertyScope:
+ searchBaseAndExtensionTypes(self.data(), [&](const QQmlJSScope *type) {
+ const auto propertyIt = type->m_properties.find(childScope->internalName());
+ if (propertyIt != type->m_properties.end()) {
+ childScope->m_baseType.scope = QQmlJSScope::ConstPtr(propertyIt->type());
+ childScope->setBaseTypeName(propertyIt->typeName());
+ return true;
}
- break;
- default:
- break;
+ return false;
+ });
+ break;
+ case QQmlJSScope::AttachedPropertyScope:
+ if (const auto attachedBase = findType(
+ childScope->internalName(), contextualTypes, usedTypes).scope) {
+ childScope->m_baseType.scope = attachedBase->attachedType();
+ childScope->setBaseTypeName(attachedBase->attachedTypeName());
}
- resolveTypes(childScope, contextualTypes, usedTypes);
+ break;
+ default:
+ break;
+ }
+}
+
+template<typename Resolver, typename ChildScopeUpdater>
+static QTypeRevision resolveTypesInternal(
+ Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
+{
+ const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
+ // NB: constness ensures no detach
+ const auto childScopes = self->childScopes();
+ for (auto it = childScopes.begin(), end = childScopes.end(); it != end; ++it) {
+ const auto childScope = *it;
+ update(childScope, self, contextualTypes, usedTypes);
+ resolveTypesInternal(resolve, update, childScope, contextualTypes, usedTypes); // recursion
+ }
+ return revision;
+}
+
+QTypeRevision QQmlJSScope::resolveTypes(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
+{
+ const auto resolveAll = [](const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes) {
+ resolveEnums(self, findType(u"int"_qs, contextualTypes, usedTypes).scope);
+ return resolveType(self, contextualTypes, usedTypes);
+ };
+ return resolveTypesInternal(resolveAll, updateChildScope, self, contextualTypes, usedTypes);
+}
+
+void QQmlJSScope::resolveNonEnumTypes(
+ const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes)
+{
+ resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
+}
+
+void QQmlJSScope::resolveEnums(const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &intType)
+{
+ Q_ASSERT(intType); // There always has to be a builtin "int" type
+ for (auto it = self->m_enumerations.begin(), end = self->m_enumerations.end(); it != end;
+ ++it) {
+ if (it->type())
+ continue;
+ QQmlJSScope::Ptr enumScope = QQmlJSScope::create();
+ reparent(self, enumScope);
+ enumScope->m_scopeType = EnumScope;
+ enumScope->setBaseTypeName(QStringLiteral("int"));
+ enumScope->m_baseType.scope = intType;
+ enumScope->m_semantics = AccessSemantics::Value;
+ enumScope->m_internalName = self->internalName() + QStringLiteral("::") + it->name();
+ it->setType(QQmlJSScope::ConstPtr(enumScope));
}
}
@@ -352,9 +456,9 @@ QQmlJSScope::ConstPtr QQmlJSScope::findCurrentQMLScope(const QQmlJSScope::ConstP
}
void QQmlJSScope::addExport(const QString &name, const QString &package,
- const QTypeRevision &version)
+ const QTypeRevision &version, const QTypeRevision &revision)
{
- m_exports.append(Export(package, name, version));
+ m_exports.append(Export(package, name, version, revision));
}
bool QQmlJSScope::hasProperty(const QString &name) const
@@ -447,6 +551,28 @@ bool QQmlJSScope::hasInterface(const QString &name) const
this, [&](const QQmlJSScope *scope) { return scope->m_interfaceNames.contains(name); });
}
+void QQmlJSScope::setBaseTypeName(const QString &baseTypeName)
+{
+ m_flags.setFlag(HasBaseTypeError, false);
+ m_baseTypeNameOrError = baseTypeName;
+}
+
+QString QQmlJSScope::baseTypeName() const
+{
+ return m_flags.testFlag(HasBaseTypeError) ? QString() : m_baseTypeNameOrError;
+}
+
+void QQmlJSScope::setBaseTypeError(const QString &baseTypeError)
+{
+ m_flags.setFlag(HasBaseTypeError);
+ m_baseTypeNameOrError = baseTypeError;
+}
+
+QString QQmlJSScope::baseTypeError() const
+{
+ return m_flags.testFlag(HasBaseTypeError) ? m_baseTypeNameOrError : QString();
+}
+
QString QQmlJSScope::attachedTypeName() const
{
QString name;
@@ -477,10 +603,10 @@ bool QQmlJSScope::isResolved() const
{
if (m_scopeType == ScopeType::AttachedPropertyScope
|| m_scopeType == ScopeType::GroupedPropertyScope) {
- return m_internalName.isEmpty() || !m_baseType.isNull();
+ return m_internalName.isEmpty() || !m_baseType.scope.isNull();
}
- return m_baseTypeName.isEmpty() || !m_baseType.isNull();
+ return m_baseTypeNameOrError.isEmpty() || !m_baseType.scope.isNull();
}
bool QQmlJSScope::isFullyResolved() const
@@ -497,10 +623,12 @@ bool QQmlJSScope::isFullyResolved() const
return baseResolved;
}
-QQmlJSScope::Export::Export(QString package, QString type, const QTypeRevision &version) :
+QQmlJSScope::Export::Export(
+ QString package, QString type, QTypeRevision version, QTypeRevision revision) :
m_package(std::move(package)),
m_type(std::move(type)),
- m_version(version)
+ m_version(std::move(version)),
+ m_revision(std::move(revision))
{
}
@@ -509,13 +637,12 @@ bool QQmlJSScope::Export::isValid() const
return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty();
}
-QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const
+void QDeferredFactory<QQmlJSScope>::populate(const QSharedPointer<QQmlJSScope> &scope) const
{
QQmlJSTypeReader typeReader(m_importer, m_filePath);
- QQmlJSScope::Ptr result = typeReader();
+ typeReader(scope);
m_importer->m_warnings.append(typeReader.errors());
- result->setInternalName(QFileInfo(m_filePath).baseName());
- return std::move(*result);
+ scope->setInternalName(QFileInfo(m_filePath).baseName());
}
bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
@@ -523,15 +650,11 @@ bool QQmlJSScope::canAssign(const QQmlJSScope::ConstPtr &derived) const
if (!derived)
return false;
- bool isBaseComponent = false;
- for (auto scope = this; scope; scope = scope->baseType().get()) {
- if (internalName() == u"QQmlComponent"_qs) {
- isBaseComponent = true;
- break;
- }
- }
+ bool isBaseComponent = causesImplicitComponentWrapping();
- for (auto scope = derived; !scope.isNull(); scope = scope->baseType()) {
+ QDuplicateTracker<QQmlJSScope::ConstPtr> seen;
+ for (auto scope = derived; !scope.isNull() && !seen.hasSeen(scope);
+ scope = scope->baseType()) {
if (isSameType(scope))
return true;
if (isBaseComponent && scope->internalName() == u"QObject"_qs)
diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h
index 3822cd9c32..e0d75dd2dc 100644
--- a/src/qmlcompiler/qqmljsscope_p.h
+++ b/src/qmlcompiler/qqmljsscope_p.h
@@ -67,7 +67,7 @@ public:
m_filePath(filePath), m_importer(importer)
{}
- QQmlJSScope create() const;
+ void populate(const QSharedPointer<QQmlJSScope> &scope) const;
bool isValid() const
{
@@ -81,7 +81,6 @@ private:
class QQmlJSScope
{
- Q_DISABLE_COPY(QQmlJSScope)
public:
QQmlJSScope(QQmlJSScope &&) = default;
QQmlJSScope &operator=(QQmlJSScope &&) = default;
@@ -115,7 +114,9 @@ public:
Script = 0x8,
CustomParser = 0x10,
Array = 0x20,
- InlineComponent = 0x40
+ InlineComponent = 0x40,
+ WrappedInImplicitComponent = 0x80,
+ HasBaseTypeError = 0x100
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAGS(Flags);
@@ -123,20 +124,36 @@ public:
class Export {
public:
Export() = default;
- Export(QString package, QString type, const QTypeRevision &version);
+ Export(QString package, QString type, QTypeRevision version, QTypeRevision revision);
bool isValid() const;
QString package() const { return m_package; }
QString type() const { return m_type; }
QTypeRevision version() const { return m_version; }
+ QTypeRevision revision() const { return m_revision; }
private:
QString m_package;
QString m_type;
QTypeRevision m_version;
+ QTypeRevision m_revision;
};
+ template<typename Pointer>
+ struct ExportedScope {
+ Pointer scope;
+ QList<QQmlJSScope::Export> exports;
+ };
+
+ template<typename Pointer>
+ struct ImportedScope {
+ Pointer scope;
+ QTypeRevision revision;
+ };
+
+ using ContextualTypes = QHash<QString, ImportedScope<ConstPtr>>;
+
struct JavaScriptIdentifier
{
enum Kind {
@@ -150,8 +167,8 @@ public:
QQmlJS::SourceLocation location;
};
- static QQmlJSScope::Ptr create(ScopeType type = QQmlJSScope::QMLScope,
- const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr());
+ static QQmlJSScope::Ptr create() { return QSharedPointer<QQmlJSScope>(new QQmlJSScope); }
+ static QQmlJSScope::Ptr clone(const QQmlJSScope::ConstPtr &origin);
static QQmlJSScope::ConstPtr findCurrentQMLScope(const QQmlJSScope::ConstPtr &scope);
QQmlJSScope::Ptr parentScope()
@@ -164,6 +181,8 @@ public:
return QQmlJSScope::WeakConstPtr(m_parentScope).toStrongRef();
}
+ static void reparent(const QQmlJSScope::Ptr &parentScope, const QQmlJSScope::Ptr &childScope);
+
void insertJSIdentifier(const QString &name, const JavaScriptIdentifier &identifier);
// inserts property as qml identifier as well as the corresponding
@@ -172,6 +191,7 @@ public:
bool isIdInCurrentScope(const QString &id) const;
ScopeType scopeType() const { return m_scopeType; }
+ void setScopeType(ScopeType type) { m_scopeType = type; }
void addOwnMethod(const QQmlJSMetaMethod &method) { m_methods.insert(method.methodName(), method); }
QMultiHash<QString, QQmlJSMetaMethod> ownMethods() const { return m_methods; }
@@ -201,8 +221,13 @@ public:
QString internalName() const { return m_internalName; }
void setInternalName(const QString &internalName) { m_internalName = internalName; }
- void addExport(const QString &name, const QString &package, const QTypeRevision &version);
+ bool causesImplicitComponentWrapping() const;
+ bool isComponentRootElement() const;
+
+ void addExport(const QString &name, const QString &package,
+ const QTypeRevision &version, const QTypeRevision &revision);
QList<Export> exports() const { return m_exports; }
+ void setExports(const QList<Export> &exports) { m_exports = exports; }
void setInterfaceNames(const QStringList& interfaces) { m_interfaceNames = interfaces; }
QStringList interfaceNames() const { return m_interfaceNames; }
@@ -212,9 +237,15 @@ public:
// If isComposite(), this is the QML/JS name of the prototype. Otherwise it's the
// relevant base class (in the hierarchy starting from QObject) of a C++ type.
- void setBaseTypeName(const QString &baseTypeName) { m_baseTypeName = baseTypeName; }
- QString baseTypeName() const { return m_baseTypeName; }
- QQmlJSScope::ConstPtr baseType() const { return m_baseType; }
+ void setBaseTypeName(const QString &baseTypeName);
+ QString baseTypeName() const;
+
+ QQmlJSScope::ConstPtr baseType() const { return m_baseType.scope; }
+ QTypeRevision baseTypeRevision() const { return m_baseType.revision; }
+
+ void clearBaseType() { m_baseType = {}; }
+ void setBaseTypeError(const QString &baseTypeError);
+ QString baseTypeError() const;
void addOwnProperty(const QQmlJSMetaProperty &prop) { m_properties.insert(prop.propertyName(), prop); }
QHash<QString, QQmlJSMetaProperty> ownProperties() const { return m_properties; }
@@ -292,6 +323,7 @@ public:
}
void setIsArrayScope(bool v) { m_flags.setFlag(Array, v); }
void setIsInlineComponent(bool v) { m_flags.setFlag(InlineComponent, v); }
+ void setIsWrappedInImplicitComponent(bool v) { m_flags.setFlag(WrappedInImplicitComponent, v); }
void setAccessSemantics(AccessSemantics semantics) { m_semantics = semantics; }
AccessSemantics accessSemantics() const { return m_semantics; }
@@ -316,9 +348,17 @@ public:
return result;
}
- static void resolveTypes(const QQmlJSScope::Ptr &self,
- const QHash<QString, ConstPtr> &contextualTypes,
- QSet<QString> *usedTypes = nullptr);
+ static QTypeRevision resolveTypes(
+ const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static void resolveNonEnumTypes(
+ const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static void resolveEnums(
+ const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ConstPtr &intType);
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation)
{
@@ -339,6 +379,16 @@ public:
return {};
}
+ static QTypeRevision nonCompositeBaseRevision(const ImportedScope<QQmlJSScope::ConstPtr> &scope)
+ {
+ for (auto base = scope; base.scope;
+ base = { base.scope->m_baseType.scope, base.scope->m_baseType.revision }) {
+ if (!base.scope->isComposite())
+ return base.revision;
+ }
+ return {};
+ }
+
/*!
\internal
Checks whether \a otherScope is the same type as this.
@@ -380,7 +430,19 @@ public:
bool isInCustomParserParent() const;
private:
- QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope = QQmlJSScope::Ptr());
+ QQmlJSScope() = default;
+ QQmlJSScope(const QQmlJSScope &) = default;
+ QQmlJSScope &operator=(const QQmlJSScope &) = default;
+
+ static ImportedScope<QQmlJSScope::ConstPtr> findType(
+ const QString &name, const ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes = nullptr);
+ static QTypeRevision resolveType(
+ const QQmlJSScope::Ptr &self, const ContextualTypes &contextualTypes,
+ QSet<QString> *usedTypes);
+ static void updateChildScope(
+ const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
+ const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes);
QHash<QString, JavaScriptIdentifier> m_jsIdentifiers;
@@ -395,8 +457,11 @@ private:
QString m_fileName;
QString m_internalName;
- QString m_baseTypeName;
- QQmlJSScope::WeakConstPtr m_baseType;
+ QString m_baseTypeNameOrError;
+
+ // We only need the revision for the base type as inheritance is
+ // the only relation between two types where the revisions matter.
+ ImportedScope<QQmlJSScope::WeakConstPtr> m_baseType;
ScopeType m_scopeType = QMLScope;
QList<Export> m_exports;
@@ -420,6 +485,9 @@ private:
QQmlJS::SourceLocation m_sourceLocation;
};
+using QQmlJSExportedScope = QQmlJSScope::ExportedScope<QQmlJSScope::Ptr>;
+using QQmlJSImportedScope = QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>;
+
QT_END_NAMESPACE
#endif // QQMLJSSCOPE_P_H
diff --git a/src/qmlcompiler/qqmljsscopesbyid_p.h b/src/qmlcompiler/qqmljsscopesbyid_p.h
new file mode 100644
index 0000000000..3abca0ed50
--- /dev/null
+++ b/src/qmlcompiler/qqmljsscopesbyid_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLJSSCOPESBYID_P_H
+#define QQMLJSSCOPESBYID_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 "qqmljsscope_p.h"
+
+#include <QtCore/qhash.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlJSScopesById
+{
+public:
+ QString id(const QQmlJSScope::ConstPtr &scope) const
+ {
+ for (auto it = m_scopesById.begin(), end = m_scopesById.end(); it != end; ++it) {
+ if (*it == scope)
+ return it.key();
+ }
+ return QString();
+ }
+
+ QQmlJSScope::ConstPtr scope(const QString &id, const QQmlJSScope::ConstPtr &referrer) const
+ {
+ Q_ASSERT(!id.isEmpty());
+ const QQmlJSScope::ConstPtr root = componentRoot(referrer);
+ const auto range = m_scopesById.equal_range(id);
+ for (auto it = range.first; it != range.second; ++it) {
+ if (componentRoot(*it) == root)
+ return *it;
+ }
+ return QQmlJSScope::ConstPtr();
+ }
+
+ void insert(const QString &id, const QQmlJSScope::ConstPtr &scope)
+ {
+ Q_ASSERT(!id.isEmpty());
+ m_scopesById.insert(id, scope);
+ }
+
+ void clear() { m_scopesById.clear(); }
+
+private:
+ static QQmlJSScope::ConstPtr componentRoot(const QQmlJSScope::ConstPtr &inner)
+ {
+ QQmlJSScope::ConstPtr scope = inner;
+ while (scope && !scope->isComponentRootElement() && !scope->isInlineComponent()) {
+ if (QQmlJSScope::ConstPtr parent = scope->parentScope())
+ scope = parent;
+ else
+ break;
+ }
+ return scope;
+ }
+
+ QMultiHash<QString, QQmlJSScope::ConstPtr> m_scopesById;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLJSSCOPESBYID_P_H
diff --git a/src/qmlcompiler/qqmljstypedescriptionreader.cpp b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
index 3a317fd452..04293fd14c 100644
--- a/src/qmlcompiler/qqmljstypedescriptionreader.cpp
+++ b/src/qmlcompiler/qqmljstypedescriptionreader.cpp
@@ -192,6 +192,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
{
QQmlJSScope::Ptr scope = QQmlJSScope::create();
+ UiScriptBinding *metaObjectRevisions = nullptr;
for (UiObjectMemberList *it = ast->initializer->members; it; it = it->next) {
UiObjectMember *member = it->member;
auto *component = cast<UiObjectDefinition *>(member);
@@ -225,7 +226,7 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
} else if (name == QLatin1String("interfaces")) {
readInterfaces(script, scope);
} else if (name == QLatin1String("exportMetaObjectRevisions")) {
- readMetaObjectRevisions(script, scope);
+ metaObjectRevisions = script;
} else if (name == QLatin1String("attachedType")) {
scope->setOwnAttachedTypeName(readStringBinding(script));
} else if (name == QLatin1String("valueType")) {
@@ -273,6 +274,8 @@ void QQmlJSTypeDescriptionReader::readComponent(UiObjectDefinition *ast)
return;
}
+ if (metaObjectRevisions)
+ readMetaObjectRevisions(metaObjectRevisions, scope);
m_objects->insert(scope->internalName(), scope);
}
@@ -296,7 +299,7 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
readParameter(component, &metaMethod);
} else {
addWarning(component->firstSourceLocation(),
- tr("Expected only Parameter object definitions."));
+ tr("Expected only Parameter in object definitions."));
}
} else if (script) {
QString name = toString(script->qualifiedId);
@@ -308,9 +311,16 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
metaMethod.setRevision(readIntBinding(script));
} else if (name == QLatin1String("isConstructor")) {
metaMethod.setIsConstructor(true);
+ } else if (name == QLatin1String("isList")) {
+ // TODO: Theoretically this can happen. QQmlJSMetaMethod should store it.
+ } else if (name == QLatin1String("isPointer")) {
+ // TODO: We don't need this information. We can probably drop all isPointer members
+ // once we make sure that the type information is always complete. The
+ // description of the type being referenced has access semantics after all.
} else {
addWarning(script->firstSourceLocation(),
- tr("Expected only name type, revision and isConstructor script bindings."));
+ tr("Expected only name, type, revision, isPointer, isList, and "
+ "isConstructor in script bindings."));
}
} else {
addWarning(member->firstSourceLocation(),
@@ -637,7 +647,7 @@ void QQmlJSTypeDescriptionReader::readExports(UiScriptBinding *ast, const QQmlJS
QString name = exp.mid(slashIdx + 1, spaceIdx - (slashIdx+1));
// ### relocatable exports where package is empty?
- scope->addExport(name, package, version);
+ scope->addExport(name, package, version, version);
}
}
@@ -664,8 +674,8 @@ void QQmlJSTypeDescriptionReader::readInterfaces(UiScriptBinding *ast, const QQm
scope->setInterfaceNames(list);
}
-void QQmlJSTypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast,
- const QQmlJSScope::Ptr &scope)
+void QQmlJSTypeDescriptionReader::readMetaObjectRevisions(
+ UiScriptBinding *ast, const QQmlJSScope::Ptr &scope)
{
Q_ASSERT(ast);
@@ -688,7 +698,8 @@ void QQmlJSTypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast,
}
int exportIndex = 0;
- const int exportCount = scope->exports().size();
+ QList<QQmlJSScope::Export> exports = scope->exports();
+ const int exportCount = exports.size();
for (PatternElementList *it = arrayLit->elements; it; it = it->next, ++exportIndex) {
auto *numberLit = cast<NumericLiteral *>(it->element->initializer);
if (!numberLit) {
@@ -712,16 +723,20 @@ void QQmlJSTypeDescriptionReader::readMetaObjectRevisions(UiScriptBinding *ast,
const QTypeRevision metaObjectVersion
= QTypeRevision::fromEncodedVersion(metaObjectRevision);
- const QTypeRevision exportVersion = scope->exports()[exportIndex].version();
+ const QQmlJSScope::Export &entry = exports.at(exportIndex);
+ const QTypeRevision exportVersion = entry.version();
if (metaObjectVersion != exportVersion) {
addWarning(numberLit->firstSourceLocation(),
- tr("Meta object revision and export version differ, ignoring the revision.\n"
+ tr("Meta object revision and export version differ.\n"
"Revision %1 corresponds to version %2.%3; it should be %4.%5.")
.arg(metaObjectRevision)
.arg(metaObjectVersion.majorVersion()).arg(metaObjectVersion.minorVersion())
.arg(exportVersion.majorVersion()).arg(exportVersion.minorVersion()));
+ exports[exportIndex] = QQmlJSScope::Export(
+ entry.package(), entry.type(), exportVersion, metaObjectVersion);
}
}
+ scope->setExports(exports);
}
void QQmlJSTypeDescriptionReader::readEnumValues(UiScriptBinding *ast, QQmlJSMetaEnum *metaEnum)
diff --git a/src/qmlcompiler/qqmljstypereader.cpp b/src/qmlcompiler/qqmljstypereader.cpp
index cd9d604044..d7e6999bcd 100644
--- a/src/qmlcompiler/qqmljstypereader.cpp
+++ b/src/qmlcompiler/qqmljstypereader.cpp
@@ -40,13 +40,13 @@
QT_BEGIN_NAMESPACE
-QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
+bool QQmlJSTypeReader::operator ()(const QSharedPointer<QQmlJSScope> &scope)
{
using namespace QQmlJS::AST;
const QFileInfo info { m_file };
- QString baseName = info.baseName();
- const QString scopeName = baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
- : baseName;
+ const QString baseName = info.baseName();
+ scope->setInternalName(baseName.endsWith(QStringLiteral(".ui")) ? baseName.chopped(3)
+ : baseName);
QQmlJS::Engine engine;
QQmlJS::Lexer lexer(&engine);
@@ -55,16 +55,10 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
const bool isESModule = lowerSuffix == QLatin1String("mjs");
const bool isJavaScript = isESModule || lowerSuffix == QLatin1String("js");
- auto errorResult = [&](){
- QQmlJSScope::Ptr result = QQmlJSScope::create(
- isJavaScript ? QQmlJSScope::JSLexicalScope : QQmlJSScope::QMLScope);
- result->setInternalName(scopeName);
- return result;
- };
QFile file(m_file);
if (!file.open(QFile::ReadOnly))
- return errorResult();
+ return false;
QString code = QString::fromUtf8(file.readAll());
file.close();
@@ -76,21 +70,19 @@ QQmlJSScope::Ptr QQmlJSTypeReader::operator()()
: parser.parseProgram())
: parser.parse();
if (!success)
- return errorResult();
+ return false;
QQmlJS::AST::Node *rootNode = parser.rootNode();
if (!rootNode)
- return errorResult();
+ return false;
QQmlJSImportVisitor membersVisitor(
- m_importer,
+ scope, m_importer,
QQmlJSImportVisitor::implicitImportDirectory(
m_file, m_importer->resourceFileMapper()),
m_qmltypesFiles, m_file, code);
rootNode->accept(&membersVisitor);
- auto result = membersVisitor.result();
- result->setInternalName(scopeName);
- return result;
+ return true;
}
QT_END_NAMESPACE
diff --git a/src/qmlcompiler/qqmljstypereader_p.h b/src/qmlcompiler/qqmljstypereader_p.h
index 08c4ff782b..8094f0d9b1 100644
--- a/src/qmlcompiler/qqmljstypereader_p.h
+++ b/src/qmlcompiler/qqmljstypereader_p.h
@@ -61,7 +61,7 @@ public:
, m_qmltypesFiles(qmltypesFiles)
{}
- QQmlJSScope::Ptr operator()();
+ bool operator()(const QSharedPointer<QQmlJSScope> &scope);
QList<QQmlJS::DiagnosticMessage> errors() const { return m_errors; }
private:
diff --git a/src/qmldebug/CMakeLists.txt b/src/qmldebug/CMakeLists.txt
index 090585497c..fe8f7febce 100644
--- a/src/qmldebug/CMakeLists.txt
+++ b/src/qmldebug/CMakeLists.txt
@@ -26,7 +26,7 @@ qt_internal_add_module(QmlDebugPrivate
qqmlprofilerclientdefinitions_p.h
qqmlprofilerevent.cpp qqmlprofilerevent_p.h
qqmlprofilereventlocation.cpp qqmlprofilereventlocation_p.h
- qqmlprofilereventreceiver_p.h
+ qqmlprofilereventreceiver.cpp qqmlprofilereventreceiver_p.h
qqmlprofilereventtype.cpp qqmlprofilereventtype_p.h
qqmlprofilertypedevent.cpp qqmlprofilertypedevent_p.h
qv4debugclient.cpp qv4debugclient_p.h
diff --git a/src/qmldebug/qqmldebugclient.cpp b/src/qmldebug/qqmldebugclient.cpp
index 03123cc6e0..13785dd6db 100644
--- a/src/qmldebug/qqmldebugclient.cpp
+++ b/src/qmldebug/qqmldebugclient.cpp
@@ -123,3 +123,5 @@ void QQmlDebugClient::messageReceived(const QByteArray &message)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugclient_p.cpp"
diff --git a/src/qmldebug/qqmldebugmessageclient.cpp b/src/qmldebug/qqmldebugmessageclient.cpp
index 0892404194..ce7a3cb2bb 100644
--- a/src/qmldebug/qqmldebugmessageclient.cpp
+++ b/src/qmldebug/qqmldebugmessageclient.cpp
@@ -88,3 +88,5 @@ void QQmlDebugMessageClient::messageReceived(const QByteArray &data)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugmessageclient_p.cpp"
diff --git a/src/qmldebug/qqmldebugtranslationclient.cpp b/src/qmldebug/qqmldebugtranslationclient.cpp
index a93184b95d..c0656ea8e3 100644
--- a/src/qmldebug/qqmldebugtranslationclient.cpp
+++ b/src/qmldebug/qqmldebugtranslationclient.cpp
@@ -59,7 +59,7 @@ void QQmlDebugTranslationClient::messageReceived(const QByteArray &message)
packet >> type;
switch (type) {
- case QQmlDebugTranslation::Reply::MissingTranslations: {
+ case QQmlDebugTranslation::Reply::TranslationIssues: {
packet >> translationIssues;
break;
}
@@ -83,3 +83,5 @@ void QQmlDebugTranslationClient::messageReceived(const QByteArray &message)
}
QT_END_NAMESPACE
+
+#include "moc_qqmldebugtranslationclient_p.cpp"
diff --git a/src/qmldebug/qqmlenginedebugclient.cpp b/src/qmldebug/qqmlenginedebugclient.cpp
index 0ca3f573d9..fd467337d8 100644
--- a/src/qmldebug/qqmlenginedebugclient.cpp
+++ b/src/qmldebug/qqmlenginedebugclient.cpp
@@ -566,3 +566,5 @@ qint32 QQmlEngineDebugClient::getId()
}
QT_END_NAMESPACE
+
+#include "moc_qqmlenginedebugclient_p.cpp"
diff --git a/src/qmldebug/qqmlinspectorclient.cpp b/src/qmldebug/qqmlinspectorclient.cpp
index 1de52bd0c1..a3f5c68f0d 100644
--- a/src/qmldebug/qqmlinspectorclient.cpp
+++ b/src/qmldebug/qqmlinspectorclient.cpp
@@ -148,3 +148,5 @@ void QQmlInspectorClient::messageReceived(const QByteArray &message)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlinspectorclient_p.cpp"
diff --git a/src/qmldebug/qqmlpreviewclient.cpp b/src/qmldebug/qqmlpreviewclient.cpp
index abda548d01..da12cca522 100644
--- a/src/qmldebug/qqmlpreviewclient.cpp
+++ b/src/qmldebug/qqmlpreviewclient.cpp
@@ -130,3 +130,5 @@ void QQmlPreviewClient::triggerZoom(float factor)
}
QT_END_NAMESPACE
+
+#include "moc_qqmlpreviewclient_p.cpp"
diff --git a/src/qmldebug/qqmlprofilereventreceiver.cpp b/src/qmldebug/qqmlprofilereventreceiver.cpp
new file mode 100644
index 0000000000..cb88f821f8
--- /dev/null
+++ b/src/qmldebug/qqmlprofilereventreceiver.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlprofilereventreceiver_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQmlProfilerEventReceiver::~QQmlProfilerEventReceiver()
+ = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qqmlprofilereventreceiver_p.cpp"
diff --git a/src/qmldebug/qqmlprofilereventreceiver_p.h b/src/qmldebug/qqmlprofilereventreceiver_p.h
index defe64a42e..45d9abf71d 100644
--- a/src/qmldebug/qqmlprofilereventreceiver_p.h
+++ b/src/qmldebug/qqmlprofilereventreceiver_p.h
@@ -62,7 +62,8 @@ class QQmlProfilerEventReceiver : public QObject
{
Q_OBJECT
public:
- QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {}
+ explicit QQmlProfilerEventReceiver(QObject *parent = nullptr) : QObject(parent) {}
+ ~QQmlProfilerEventReceiver() override;
virtual int numLoadedEventTypes() const = 0;
virtual void addEventType(const QQmlProfilerEventType &type) = 0;
diff --git a/src/qmldebug/qv4debugclient.cpp b/src/qmldebug/qv4debugclient.cpp
index 76c2f1ebea..127e4a405e 100644
--- a/src/qmldebug/qv4debugclient.cpp
+++ b/src/qmldebug/qv4debugclient.cpp
@@ -576,3 +576,5 @@ QByteArray QV4DebugClientPrivate::packMessage(const QByteArray &type, const QJso
}
QT_END_NAMESPACE
+
+#include "moc_qv4debugclient_p.cpp"
diff --git a/src/qmldevtools/CMakeLists.txt b/src/qmldevtools/CMakeLists.txt
index abe12adfe5..aaec48a33c 100644
--- a/src/qmldevtools/CMakeLists.txt
+++ b/src/qmldevtools/CMakeLists.txt
@@ -67,10 +67,10 @@ if(QT_FEATURE_framework)
)
else()
set(_qml_dev_tools_private_includes
- $<BUILD_INTERFACE:${qml_module_include_dir}>
- $<BUILD_INTERFACE:${qml_module_repo_include_dir}>
- $<BUILD_INTERFACE:${qml_module_include_dir}/${PROJECT_VERSION}>
- $<BUILD_INTERFACE:${qml_module_include_dir}/${PROJECT_VERSION}/${qml_module}>
+ $<BUILD_INTERFACE:${qml_module_build_interface_include_dir}>
+ $<BUILD_INTERFACE:${qml_repo_build_interface_include_dir}>
+ $<BUILD_INTERFACE:${qml_module_build_interface_versioned_include_dir}>
+ $<BUILD_INTERFACE:${qml_module_build_interface_versioned_inner_include_dir}>
)
endif()
target_include_directories(QmlDevToolsPrivate PUBLIC ${_qml_dev_tools_private_includes})
@@ -83,13 +83,17 @@ if(QT_FEATURE_framework)
)
else()
set(_qml_dev_tools_public_includes
- $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${qml_module}>
- $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${qml_module}/${PROJECT_VERSION}>
- $<INSTALL_INTERFACE:${INSTALL_INCLUDEDIR}/${qml_module}/${PROJECT_VERSION}/${qml_module}>
+ $<INSTALL_INTERFACE:${qml_module_install_interface_include_dir}>
+ $<INSTALL_INTERFACE:${qml_module_install_interface_versioned_include_dir}>
+ $<INSTALL_INTERFACE:${qml_module_install_interface_versioned_inner_include_dir}>
)
endif()
target_include_directories(QmlDevToolsPrivate PUBLIC ${_qml_dev_tools_public_includes})
+set_target_properties(QmlDevToolsPrivate
+ PROPERTIES EXTRA_INCLUDE_DIRECTORIES
+ "${_qml_dev_tools_public_includes}${_qml_dev_tools_private_includes}"
+)
# We build the qlalr sources into qmldevtools, so there's no link-time
# dependency to QtQml. However we also include files in QmlDevToolsPrivate such
# as qqmlirbuilder.cpp that include <private/qqmljsgrammar_p.h> that
diff --git a/src/qmldom/qqmldomattachedinfo.cpp b/src/qmldom/qqmldomattachedinfo.cpp
index 707aae4283..eb48640d90 100644
--- a/src/qmldom/qqmldomattachedinfo.cpp
+++ b/src/qmldom/qqmldomattachedinfo.cpp
@@ -369,3 +369,5 @@ bool UpdatedScriptExpression::visitTree(Tree base, function_ref<bool(Path, Tree)
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomattachedinfo_p.cpp"
diff --git a/src/qmldom/qqmldomcomments.cpp b/src/qmldom/qqmldomcomments.cpp
index af58b6d821..7edcc0c9d9 100644
--- a/src/qmldom/qqmldomcomments.cpp
+++ b/src/qmldom/qqmldomcomments.cpp
@@ -555,7 +555,7 @@ void AstComments::collectComments(std::shared_ptr<Engine> engine, AST::Node *n,
}
if (iPre == 0)
preNewline = 1;
- quint32 iPost = cLoc.end();
+ qsizetype iPost = cLoc.end();
while (iPost < code.size()) {
QChar c = code.at(iPost);
if (!c.isSpace()) {
diff --git a/src/qmldom/qqmldomelements.cpp b/src/qmldom/qqmldomelements.cpp
index 914c72e34f..9a9a186833 100644
--- a/src/qmldom/qqmldomelements.cpp
+++ b/src/qmldom/qqmldomelements.cpp
@@ -57,6 +57,7 @@
#include <QtCore/QBasicMutex>
#include <optional>
+#include <limits>
QT_BEGIN_NAMESPACE
@@ -653,9 +654,14 @@ MutableDomItem QmlObject::addMethod(MutableDomItem &self, MethodInfo functionDef
void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
{
+ const quint32 posOfNewElements = std::numeric_limits<quint32>::max();
bool isRootObject = pathFromOwner().length() == 5
&& pathFromOwner()[0] == Path::Field(Fields::components)
&& pathFromOwner()[3] == Path::Field(Fields::objects);
+ QString code;
+ DomItem owner = self.owner();
+ if (std::shared_ptr<QmlFile> qmlFilePtr = self.ownerAs<QmlFile>())
+ code = qmlFilePtr->code();
ow.writeRegion(u"name", name());
if (!onTarget.isEmpty())
ow.space().writeRegion(u"on", u"on").space().writeRegion(u"onTarget", onTarget).space();
@@ -678,10 +684,10 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
DomItem component;
if (isRootObject)
component = self.containingObject();
- auto startLoc = [](FileLocations::Tree l) {
+ auto startLoc = [&](FileLocations::Tree l) {
if (l)
return l->info().fullRegion;
- return SourceLocation(~quint32(0), 0, 0, 0);
+ return SourceLocation(posOfNewElements, 0, 0, 0);
};
if (ow.lineWriter.options().attributesSequence
== LineWriterOptions::AttributesSequence::Preserve) {
@@ -749,10 +755,22 @@ void QmlObject::writeOut(DomItem &self, OutWriter &ow, QString onTarget) const
qsizetype iAttr = 0;
while (iAttr != attribs.size()) {
auto &el = attribs[iAttr++];
- if (iAttr > 1 && el.second.internalKind() != attribs[iAttr - 2].second.internalKind())
- ow.ensureNewline(2);
- else
- ow.ensureNewline();
+ // check for an empty line before the current element, and preserve it
+ int preNewlines = 0;
+ quint32 start = el.first.offset;
+ if (start != posOfNewElements && size_t(code.size()) >= start) {
+ while (start != 0) {
+ QChar c = code.at(--start);
+ if (c == u'\n') {
+ if (++preNewlines == 2)
+ break;
+ } else if (!c.isSpace())
+ break;
+ }
+ }
+ if (preNewlines == 0)
+ ++preNewlines;
+ ow.ensureNewline(preNewlines);
if (el.second.internalKind() == DomType::PropertyDefinition && iAttr != attribs.size()
&& el.first.offset != ~quint32(0)) {
DomItem b;
@@ -1197,9 +1215,10 @@ void EnumDecl::writeOut(DomItem &self, OutWriter &ow) const
QList<Path> ImportScope::allSources(DomItem &self) const
{
- DomItem env = self.environment();
+ DomItem top = self.top();
+ DomItem env = top.environment();
Path selfPath = self.canonicalPath().field(Fields::allSources);
- RefCacheEntry cached = RefCacheEntry::forPath(env, selfPath);
+ RefCacheEntry cached = (env ? RefCacheEntry::forPath(env, selfPath) : RefCacheEntry());
if (cached.cached == RefCacheEntry::Cached::All)
return cached.canonicalPaths;
QList<Path> res;
@@ -1211,7 +1230,7 @@ QList<Path> ImportScope::allSources(DomItem &self) const
continue;
knownPaths.insert(pNow);
res.append(pNow);
- DomItem sourceBase = env.path(pNow);
+ DomItem sourceBase = top.path(pNow);
for (DomItem autoExp : sourceBase.field(Fields::autoExports).values()) {
if (const ModuleAutoExport *autoExpPtr = autoExp.as<ModuleAutoExport>()) {
Path newSource;
@@ -1241,7 +1260,8 @@ QList<Path> ImportScope::allSources(DomItem &self) const
}
}
}
- RefCacheEntry::addForPath(env, selfPath, RefCacheEntry { RefCacheEntry::Cached::All, res });
+ if (env)
+ RefCacheEntry::addForPath(env, selfPath, RefCacheEntry { RefCacheEntry::Cached::All, res });
return res;
}
@@ -1447,10 +1467,10 @@ class FirstNodeVisitor : public VisitAll
{
public:
quint32 minStart = 0;
- quint32 maxEnd = ~quint32(0);
+ quint32 maxEnd = std::numeric_limits<quint32>::max();
AST::Node *firstNodeInRange = nullptr;
- FirstNodeVisitor(quint32 minStart = 0, quint32 maxEnd = ~quint32(0))
+ FirstNodeVisitor(quint32 minStart = 0, quint32 maxEnd = std::numeric_limits<quint32>::max())
: minStart(minStart), maxEnd(maxEnd)
{
}
@@ -1769,3 +1789,5 @@ void EnumItem::writeOut(DomItem &self, OutWriter &ow) const
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomelements_p.cpp"
diff --git a/src/qmldom/qqmldomelements_p.h b/src/qmldom/qqmldomelements_p.h
index 69c2cc1a7d..023883dfd6 100644
--- a/src/qmldom/qqmldomelements_p.h
+++ b/src/qmldom/qqmldomelements_p.h
@@ -726,7 +726,6 @@ public:
: CommentableDomElement(pathFromOwner), m_name(name), m_values(values)
{
}
- EnumDecl &operator=(const EnumDecl &) = default;
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
@@ -766,7 +765,6 @@ public:
DomType kind() const override { return kindValue; }
QmlObject(Path pathFromOwner = Path());
- QmlObject &operator=(const QmlObject &) = default;
bool iterateDirectSubpaths(DomItem &self, DirectVisitor) override;
bool iterateBaseDirectSubpaths(DomItem &self, DirectVisitor);
QList<QString> fields() const;
diff --git a/src/qmldom/qqmldomerrormessage.cpp b/src/qmldom/qqmldomerrormessage.cpp
index e621ac775f..450ae558b8 100644
--- a/src/qmldom/qqmldomerrormessage.cpp
+++ b/src/qmldom/qqmldomerrormessage.cpp
@@ -560,3 +560,5 @@ ErrorLevel errorLevelFromQtMsgType(QtMsgType msgType)
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomerrormessage_p.cpp"
diff --git a/src/qmldom/qqmldomerrormessage_p.h b/src/qmldom/qqmldomerrormessage_p.h
index fc3e0a2e11..3e7233125e 100644
--- a/src/qmldom/qqmldomerrormessage_p.h
+++ b/src/qmldom/qqmldomerrormessage_p.h
@@ -160,6 +160,46 @@ public:
void dump(Sink s) const;
QString toString() const;
QCborMap toCbor() const;
+ friend int compare(const ErrorMessage &msg1, const ErrorMessage &msg2)
+ {
+ int c;
+ c = msg1.location.offset - msg2.location.offset;
+ if (c != 0)
+ return c;
+ c = msg1.location.startLine - msg2.location.startLine;
+ if (c != 0)
+ return c;
+ c = msg1.errorId.compare(msg2.errorId);
+ if (c != 0)
+ return c;
+ if (!msg1.errorId.isEmpty())
+ return 0;
+ c = msg1.message.compare(msg2.message);
+ if (c != 0)
+ return c;
+ c = msg1.file.compare(msg2.file);
+ if (c != 0)
+ return c;
+ c = Path::cmp(msg1.path, msg2.path);
+ if (c != 0)
+ return c;
+ c = int(msg1.level) - int(msg2.level);
+ if (c != 0)
+ return c;
+ c = int(msg1.errorGroups.groups.size() - msg2.errorGroups.groups.size());
+ if (c != 0)
+ return c;
+ for (qsizetype i = 0; i < msg1.errorGroups.groups.size(); ++i) {
+ c = msg1.errorGroups.groups[i].groupId().compare(msg2.errorGroups.groups[i].groupId());
+ if (c != 0)
+ return c;
+ }
+ c = msg1.location.length - msg2.location.length;
+ if (c != 0)
+ return c;
+ c = msg1.location.startColumn - msg2.location.startColumn;
+ return c;
+ }
QLatin1String errorId;
QString message;
@@ -171,13 +211,26 @@ public:
};
inline bool operator !=(const ErrorMessage &e1, const ErrorMessage &e2) {
- return e1.errorId != e2.errorId || e1.message != e2.message || e1.errorGroups != e2.errorGroups
- || e1.level != e2.level || e1.path != e2.path || e1.file != e2.file
- || e1.location.startLine != e2.location.startLine || e1.location.offset != e2.location.offset
- || e1.location.startColumn != e2.location.startColumn || e1.location.length != e2.location.length;
+ return compare(e1, e2) != 0;
}
inline bool operator ==(const ErrorMessage &e1, const ErrorMessage &e2) {
- return !(e1 != e2);
+ return compare(e1, e2) == 0;
+}
+inline bool operator<(const ErrorMessage &e1, const ErrorMessage &e2)
+{
+ return compare(e1, e2) < 0;
+}
+inline bool operator<=(const ErrorMessage &e1, const ErrorMessage &e2)
+{
+ return compare(e1, e2) <= 0;
+}
+inline bool operator>(const ErrorMessage &e1, const ErrorMessage &e2)
+{
+ return compare(e1, e2) > 0;
+}
+inline bool operator>=(const ErrorMessage &e1, const ErrorMessage &e2)
+{
+ return compare(e1, e2) >= 0;
}
QMLDOM_EXPORT void silentError(const ErrorMessage &);
diff --git a/src/qmldom/qqmldomfieldfilter.cpp b/src/qmldom/qqmldomfieldfilter.cpp
index 3fa39b5b49..1ea27e0ee5 100644
--- a/src/qmldom/qqmldomfieldfilter.cpp
+++ b/src/qmldom/qqmldomfieldfilter.cpp
@@ -237,3 +237,5 @@ void FieldFilter::setFiltred()
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomfieldfilter_p.cpp"
diff --git a/src/qmldom/qqmldomfilewriter.cpp b/src/qmldom/qqmldomfilewriter.cpp
index b24e5518ba..b7b0e21d97 100644
--- a/src/qmldom/qqmldomfilewriter.cpp
+++ b/src/qmldom/qqmldomfilewriter.cpp
@@ -166,3 +166,5 @@ FileWriter::Status FileWriter::write(QString tFile, function_ref<bool(QTextStrea
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomfilewriter_p.cpp"
diff --git a/src/qmldom/qqmldomitem.cpp b/src/qmldom/qqmldomitem.cpp
index 079fa5678e..3a3ab7bb26 100644
--- a/src/qmldom/qqmldomitem.cpp
+++ b/src/qmldom/qqmldomitem.cpp
@@ -1927,14 +1927,23 @@ MutableDomItem DomItem::makeCopy(DomItem::CopyOption option)
return MutableDomItem(newItem.path(pathFromOwner()));
}
DomItem env = environment();
- std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>();
- Q_ASSERT(envPtr);
- std::shared_ptr<DomEnvironment> newEnvPtr(
- new DomEnvironment(envPtr, envPtr->loadPaths(), envPtr->options()));
- DomBase *eBase = envPtr.get();
- if (std::holds_alternative<DomEnvironment *>(m_element) && eBase
- && std::get<DomEnvironment *>(m_element) == eBase)
- return MutableDomItem(DomItem(newEnvPtr));
+ std::shared_ptr<DomEnvironment> newEnvPtr;
+ if (std::shared_ptr<DomEnvironment> envPtr = env.ownerAs<DomEnvironment>()) {
+ newEnvPtr = std::shared_ptr<DomEnvironment>(
+ new DomEnvironment(envPtr, envPtr->loadPaths(), envPtr->options()));
+ DomBase *eBase = envPtr.get();
+ if (std::holds_alternative<DomEnvironment *>(m_element) && eBase
+ && std::get<DomEnvironment *>(m_element) == eBase)
+ return MutableDomItem(DomItem(newEnvPtr));
+ } else if (std::shared_ptr<DomUniverse> univPtr = top().ownerAs<DomUniverse>()) {
+ newEnvPtr = std::shared_ptr<DomEnvironment>(new DomEnvironment(
+ QStringList(),
+ DomEnvironment::Option::SingleThreaded | DomEnvironment::Option::NoDependencies,
+ univPtr));
+ } else {
+ Q_ASSERT(false);
+ return {};
+ }
DomItem newItem = std::visit(
[this, newEnvPtr, &o](auto &&el) {
auto copyPtr = el->makeCopy(o);
@@ -2279,21 +2288,23 @@ DomItem::DomItem(std::shared_ptr<DomUniverse> universePtr):
}
void DomItem::loadFile(QString canonicalFilePath, QString logicalPath, QString code,
- QDateTime codeDate, DomTop::Callback callback, LoadOptions loadOptions)
+ QDateTime codeDate, DomTop::Callback callback, LoadOptions loadOptions,
+ std::optional<DomType> fileType)
{
DomItem topEl = top();
if (topEl.internalKind() == DomType::DomEnvironment
|| topEl.internalKind() == DomType::DomUniverse) {
if (auto univ = topEl.ownerAs<DomUniverse>())
univ->loadFile(*this, canonicalFilePath, logicalPath, code, codeDate, callback,
- loadOptions);
+ loadOptions, fileType);
else if (auto env = topEl.ownerAs<DomEnvironment>()) {
if (env->options() & DomEnvironment::Option::NoDependencies)
env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate, callback,
- DomTop::Callback(), DomTop::Callback(), loadOptions);
+ DomTop::Callback(), DomTop::Callback(), loadOptions, fileType);
else
env->loadFile(topEl, canonicalFilePath, logicalPath, code, codeDate,
- DomTop::Callback(), DomTop::Callback(), callback, loadOptions);
+ DomTop::Callback(), DomTop::Callback(), callback, loadOptions,
+ fileType);
} else
Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed");
} else {
@@ -2303,7 +2314,7 @@ void DomItem::loadFile(QString canonicalFilePath, QString logicalPath, QString c
}
void DomItem::loadFile(QString filePath, QString logicalPath, DomTop::Callback callback,
- LoadOptions loadOptions)
+ LoadOptions loadOptions, std::optional<DomType> fileType)
{
DomItem topEl = top();
if (topEl.internalKind() == DomType::DomEnvironment
@@ -2313,10 +2324,10 @@ void DomItem::loadFile(QString filePath, QString logicalPath, DomTop::Callback c
else if (auto env = topEl.ownerAs<DomEnvironment>()) {
if (env->options() & DomEnvironment::Option::NoDependencies)
env->loadFile(topEl, filePath, logicalPath, callback, DomTop::Callback(),
- DomTop::Callback(), loadOptions);
+ DomTop::Callback(), loadOptions, fileType);
else
env->loadFile(topEl, filePath, logicalPath, DomTop::Callback(), DomTop::Callback(),
- callback, loadOptions);
+ callback, loadOptions, fileType);
} else
Q_ASSERT(false && "expected either DomUniverse or DomEnvironment cast to succeed");
} else {
@@ -2727,26 +2738,28 @@ DomItem Reference::get(DomItem &self, ErrorHandler h, QList<Path> *visitedRefs)
Path cachedPath;
if (shouldCache()) {
env = self.environment();
- selfPath = self.canonicalPath();
- RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
- switch (cached.cached) {
- case RefCacheEntry::Cached::None:
- break;
- case RefCacheEntry::Cached::First:
- case RefCacheEntry::Cached::All:
- if (!cached.canonicalPaths.isEmpty())
- cachedPath = cached.canonicalPaths.first();
- else
- return res;
- break;
- }
- if (cachedPath) {
- res = env.path(cachedPath);
- if (!res)
- qCWarning(refLog) << "referenceCache outdated, reference at " << selfPath
- << " leads to invalid path " << cachedPath;
- else
- return res;
+ if (env) {
+ selfPath = self.canonicalPath();
+ RefCacheEntry cached = RefCacheEntry::forPath(self, selfPath);
+ switch (cached.cached) {
+ case RefCacheEntry::Cached::None:
+ break;
+ case RefCacheEntry::Cached::First:
+ case RefCacheEntry::Cached::All:
+ if (!cached.canonicalPaths.isEmpty())
+ cachedPath = cached.canonicalPaths.first();
+ else
+ return res;
+ break;
+ }
+ if (cachedPath) {
+ res = env.path(cachedPath);
+ if (!res)
+ qCWarning(refLog) << "referenceCache outdated, reference at " << selfPath
+ << " leads to invalid path " << cachedPath;
+ else
+ return res;
+ }
}
}
QList<Path> visitedRefsLocal;
@@ -2972,12 +2985,10 @@ void OwningItem::addError(DomItem &, ErrorMessage msg)
void OwningItem::addErrorLocal(ErrorMessage msg)
{
QMutexLocker l(mutex());
- auto it = m_errors.constFind(msg.path);
- while (it != m_errors.constEnd() && it->path == msg.path) {
- if (*it++ == msg)
- return;
- }
- m_errors.insert(msg.path, msg);
+ quint32 &c = m_errorsCounts[msg];
+ c += 1;
+ if (c == 1)
+ m_errors.insert(msg.path, msg);
}
void OwningItem::clearErrors(ErrorGroups groups)
@@ -3369,3 +3380,5 @@ void ListPBase::writeOut(DomItem &self, OutWriter &ow, bool compact) const
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomitem_p.cpp"
diff --git a/src/qmldom/qqmldomitem_p.h b/src/qmldom/qqmldomitem_p.h
index 469001709c..9388309bf7 100644
--- a/src/qmldom/qqmldomitem_p.h
+++ b/src/qmldom/qqmldomitem_p.h
@@ -588,7 +588,9 @@ public:
} else if constexpr (domTypeIsObjWrap(T::kindValue)) {
return m_value.value<T *>();
} else {
- Q_ASSERT_X(false, "SimpleObjectWrapT", "wrapping of unexpected type");
+ // need dependent static assert to not unconditially trigger
+ static_assert(!std::is_same_v<T, T>, "wrapping of unexpected type");
+ return nullptr; // necessary to avoid warnings on INTEGRITY
}
}
@@ -1036,11 +1038,11 @@ public:
DomItem(std::shared_ptr<DomUniverse>);
void loadFile(QString filePath, QString logicalPath,
- std::function<void(Path, DomItem &, DomItem &)> callback,
- LoadOptions loadOptions);
+ std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>());
void loadFile(QString canonicalFilePath, QString logicalPath, QString code, QDateTime codeDate,
- std::function<void(Path, DomItem &, DomItem &)> callback,
- LoadOptions loadOptions);
+ std::function<void(Path, DomItem &, DomItem &)> callback, LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>());
void loadModuleDependency(QString uri, Version v,
std::function<void(Path, DomItem &, DomItem &)> callback = nullptr,
ErrorHandler = nullptr);
@@ -1342,6 +1344,7 @@ private:
QDateTime m_lastDataUpdateAt;
QDateTime m_frozenAt;
QMultiMap<Path, ErrorMessage> m_errors;
+ QMap<ErrorMessage, quint32> m_errorsCounts;
};
template<typename T>
diff --git a/src/qmldom/qqmldomlinewriter.cpp b/src/qmldom/qqmldomlinewriter.cpp
index a2371c4ccd..6c04602a55 100644
--- a/src/qmldom/qqmldomlinewriter.cpp
+++ b/src/qmldom/qqmldomlinewriter.cpp
@@ -480,3 +480,5 @@ void LineWriter::commitLine(QString eol, TextAddType tType, int untilChar)
} // namespace Dom
} // namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomlinewriter_p.cpp"
diff --git a/src/qmldom/qqmldommoduleindex.cpp b/src/qmldom/qqmldommoduleindex.cpp
index 700537d287..47a2d9192f 100644
--- a/src/qmldom/qqmldommoduleindex.cpp
+++ b/src/qmldom/qqmldommoduleindex.cpp
@@ -145,7 +145,7 @@ ModuleIndex::~ModuleIndex()
auto it = scopes.begin();
auto end = scopes.end();
while (it != end) {
- free(*it);
+ delete *it;
++it;
}
}
diff --git a/src/qmldom/qqmldompath.cpp b/src/qmldom/qqmldompath.cpp
index c2ceeaf3cc..d901813f3a 100644
--- a/src/qmldom/qqmldompath.cpp
+++ b/src/qmldom/qqmldompath.cpp
@@ -205,24 +205,25 @@ int PathComponent::cmp(const PathComponent &p1, const PathComponent &p2)
} // namespace PathEls
-PathEls::PathComponent Path::component(int i) const
+const PathEls::PathComponent &Path::component(int i) const
{
+ static Component emptyComponent;
if (i < 0)
i += m_length;
if (i >= m_length || i < 0) {
Q_ASSERT(false && "index out of bounds");
- return Component();
+ return emptyComponent;
}
i = i - m_length - m_endOffset;
auto data = m_data.get();
while (data) {
i += data->components.length();
if (i >= 0)
- return data->components.at(i);
+ return qAsConst(data)->components[i];
data = data->parent.get();
}
Q_ASSERT(false && "Invalid data reached while resolving a seemengly valid index in Path (inconsisten Path object)");
- return Component();
+ return emptyComponent;
}
Path Path::operator[](int i) const
@@ -247,7 +248,7 @@ PathIterator Path::end() const
PathRoot Path::headRoot() const
{
- auto comp = component(0);
+ auto &comp = component(0);
if (PathEls::Root const * r = comp.base()->asRoot())
return r->contextKind;
return PathRoot::Other;
@@ -285,7 +286,7 @@ index_type Path::headIndex(index_type defaultValue) const
function<bool (DomItem)> Path::headFilter() const
{
- auto comp = component(0);
+ auto &comp = component(0);
if (PathEls::Filter const * f = comp.base()->asFilter()) {
return f->filterFunction;
}
@@ -939,7 +940,7 @@ void Path::dump(Sink sink) const
{
bool first = true;
for (int i = 0; i < m_length; ++i) {
- auto c = component(i);
+ auto &c = component(i);
if (!c.hasSquareBrackets()) {
if (!first || (c.kind() != Kind::Root && c.kind() != Kind::Current))
sink(u".");
@@ -997,3 +998,5 @@ Path Path::fromString(QString s, ErrorHandler errorHandler)
} // end namespace Dom
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldompath_p.cpp"
diff --git a/src/qmldom/qqmldompath_p.h b/src/qmldom/qqmldompath_p.h
index 7fe68428d7..f0fddcabea 100644
--- a/src/qmldom/qqmldompath_p.h
+++ b/src/qmldom/qqmldompath_p.h
@@ -124,7 +124,8 @@ public:
virtual const Filter *asFilter() const { return nullptr; }
};
-class Empty: public Base {
+class Empty final : public Base
+{
public:
Empty() = default;
Kind kind() const override { return Kind::Empty; }
@@ -133,7 +134,8 @@ public:
const Empty * asEmpty() const override { return this; }
};
-class Field: public Base {
+class Field final : public Base
+{
public:
Field() = default;
Field(QStringView n): fieldName(n) {}
@@ -147,7 +149,8 @@ public:
QStringView fieldName;
};
-class Index: public Base {
+class Index final : public Base
+{
public:
Index() = default;
Index(index_type i): indexValue(i) {}
@@ -161,7 +164,8 @@ public:
index_type indexValue = -1;
};
-class Key: public Base {
+class Key final : public Base
+{
public:
Key() = default;
Key(QString n) : keyValue(n) { }
@@ -180,7 +184,8 @@ public:
QString keyValue;
};
-class Root: public Base {
+class Root final : public Base
+{
public:
Root() = default;
Root(PathRoot r): contextKind(r), contextName() {}
@@ -229,7 +234,8 @@ public:
QStringView contextName;
};
-class Current: public Base {
+class Current final : public Base
+{
public:
Current() = default;
Current(PathCurrent c): contextKind(c) {}
@@ -283,7 +289,8 @@ public:
QStringView contextName;
};
-class Any: public Base {
+class Any final : public Base
+{
public:
Any() = default;
Kind kind() const override { return Kind::Any; }
@@ -293,7 +300,8 @@ public:
const Any *asAny() const override { return this; }
};
-class QMLDOM_EXPORT Filter: public Base {
+class QMLDOM_EXPORT Filter final : public Base
+{
public:
Filter() = default;
Filter(std::function<bool(DomItem)> f, QStringView filterDescription = u"<native code filter>");
@@ -718,10 +726,12 @@ public:
using iterator_category = std::forward_iterator_tag;
static int cmp(const Path &p1, const Path &p2);
- Component component(int i) const;
+
private:
+ const Component &component(int i) const;
explicit Path(quint16 endOffset, quint16 length, std::shared_ptr<PathEls::PathData> data);
friend class QQmlJS::Dom::PathEls::TestPaths;
+ friend class FieldFilter;
friend size_t qHash(const Path &, size_t);
Path noEndOffset() const;
@@ -762,8 +772,8 @@ public:
Path operator *() const { return currentEl.head(); }
PathIterator operator ++() { currentEl = currentEl.dropFront(); return *this; }
PathIterator operator ++(int) { PathIterator res{currentEl}; currentEl = currentEl.dropFront(); return res; }
- bool operator ==(const PathIterator &o) { return currentEl == o.currentEl; }
- bool operator !=(const PathIterator &o) { return currentEl != o.currentEl; }
+ bool operator ==(const PathIterator &o) const { return currentEl == o.currentEl; }
+ bool operator !=(const PathIterator &o) const { return currentEl != o.currentEl; }
};
class Source {
diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp
index d627af12ef..ee48a71c29 100644
--- a/src/qmldom/qqmldomreformatter.cpp
+++ b/src/qmldom/qqmldomreformatter.cpp
@@ -972,7 +972,11 @@ protected:
// to check
bool visit(TypeExpression *) override { return true; }
- bool visit(SuperLiteral *) override { return true; }
+ bool visit(SuperLiteral *) override
+ {
+ out("super");
+ return true;
+ }
bool visit(PatternProperty *) override { return true; }
bool visit(ComputedPropertyName *) override
{
@@ -989,7 +993,61 @@ protected:
}
bool visit(YieldExpression *) override { return true; }
bool visit(ClassExpression *) override { return true; }
- bool visit(ClassDeclaration *) override { return true; }
+
+ // Return false because we want to omit default function calls in accept0 implementation.
+ bool visit(ClassDeclaration *ast) override
+ {
+ preVisit(ast);
+ out(ast->classToken);
+ out(" ");
+ out(ast->name);
+ if (ast->heritage) {
+ out(" extends ");
+ accept(ast->heritage);
+ }
+ out(" {");
+ int baseIndent = lw.increaseIndent();
+ for (ClassElementList *it = ast->elements; it; it = it->next) {
+ PatternProperty *property = it->property;
+ lw.newline();
+ preVisit(property);
+ if (it->isStatic)
+ out("static ");
+ if (property->type == PatternProperty::Getter)
+ out("get ");
+ else if (property->type == PatternProperty::Setter)
+ out("set ");
+ FunctionExpression *f = AST::cast<FunctionExpression *>(property->initializer);
+ const bool scoped = f->lbraceToken.length != 0;
+ out(f->functionToken);
+ out(f->lparenToken);
+ accept(f->formals);
+ out(f->rparenToken);
+ out(f->lbraceToken);
+ if (scoped)
+ ++expressionDepth;
+ if (f->body) {
+ if (f->body->next || scoped) {
+ lnAcceptIndented(f->body);
+ lw.newline();
+ } else {
+ baseIndent = lw.increaseIndent(1);
+ accept(f->body);
+ lw.decreaseIndent(1, baseIndent);
+ }
+ }
+ if (scoped)
+ --expressionDepth;
+ out(f->rbraceToken);
+ lw.newline();
+ postVisit(property);
+ }
+ lw.decreaseIndent(1, baseIndent);
+ out("}");
+ postVisit(ast);
+ return false;
+ }
+
bool visit(ClassElementList *) override { return true; }
bool visit(Program *) override { return true; }
bool visit(NameSpaceImport *) override { return true; }
diff --git a/src/qmldom/qqmldomtop.cpp b/src/qmldom/qqmldomtop.cpp
index c41402d761..7d2500488b 100644
--- a/src/qmldom/qqmldomtop.cpp
+++ b/src/qmldom/qqmldomtop.cpp
@@ -48,7 +48,6 @@
#include <QtQml/private/qqmljsastvisitor_p.h>
#include <QtQml/private/qqmljsast_p.h>
-#include <QtCore/QAtomicInt>
#include <QtCore/QBasicMutex>
#include <QtCore/QCborArray>
#include <QtCore/QDebug>
@@ -157,11 +156,14 @@ DomUniverse::DomUniverse(QString universeName, Options options):
std::shared_ptr<DomUniverse> DomUniverse::guaranteeUniverse(std::shared_ptr<DomUniverse> univ)
{
- static QAtomicInt counter(0);
+ const auto next = [] {
+ static std::atomic<int> counter(0);
+ return counter.fetch_add(1, std::memory_order_relaxed) + 1;
+ };
if (univ)
return univ;
return std::shared_ptr<DomUniverse>(
- new DomUniverse(QLatin1String("universe") + QString::number(++counter)));
+ new DomUniverse(QLatin1String("universe") + QString::number(next())));
}
DomItem DomUniverse::create(QString universeName, Options options)
@@ -248,56 +250,58 @@ std::shared_ptr<OwningItem> DomUniverse::doCopy(DomItem &) const
}
void DomUniverse::loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback,
- LoadOptions loadOptions)
+ LoadOptions loadOptions, std::optional<DomType> fileType)
{
- loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0), callback, loadOptions);
+ loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0), callback,
+ loadOptions, fileType);
}
-void DomUniverse::loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath,
- QString code, QDateTime codeDate, Callback callback,
- LoadOptions loadOptions)
-{
- if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive) ||
- canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive) ||
- canonicalFilePath.endsWith(u".ui", Qt::CaseInsensitive)) {
- m_queue.enqueue(ParsingTask{
- QDateTime::currentDateTime(),
- loadOptions,
- DomType::QmlFile,
- canonicalFilePath,
- logicalPath,
- code,
- codeDate,
- self.ownerAs<DomUniverse>(),
- callback});
+static DomType fileTypeForPath(DomItem &self, QString canonicalFilePath)
+{
+ if (canonicalFilePath.endsWith(u".qml", Qt::CaseInsensitive)
+ || canonicalFilePath.endsWith(u".qmlannotation", Qt::CaseInsensitive)) {
+ return DomType::QmlFile;
} else if (canonicalFilePath.endsWith(u".qmltypes")) {
- m_queue.enqueue(ParsingTask{
- QDateTime::currentDateTime(),
- loadOptions,
- DomType::QmltypesFile,
- canonicalFilePath,
- logicalPath,
- code,
- codeDate,
- self.ownerAs<DomUniverse>(),
- callback});
- } else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(), Qt::CaseInsensitive) == 0) {
- m_queue.enqueue(ParsingTask{
- QDateTime::currentDateTime(),
- loadOptions,
- DomType::QmldirFile,
- canonicalFilePath,
- logicalPath,
- code,
- codeDate,
- self.ownerAs<DomUniverse>(),
- callback});
+ return DomType::QmltypesFile;
+ } else if (QStringView(u"qmldir").compare(QFileInfo(canonicalFilePath).fileName(),
+ Qt::CaseInsensitive)
+ == 0) {
+ return DomType::QmltypesFile;
} else if (QFileInfo(canonicalFilePath).isDir()) {
- m_queue.enqueue(ParsingTask { QDateTime::currentDateTime(), loadOptions,
- DomType::QmlDirectory, canonicalFilePath, logicalPath, code,
- codeDate, self.ownerAs<DomUniverse>(), callback });
+ return DomType::QmlDirectory;
} else {
- self.addError(myErrors().error(tr("Ignoring request to load file of unknown type %1, calling callback immediately").arg(canonicalFilePath)).handle());
+ self.addError(DomUniverse::myErrors()
+ .error(QCoreApplication::translate("Dom::filteTypeForPath",
+ "Could not detect type of file %1")
+ .arg(canonicalFilePath))
+ .handle());
+ }
+ return DomType::Empty;
+}
+
+void DomUniverse::loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath,
+ QString code, QDateTime codeDate, Callback callback,
+ LoadOptions loadOptions, std::optional<DomType> fileType)
+{
+ DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath));
+ switch (fType) {
+ case DomType::QmlFile:
+ case DomType::QmltypesFile:
+ case DomType::QmldirFile:
+ case DomType::QmlDirectory: {
+ // Protect the queue from concurrent access.
+ QMutexLocker l(mutex());
+ m_queue.enqueue(ParsingTask { QDateTime::currentDateTime(), loadOptions, fType,
+ canonicalFilePath, logicalPath, code, codeDate,
+ self.ownerAs<DomUniverse>(), callback });
+ break;
+ }
+ default:
+ self.addError(myErrors()
+ .error(tr("Ignoring request to load file %1 of unexpected type %2, "
+ "calling callback immediately")
+ .arg(canonicalFilePath, domTypeToString(fType)))
+ .handle());
Q_ASSERT(false && "loading non supported file type");
callback(Path(), DomItem::empty, DomItem::empty);
return;
@@ -350,7 +354,14 @@ updateEntry(DomItem &univ, std::shared_ptr<T> newItem,
void DomUniverse::execQueue()
{
- ParsingTask t = m_queue.dequeue();
+ ParsingTask t;
+ {
+ // Protect the queue from concurrent access.
+ QMutexLocker l(mutex());
+ if (m_queue.isEmpty())
+ return;
+ t = m_queue.dequeue();
+ }
shared_ptr<DomUniverse> topPtr = t.requestingUniverse.lock();
if (!topPtr) {
myErrors().error(tr("Ignoring callback for loading of %1: universe is not valid anymore").arg(t.canonicalPath)).handle();
@@ -626,7 +637,8 @@ void LoadInfo::advanceLoad(DomItem &self)
[this, self, dep](Path, DomItem &, DomItem &) mutable {
finishedLoadingDep(self, dep);
},
- nullptr, nullptr, LoadOption::DefaultLoad, self.errorHandler());
+ nullptr, nullptr, LoadOption::DefaultLoad, dep.fileType,
+ self.errorHandler());
else
Q_ASSERT(false && "missing environment");
} else {
@@ -746,12 +758,13 @@ void LoadInfo::doAddDependencies(DomItem &self)
DomItem import = currentImports.index(i);
if (const Import *importPtr = import.as<Import>()) {
if (!importPtr->filePath().isEmpty()) {
- addDependency(
- self,
- Dependency { QString(), importPtr->version, importPtr->filePath() });
+ addDependency(self,
+ Dependency { QString(), importPtr->version, importPtr->filePath(),
+ DomType::Empty });
} else {
addDependency(self,
- Dependency { importPtr->uri, importPtr->version, QString() });
+ Dependency { importPtr->uri, importPtr->version, QString(),
+ DomType::ModuleIndex });
}
}
}
@@ -763,7 +776,8 @@ void LoadInfo::doAddDependencies(DomItem &self)
Path canonicalPath = ref->referredObjectPath[2];
if (canonicalPath && !canonicalPath.headName().isEmpty())
addDependency(self,
- Dependency { QString(), Version(), canonicalPath.headName() });
+ Dependency { QString(), Version(), canonicalPath.headName(),
+ DomType::QmltypesFile });
}
}
DomItem currentQmlFiles = el.field(Fields::currentItem).field(Fields::qmlFiles);
@@ -772,9 +786,9 @@ void LoadInfo::doAddDependencies(DomItem &self)
if (const Reference *ref = el.as<Reference>()) {
Path canonicalPath = ref->referredObjectPath[2];
if (canonicalPath && !canonicalPath.headName().isEmpty())
- addDependency(
- self,
- Dependency { QString(), Version(), canonicalPath.headName() });
+ addDependency(self,
+ Dependency { QString(), Version(), canonicalPath.headName(),
+ DomType::QmlFile });
}
return true;
});
@@ -783,7 +797,9 @@ void LoadInfo::doAddDependencies(DomItem &self)
for (Path qmldirPath : elPtr->qmldirsToLoad(el)) {
Path canonicalPath = qmldirPath[2];
if (canonicalPath && !canonicalPath.headName().isEmpty())
- addDependency(self, Dependency { QString(), Version(), canonicalPath.headName() });
+ addDependency(self,
+ Dependency { QString(), Version(), canonicalPath.headName(),
+ DomType::QmldirFile });
}
} else if (!el) {
self.addError(DomEnvironment::myErrors().error(
@@ -1147,10 +1163,11 @@ std::shared_ptr<DomEnvironment> DomEnvironment::makeCopy(DomItem &self) const
void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath,
DomTop::Callback loadCallback, DomTop::Callback directDepsCallback,
- DomTop::Callback endCallback, LoadOptions loadOptions, ErrorHandler h)
+ DomTop::Callback endCallback, LoadOptions loadOptions,
+ std::optional<DomType> fileType, ErrorHandler h)
{
loadFile(self, filePath, logicalPath, QString(), QDateTime::fromMSecsSinceEpoch(0),
- loadCallback, directDepsCallback, endCallback, loadOptions, h);
+ loadCallback, directDepsCallback, endCallback, loadOptions, fileType, h);
}
std::shared_ptr<OwningItem> DomEnvironment::doCopy(DomItem &) const
@@ -1167,11 +1184,10 @@ std::shared_ptr<OwningItem> DomEnvironment::doCopy(DomItem &) const
void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPath, QString code,
QDateTime codeDate, Callback loadCallback,
Callback directDepsCallback, Callback endCallback,
- LoadOptions loadOptions, ErrorHandler h)
+ LoadOptions loadOptions, std::optional<DomType> fileType,
+ ErrorHandler h)
{
QFileInfo fileInfo(filePath);
- bool isDir = fileInfo.isDir();
- QString ext = fileInfo.suffix();
QString canonicalFilePath = fileInfo.canonicalFilePath();
if (canonicalFilePath.isEmpty()) {
if (code.isNull()) {
@@ -1190,7 +1206,9 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
}
}
shared_ptr<ExternalItemInfoBase> oldValue, newValue;
- if (isDir) {
+ DomType fType = (bool(fileType) ? (*fileType) : fileTypeForPath(self, canonicalFilePath));
+ switch (fType) {
+ case DomType::QmlDirectory: {
{
QMutexLocker l(mutex());
auto it = m_qmlDirectoryWithPath.find(canonicalFilePath);
@@ -1217,10 +1235,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
self.universe().loadFile(
canonicalFilePath, logicalPath, code, codeDate,
callbackForQmlDirectory(self, loadCallback, directDepsCallback, endCallback),
- loadOptions);
+ loadOptions, fType);
return;
}
- } else if (ext == u"qml" || ext == u"ui" || ext == u"qmlannotation") {
+ } break;
+ case DomType::QmlFile: {
{
QMutexLocker l(mutex());
auto it = m_qmlFileWithPath.find(canonicalFilePath);
@@ -1246,10 +1265,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
self.universe().loadFile(
canonicalFilePath, logicalPath, code, codeDate,
callbackForQmlFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions);
+ loadOptions, fType);
return;
}
- } else if (ext == u"qmltypes") {
+ } break;
+ case DomType::QmltypesFile: {
{
QMutexLocker l(mutex());
auto it = m_qmltypesFileWithPath.find(canonicalFilePath);
@@ -1276,10 +1296,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
self.universe().loadFile(
canonicalFilePath, logicalPath, code, codeDate,
callbackForQmltypesFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions);
+ loadOptions, fType);
return;
}
- } else if (fileInfo.fileName() == u"qmldir") {
+ } break;
+ case DomType::QmldirFile: {
{
QMutexLocker l(mutex());
auto it = m_qmldirFileWithPath.find(canonicalFilePath);
@@ -1305,10 +1326,11 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
self.universe().loadFile(
canonicalFilePath, logicalPath, code, codeDate,
callbackForQmldirFile(self, loadCallback, directDepsCallback, endCallback),
- loadOptions);
+ loadOptions, fType);
return;
}
- } else {
+ } break;
+ default: {
myErrors().error(tr("Unexpected file to load: '%1'").arg(filePath)).handle(h);
if (loadCallback)
loadCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
@@ -1317,6 +1339,7 @@ void DomEnvironment::loadFile(DomItem &self, QString filePath, QString logicalPa
if (endCallback)
endCallback(self.canonicalPath(), DomItem::empty, DomItem::empty);
return;
+ } break;
}
Path p = self.copy(newValue).canonicalPath();
std::shared_ptr<LoadInfo> lInfo = loadInfo(p);
@@ -2310,3 +2333,5 @@ bool RefCacheEntry::addForPath(DomItem &el, Path canonicalPath, const RefCacheEn
} // end namespace QQmlJS
QT_END_NAMESPACE
+
+#include "moc_qqmldomtop_p.cpp"
diff --git a/src/qmldom/qqmldomtop_p.h b/src/qmldom/qqmldomtop_p.h
index 4c905991af..eeb0038d09 100644
--- a/src/qmldom/qqmldomtop_p.h
+++ b/src/qmldom/qqmldomtop_p.h
@@ -61,6 +61,7 @@
#include <QtCore/QCborMap>
#include <memory>
+#include <optional>
QT_BEGIN_NAMESPACE
@@ -253,9 +254,11 @@ public:
}
void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback callback,
- LoadOptions loadOptions);
+ LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>());
void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code,
- QDateTime codeDate, Callback callback, LoadOptions loadOptions);
+ QDateTime codeDate, Callback callback, LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>());
void execQueue();
std::shared_ptr<ExternalItemPair<GlobalScope>> globalScopeWithName(QString name) const
@@ -517,6 +520,7 @@ public:
QString uri; // either dotted uri or file:, http: https: uri
Version version;
QString filePath; // for file deps
+ DomType fileType;
};
class QMLDOM_EXPORT LoadInfo final : public OwningItem
@@ -683,10 +687,13 @@ public:
void loadFile(DomItem &self, QString filePath, QString logicalPath, Callback loadCallback,
Callback directDepsCallback, Callback endCallback, LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>(),
ErrorHandler h = nullptr);
void loadFile(DomItem &self, QString canonicalFilePath, QString logicalPath, QString code,
QDateTime codeDate, Callback loadCallback, Callback directDepsCallback,
- Callback endCallback, LoadOptions loadOptions, ErrorHandler h = nullptr);
+ Callback endCallback, LoadOptions loadOptions,
+ std::optional<DomType> fileType = std::optional<DomType>(),
+ ErrorHandler h = nullptr);
void loadModuleDependency(DomItem &self, QString uri, Version v,
Callback loadCallback = nullptr, Callback endCallback = nullptr,
ErrorHandler = nullptr);
diff --git a/src/qmllocalstorage/qqmllocalstorage.cpp b/src/qmllocalstorage/qqmllocalstorage.cpp
index 565ebc0a07..8295b441df 100644
--- a/src/qmllocalstorage/qqmllocalstorage.cpp
+++ b/src/qmllocalstorage/qqmllocalstorage.cpp
@@ -526,7 +526,7 @@ through the data.
*/
/*!
- \qmlmodule QtQuick.LocalStorage 2.\QtMinorVersion
+ \qmlmodule QtQuick.LocalStorage
\title Qt Quick Local Storage QML Types
\ingroup qmlmodules
\brief Provides a JavaScript object singleton type for accessing a local
@@ -584,10 +584,10 @@ db = Sql.openDatabaseSync(identifier, version, description, estimated_size, call
\endqml
The above code returns the database identified by \e identifier. If the database does not already
-exist, it is created, and the function \e callback is called with the database as a parameter. \e
-identifier is the name of the physical file (with or without full path) containing the database. \e
-description and \e estimated_size are written to the INI file (described below), but are currently
-unused.
+exist, it is created, and the function \e callback is called with the database as a parameter.
+\e identifier is the name of the physical file (with or without relative path) containing the
+database. \e description and \e estimated_size are written to the INI file (described below), but
+are currently unused.
May throw exception with code property SQLException.DATABASE_ERR, or SQLException.VERSION_ERR.
@@ -636,7 +636,7 @@ If the callback throws exceptions, the transaction is rolled back.
Below you will find an example of a database transaction which catches exceptions.
-\quotefromfile localstorage/localstorage/Database.js
+\quotefromfile localstorage/Database.js
\skipuntil dbInit()
\printto dbGetHandle
@@ -692,7 +692,7 @@ SQLException.UNKNOWN_ERR.
See below for an example:
-\quotefromfile localstorage/localstorage/Database.js
+\quotefromfile localstorage/Database.js
\skipto dbReadAll()
\printto dbUpdate(Pdate
@@ -794,3 +794,5 @@ void QQmlLocalStorage::openDatabaseSync(QQmlV4Function *args)
}
QT_END_NAMESPACE
+
+#include "moc_qqmllocalstorage_p.cpp"
diff --git a/src/qmlmodels/CMakeLists.txt b/src/qmlmodels/CMakeLists.txt
index 3166e5d90c..41a1475365 100644
--- a/src/qmlmodels/CMakeLists.txt
+++ b/src/qmlmodels/CMakeLists.txt
@@ -27,6 +27,11 @@ qt_internal_add_qml_module(QmlModels
Qt::QmlPrivate
)
+qt_internal_extend_target(QmlModels CONDITION QT_FEATURE_qml_itemmodel
+ SOURCES
+ qqmlmodelindexvaluetype.cpp qqmlmodelindexvaluetype_p.h
+)
+
qt_internal_extend_target(QmlModels CONDITION QT_FEATURE_qml_object_model
SOURCES
qqmlinstantiator.cpp qqmlinstantiator_p.h
diff --git a/src/qmlmodels/doc/src/qtqmlmodel.qdoc b/src/qmlmodels/doc/src/qtqmlmodel.qdoc
index 33c648e87f..ea46bf7da9 100644
--- a/src/qmlmodels/doc/src/qtqmlmodel.qdoc
+++ b/src/qmlmodels/doc/src/qtqmlmodel.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQml.Models 2.\QtMinorVersion
+ \qmlmodule QtQml.Models
\title Qt QML Models QML Types
\ingroup qmlmodules
\brief Provides QML types for data models
diff --git a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
index 1058d87485..869c6a4fa9 100644
--- a/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
+++ b/src/qmlmodels/qqmlabstractdelegatecomponent.cpp
@@ -59,3 +59,5 @@ QVariant QQmlAbstractDelegateComponent::value(QQmlAdaptorModel *adaptorModel, in
}
QT_END_NAMESPACE
+
+#include "moc_qqmlabstractdelegatecomponent_p.cpp"
diff --git a/src/qmlmodels/qqmladaptormodel.cpp b/src/qmlmodels/qqmladaptormodel.cpp
index dc3ea8019e..f283271018 100644
--- a/src/qmlmodels/qqmladaptormodel.cpp
+++ b/src/qmlmodels/qqmladaptormodel.cpp
@@ -549,7 +549,8 @@ public:
metaObject.reset(builder.toMetaObject());
*static_cast<QMetaObject *>(this) = *metaObject;
- propertyCache.adopt(new QQmlPropertyCache(metaObject.data(), model.modelItemRevision));
+ propertyCache = QQmlPropertyCache::createStandalone(
+ metaObject.data(), model.modelItemRevision);
}
};
@@ -683,8 +684,8 @@ public:
{
VDMListDelegateDataType *dataType = const_cast<VDMListDelegateDataType *>(this);
if (!propertyCache) {
- dataType->propertyCache.adopt(new QQmlPropertyCache(
- &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision));
+ dataType->propertyCache = QQmlPropertyCache::createStandalone(
+ &QQmlDMListAccessorData::staticMetaObject, model.modelItemRevision);
}
return new QQmlDMListAccessorData(
@@ -962,30 +963,38 @@ QQmlAdaptorModel::~QQmlAdaptorModel()
accessors->cleanup(*this);
}
-void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *parent)
+void QQmlAdaptorModel::setModel(const QVariant &variant, QObject *)
{
accessors->cleanup(*this);
+ // Don't use variant anymore after this. list may transform it.
list.setList(variant);
+ modelStrongReference.clear();
+
if (QObject *object = qvariant_cast<QObject *>(list.list())) {
- setObject(object, parent);
+ if (QQmlData *ddata = QQmlData::get(object))
+ modelStrongReference = ddata->jsWrapper;
+ setObject(object);
if (qobject_cast<QAbstractItemModel *>(object))
accessors = new VDMAbstractItemModelDataType(this);
else
accessors = new VDMObjectDelegateDataType;
} else if (list.type() == QQmlListAccessor::ListProperty) {
- setObject(static_cast<const QQmlListReference *>(variant.constData())->object(), parent);
+ auto object = static_cast<const QQmlListReference *>(list.list().constData())->object();
+ if (QQmlData *ddata = QQmlData::get(object))
+ modelStrongReference = ddata->jsWrapper;
+ setObject(object);
accessors = new VDMObjectDelegateDataType;
} else if (list.type() == QQmlListAccessor::ObjectList) {
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = new VDMObjectDelegateDataType;
} else if (list.type() != QQmlListAccessor::Invalid
&& list.type() != QQmlListAccessor::Instance) { // Null QObject
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = new VDMListDelegateDataType;
} else {
- setObject(nullptr, parent);
+ setObject(nullptr);
accessors = &qt_vdm_null_accessors;
}
}
diff --git a/src/qmlmodels/qqmladaptormodel_p.h b/src/qmlmodels/qqmladaptormodel_p.h
index 531e8d9105..8635762bc4 100644
--- a/src/qmlmodels/qqmladaptormodel_p.h
+++ b/src/qmlmodels/qqmladaptormodel_p.h
@@ -70,7 +70,7 @@ class QQmlDelegateModel;
class QQmlDelegateModelItem;
class QQmlDelegateModelItemMetaType;
-class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlStrongJSQObjectReference<QObject>
+class Q_QMLMODELS_PRIVATE_EXPORT QQmlAdaptorModel : public QQmlGuard<QObject>
{
public:
class Accessors
@@ -114,6 +114,10 @@ public:
const Accessors *accessors;
QPersistentModelIndex rootIndex;
QQmlListAccessor list;
+ // we need to ensure that a JS created model does not get gced, but cannot
+ // arbitrarily set the parent (using QQmlStrongJSQObjectReference) of QObject based models,
+ // as that causes issues with singletons
+ QV4::PersistentValue modelStrongReference;
QTypeRevision modelItemRevision = QTypeRevision::zero();
@@ -121,7 +125,7 @@ public:
~QQmlAdaptorModel();
inline QVariant model() const { return list.list(); }
- void setModel(const QVariant &variant, QObject *parent);
+ void setModel(const QVariant &variant, QObject *parent = nullptr);
void invalidateModel();
bool isValid() const;
diff --git a/src/qmlmodels/qqmlchangeset.cpp b/src/qmlmodels/qqmlchangeset.cpp
index ba876b42e2..99def9567c 100644
--- a/src/qmlmodels/qqmlchangeset.cpp
+++ b/src/qmlmodels/qqmlchangeset.cpp
@@ -557,16 +557,17 @@ void QQmlChangeSet::change(QVector<Change> *changes)
QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
{
+ QDebugStateSaver stateSaver(debug);
debug.nospace() << "QQmlChangeSet(";
const QVector<QQmlChangeSet::Change> &removes = set.removes();
for (const QQmlChangeSet::Change &remove : removes)
- debug << remove;
+ debug << remove << ' ';
const QVector<QQmlChangeSet::Change> &inserts = set.inserts();
for (const QQmlChangeSet::Change &insert : inserts)
- debug << insert;
+ debug << insert << ' ';
const QVector<QQmlChangeSet::Change> &changes = set.changes();
for (const QQmlChangeSet::Change &change : changes)
- debug << change;
+ debug << change << ' ';
return debug.nospace() << ')';
}
@@ -576,7 +577,8 @@ QDebug operator <<(QDebug debug, const QQmlChangeSet &set)
QDebug operator <<(QDebug debug, const QQmlChangeSet::Change &change)
{
- return (debug.nospace() << "Change(" << change.index << ',' << change.count << ')').space();
+ QDebugStateSaver stateSaver(debug);
+ return debug.nospace() << "Change(" << change.index << ',' << change.count << ')';
}
QT_END_NAMESPACE
diff --git a/src/qmlmodels/qqmldelegatemodel.cpp b/src/qmlmodels/qqmldelegatemodel.cpp
index 5c5f464cd5..f127885e98 100644
--- a/src/qmlmodels/qqmldelegatemodel.cpp
+++ b/src/qmlmodels/qqmldelegatemodel.cpp
@@ -259,7 +259,7 @@ QQmlDelegateModel::~QQmlDelegateModel()
{
Q_D(QQmlDelegateModel);
d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setObject(nullptr, this);
+ d->m_adaptorModel.setObject(nullptr);
for (QQmlDelegateModelItem *cacheItem : qAsConst(d->m_cache)) {
if (cacheItem->object) {
@@ -389,6 +389,12 @@ void QQmlDelegateModelPrivate::connectToAbstractItemModel()
q, QQmlDelegateModel, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
q, QQmlDelegateModel, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsInserted(QModelIndex,int,int)),
+ q, QQmlDelegateModel, SLOT(_q_columnsInserted(QModelIndex,int,int)));
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsRemoved(QModelIndex,int,int)),
+ q, QQmlDelegateModel, SLOT(_q_columnsRemoved(QModelIndex,int,int)));
+ qmlobject_connect(aim, QAbstractItemModel, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)),
+ q, QQmlDelegateModel, SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
q, QQmlDelegateModel, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
qmlobject_connect(aim, QAbstractItemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
@@ -413,6 +419,12 @@ void QQmlDelegateModelPrivate::disconnectFromAbstractItemModel()
q, SLOT(_q_rowsAboutToBeRemoved(QModelIndex,int,int)));
QObject::disconnect(aim, SIGNAL(rowsRemoved(QModelIndex,int,int)),
q, SLOT(_q_rowsRemoved(QModelIndex,int,int)));
+ QObject::disconnect(aim, SIGNAL(columnsInserted(QModelIndex,int,int)), q,
+ SLOT(_q_columnsInserted(QModelIndex,int,int)));
+ QObject::disconnect(aim, SIGNAL(columnsRemoved(QModelIndex,int,int)), q,
+ SLOT(_q_columnsRemoved(QModelIndex,int,int)));
+ QObject::disconnect(aim, SIGNAL(columnsMoved(QModelIndex,int,int,QModelIndex,int)), q,
+ SLOT(_q_columnsMoved(QModelIndex,int,int,QModelIndex,int)));
QObject::disconnect(aim, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector<int>)),
q, SLOT(_q_dataChanged(QModelIndex,QModelIndex,QVector<int>)));
QObject::disconnect(aim, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)),
@@ -431,7 +443,7 @@ void QQmlDelegateModel::setModel(const QVariant &model)
_q_itemsRemoved(0, d->m_count);
d->disconnectFromAbstractItemModel();
- d->m_adaptorModel.setModel(model, this);
+ d->m_adaptorModel.setModel(model);
d->connectToAbstractItemModel();
d->m_adaptorModel.replaceWatchedRoles(QList<QByteArray>(), d->m_watchedRoles);
@@ -1970,6 +1982,38 @@ void QQmlDelegateModel::_q_rowsMoved(
}
}
+void QQmlDelegateModel::_q_columnsInserted(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QQmlDelegateModel);
+ Q_UNUSED(end);
+ if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
+ // mark all items as changed
+ _q_itemsChanged(0, d->m_count, QVector<int>());
+ }
+}
+
+void QQmlDelegateModel::_q_columnsRemoved(const QModelIndex &parent, int begin, int end)
+{
+ Q_D(QQmlDelegateModel);
+ Q_UNUSED(end);
+ if (parent == d->m_adaptorModel.rootIndex && begin == 0) {
+ // mark all items as changed
+ _q_itemsChanged(0, d->m_count, QVector<int>());
+ }
+}
+
+void QQmlDelegateModel::_q_columnsMoved(const QModelIndex &parent, int start, int end,
+ const QModelIndex &destination, int column)
+{
+ Q_D(QQmlDelegateModel);
+ Q_UNUSED(end);
+ if ((parent == d->m_adaptorModel.rootIndex && start == 0)
+ || (destination == d->m_adaptorModel.rootIndex && column == 0)) {
+ // mark all items as changed
+ _q_itemsChanged(0, d->m_count, QVector<int>());
+ }
+}
+
void QQmlDelegateModel::_q_dataChanged(const QModelIndex &begin, const QModelIndex &end, const QVector<int> &roles)
{
Q_D(QQmlDelegateModel);
@@ -2054,8 +2098,8 @@ bool QQmlDelegateModelPrivate::insert(Compositor::insert_iterator &before, const
// Must be before the new object is inserted into the cache or its indexes will be adjusted too.
itemsInserted(QVector<Compositor::Insert>(1, Compositor::Insert(before, 1, cacheItem->groups & ~Compositor::CacheFlag)));
- before = m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
m_cache.insert(before.cacheIndex, cacheItem);
+ m_compositor.insert(before, nullptr, 0, 1, cacheItem->groups);
return true;
}
@@ -3922,4 +3966,6 @@ QV4::ReturnedValue QQmlDelegateModelEngineData::array(QV4::ExecutionEngine *v4,
QT_END_NAMESPACE
+#include "moc_qqmldelegatemodel_p_p.cpp"
+
#include "moc_qqmldelegatemodel_p.cpp"
diff --git a/src/qmlmodels/qqmldelegatemodel_p.h b/src/qmlmodels/qqmldelegatemodel_p.h
index f4578e130e..2ce02c4aa5 100644
--- a/src/qmlmodels/qqmldelegatemodel_p.h
+++ b/src/qmlmodels/qqmldelegatemodel_p.h
@@ -152,6 +152,9 @@ private Q_SLOTS:
void _q_itemsMoved(int from, int to, int count);
void _q_modelReset();
void _q_rowsInserted(const QModelIndex &,int,int);
+ void _q_columnsInserted(const QModelIndex &, int, int);
+ void _q_columnsRemoved(const QModelIndex &, int, int);
+ void _q_columnsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void _q_rowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end);
void _q_rowsRemoved(const QModelIndex &,int,int);
void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
diff --git a/src/qmlmodels/qqmlinstantiator.cpp b/src/qmlmodels/qqmlinstantiator.cpp
index 3b663badf5..cb7ca1126c 100644
--- a/src/qmlmodels/qqmlinstantiator.cpp
+++ b/src/qmlmodels/qqmlinstantiator.cpp
@@ -147,7 +147,7 @@ void QQmlInstantiatorPrivate::_q_modelUpdated(const QQmlChangeSet &changeSet, bo
{
Q_Q(QQmlInstantiator);
- if (!componentComplete || effectiveReset)
+ if (!componentComplete || effectiveReset || !active)
return;
if (reset) {
diff --git a/src/qmlmodels/qqmllistaccessor.cpp b/src/qmlmodels/qqmllistaccessor.cpp
index 230f190834..381d5d34de 100644
--- a/src/qmlmodels/qqmllistaccessor.cpp
+++ b/src/qmlmodels/qqmllistaccessor.cpp
@@ -75,6 +75,7 @@ void QQmlListAccessor::setList(const QVariant &v)
d = d.value<QJSValue>().toVariant();
variantsType = d.metaType();
}
+
if (!d.isValid()) {
m_type = Invalid;
} else if (variantsType == QMetaType::fromType<QStringList>()) {
@@ -85,6 +86,9 @@ void QQmlListAccessor::setList(const QVariant &v)
m_type = VariantList;
} else if (variantsType == QMetaType::fromType<QList<QObject *>>()) {
m_type = ObjectList;
+ } else if (variantsType.flags() & QMetaType::IsQmlList) {
+ d = QVariant::fromValue(QQmlListReference(d));
+ m_type = ListProperty;
} else if (variantsType == QMetaType::fromType<QQmlListReference>()) {
m_type = ListProperty;
} else if (variantsType.flags() & QMetaType::PointerToQObject) {
diff --git a/src/qmlmodels/qqmllistcompositor_p.h b/src/qmlmodels/qqmllistcompositor_p.h
index 7bf20397fd..797a457e8c 100644
--- a/src/qmlmodels/qqmllistcompositor_p.h
+++ b/src/qmlmodels/qqmllistcompositor_p.h
@@ -308,6 +308,10 @@ Q_DECLARE_TYPEINFO(QQmlListCompositor::Insert, Q_PRIMITIVE_TYPE);
inline QQmlListCompositor::iterator::iterator() {}
+QT_WARNING_PUSH
+// GCC isn't wrong, as groupCount is public in iterator, but we tried Q_ASSUME(),
+// right in front of the loops, and it didn't help, so we disable the warning:
+QT_WARNING_DISABLE_GCC("-Warray-bounds")
inline QQmlListCompositor::iterator::iterator(
Range *range, int offset, Group group, int groupCount)
: range(range)
@@ -335,6 +339,7 @@ inline void QQmlListCompositor::iterator::decrementIndexes(int difference, uint
index[i] -= difference;
}
}
+QT_WARNING_POP // -Warray-bounds
inline QQmlListCompositor::insert_iterator::insert_iterator(
Range *range, int offset, Group group, int groupCount)
diff --git a/src/qmlmodels/qqmllistmodel.cpp b/src/qmlmodels/qqmllistmodel.cpp
index a9c58d59a5..c060aaec97 100644
--- a/src/qmlmodels/qqmllistmodel.cpp
+++ b/src/qmlmodels/qqmllistmodel.cpp
@@ -129,8 +129,28 @@ const ListLayout::Role &ListLayout::getRoleOrCreate(QV4::String *key, Role::Data
const ListLayout::Role &ListLayout::createRole(const QString &key, ListLayout::Role::DataType type)
{
- const int dataSizes[] = { sizeof(StringOrTranslation), sizeof(double), sizeof(bool), sizeof(ListModel *), sizeof(ListElement::GuardedQObjectPointer), sizeof(QVariantMap), sizeof(QDateTime), sizeof(QUrl), sizeof(QJSValue) };
- const int dataAlignments[] = { alignof(StringOrTranslation), alignof(double), alignof(bool), alignof(ListModel *), alignof(QObject *), alignof(QVariantMap), alignof(QDateTime), alignof(QUrl), alignof(QJSValue) };
+ const int dataSizes[] = {
+ sizeof(StringOrTranslation),
+ sizeof(double),
+ sizeof(bool),
+ sizeof(ListModel *),
+ sizeof(QV4::PersistentValue),
+ sizeof(QVariantMap),
+ sizeof(QDateTime),
+ sizeof(QUrl),
+ sizeof(QJSValue)
+ };
+ const int dataAlignments[] = {
+ alignof(StringOrTranslation),
+ alignof(double),
+ alignof(bool),
+ alignof(ListModel *),
+ alignof(QV4::PersistentValue),
+ alignof(QVariantMap),
+ alignof(QDateTime),
+ alignof(QUrl),
+ alignof(QJSValue)
+ };
Role *r = new Role;
r->name = key;
@@ -567,6 +587,17 @@ ListModel *ListModel::getListProperty(int elementIndex, const ListLayout::Role &
return e->getListProperty(role);
}
+void ListModel::updateTranslations()
+{
+ for (int index = 0; index != elements.count(); ++index) {
+ ListElement *e = elements[index];
+ if (ModelNodeMetaObject *cache = e->objectCache()) {
+ // TODO: more fine grained tracking?
+ cache->updateValues();
+ }
+ }
+}
+
void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
{
ListElement *e = elements[elementIndex];
@@ -623,10 +654,9 @@ void ListModel::set(int elementIndex, QV4::Object *object, QVector<int> *roles)
roleIndex = e->setFunctionProperty(r, jsv);
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (role.type == ListLayout::Role::QObject)
- roleIndex = e->setQObjectProperty(role, o);
+ roleIndex = e->setQObjectProperty(role, wrapper);
} else if (QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
@@ -714,23 +744,21 @@ void ListModel::set(int elementIndex, QV4::Object *object, ListModel::SetElement
}
} else if (QV4::Object *o = propertyValue->as<QV4::Object>()) {
if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
- QObject *o = wrapper->object();
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::QObject);
if (r.type == ListLayout::Role::QObject)
- e->setQObjectPropertyFast(r, o);
+ e->setQObjectPropertyFast(r, wrapper);
} else {
QVariant maybeUrl = o->engine()->toVariant(o->asReturnedValue(), QMetaType::fromType<QUrl>(), true);
if (maybeUrl.metaType() == QMetaType::fromType<QUrl>()) {
const QUrl qurl = maybeUrl.toUrl();
const ListLayout::Role &r = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::Url);
- if (r.type == ListLayout::Role::Url) {
+ if (r.type == ListLayout::Role::Url)
e->setUrlPropertyFast(r, qurl);
- }
- return;
+ } else {
+ const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
+ if (role.type == ListLayout::Role::VariantMap)
+ e->setVariantMapFast(role, o);
}
- const ListLayout::Role &role = m_layout->getRoleOrCreate(propertyName, ListLayout::Role::VariantMap);
- if (role.type == ListLayout::Role::VariantMap)
- e->setVariantMapFast(role, o);
}
} else if (propertyValue->isNullOrUndefined()) {
if (reason == SetElement::WasJustInserted) {
@@ -842,12 +870,11 @@ StringOrTranslation *ListElement::getStringProperty(const ListLayout::Role &role
return s;
}
-QObject *ListElement::getQObjectProperty(const ListLayout::Role &role)
+QV4::QObjectWrapper *ListElement::getQObjectProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
- GuardedQObjectPointer *o
- = reinterpret_cast<GuardedQObjectPointer *>(mem);
- return o->data();
+ QV4::PersistentValue *g = reinterpret_cast<QV4::PersistentValue *>(mem);
+ return g->as<QV4::QObjectWrapper>();
}
QVariantMap *ListElement::getVariantMapProperty(const ListLayout::Role &role)
@@ -894,13 +921,13 @@ QJSValue *ListElement::getFunctionProperty(const ListLayout::Role &role)
return f;
}
-ListElement::GuardedQObjectPointer *
+QV4::PersistentValue *
ListElement::getGuardProperty(const ListLayout::Role &role)
{
char *mem = getPropertyMemory(role);
bool existingGuard = false;
- for (size_t i = 0; i < sizeof(GuardedQObjectPointer);
+ for (size_t i = 0; i < sizeof(QV4::PersistentValue);
++i) {
if (mem[i] != 0) {
existingGuard = true;
@@ -908,12 +935,12 @@ ListElement::getGuardProperty(const ListLayout::Role &role)
}
}
- GuardedQObjectPointer *o = nullptr;
+ QV4::PersistentValue *g = nullptr;
if (existingGuard)
- o = reinterpret_cast<GuardedQObjectPointer *>(mem);
+ g = reinterpret_cast<QV4::PersistentValue *>(mem);
- return o;
+ return g;
}
ListModel *ListElement::getListProperty(const ListLayout::Role &role)
@@ -969,12 +996,8 @@ QVariant ListElement::getProperty(const ListLayout::Role &role, const QQmlListMo
break;
case ListLayout::Role::QObject:
{
- GuardedQObjectPointer *guard =
- reinterpret_cast<GuardedQObjectPointer *>(
- mem);
- QObject *object = guard->data();
- if (object)
- data = QVariant::fromValue(object);
+ QV4::PersistentValue *guard = reinterpret_cast<QV4::PersistentValue *>(mem);
+ data = QVariant::fromValue(guard->as<QV4::QObjectWrapper>()->object());
}
break;
case ListLayout::Role::VariantMap:
@@ -1086,69 +1109,17 @@ int ListElement::setListProperty(const ListLayout::Role &role, ListModel *m)
return roleIndex;
}
-static void
-restoreQObjectOwnership(ListElement::GuardedQObjectPointer *pointer)
-{
- if (QObject *o = pointer->data()) {
- QQmlData *data = QQmlData::get(o, false);
- Q_ASSERT(data);
-
- // Only restore the previous state if the object hasn't become explicitly
- // owned
- if (!data->explicitIndestructibleSet) {
- data->indestructible = (pointer->tag() & ListElement::Indestructible);
- data->explicitIndestructibleSet = (pointer->tag() & ListElement::ExplicitlySet);
- }
- }
-}
-
-static void setQObjectOwnership(char *mem, QObject *o)
-{
- QQmlData *ddata = QQmlData::get(o, false);
- const int ownership = (!ddata || ddata->indestructible ? ListElement::Indestructible : 0)
- | (ddata && ddata->explicitIndestructibleSet ? ListElement::ExplicitlySet : 0);
-
- // If ddata didn't exist above, force its creation now
- if (!ddata)
- ddata = QQmlData::get(o, true);
-
- ddata->indestructible = true;
- ddata->explicitIndestructibleSet = false;
-
- new (mem) ListElement::GuardedQObjectPointer(
- o, static_cast<ListElement::ObjectIndestructible>(ownership));
-}
-
-int ListElement::setQObjectProperty(const ListLayout::Role &role, QObject *o)
+int ListElement::setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
int roleIndex = -1;
if (role.type == ListLayout::Role::QObject) {
char *mem = getPropertyMemory(role);
- GuardedQObjectPointer *g =
- reinterpret_cast<GuardedQObjectPointer *>(mem);
- bool existingGuard = false;
- for (size_t i = 0; i < sizeof(GuardedQObjectPointer);
- ++i) {
- if (mem[i] != 0) {
- existingGuard = true;
- break;
- }
- }
- bool changed;
- if (existingGuard) {
- changed = g->data() != o;
- if (changed)
- restoreQObjectOwnership(g);
- g->~GuardedQObjectPointer();
- } else {
- changed = true;
- }
-
- setQObjectOwnership(mem, o);
-
- if (changed)
- roleIndex = role.index;
+ if (isMemoryUsed<QVariantMap>(mem))
+ reinterpret_cast<QV4::PersistentValue *>(mem)->set(o->engine(), *o);
+ else
+ new (mem) QV4::PersistentValue(o->engine(), o);
+ roleIndex = role.index;
}
return roleIndex;
@@ -1281,11 +1252,10 @@ void ListElement::setBoolPropertyFast(const ListLayout::Role &role, bool b)
*value = b;
}
-void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QObject *o)
+void ListElement::setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o)
{
char *mem = getPropertyMemory(role);
-
- setQObjectOwnership(mem, o);
+ new (mem) QV4::PersistentValue(o->engine(), o);
}
void ListElement::setListPropertyFast(const ListLayout::Role &role, ListModel *m)
@@ -1402,7 +1372,7 @@ QVector<int> ListElement::sync(ListElement *src, ListLayout *srcLayout, ListElem
break;
case ListLayout::Role::QObject:
{
- QObject *object = src->getQObjectProperty(srcRole);
+ QV4::QObjectWrapper *object = src->getQObjectProperty(srcRole);
roleIndex = target->setQObjectProperty(targetRole, object);
}
break;
@@ -1457,14 +1427,8 @@ void ListElement::destroy(ListLayout *layout)
break;
case ListLayout::Role::QObject:
{
- GuardedQObjectPointer *guard =
- getGuardProperty(r);
-
- if (guard) {
- restoreQObjectOwnership(guard);
-
- guard->~GuardedQObjectPointer();
- }
+ if (QV4::PersistentValue *guard = getGuardProperty(r))
+ guard->~PersistentValue();
}
break;
case ListLayout::Role::VariantMap:
@@ -1601,8 +1565,7 @@ int ListElement::setJsProperty(const ListLayout::Role &role, const QV4::Value &d
QV4::ScopedObject o(scope, d);
QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>();
if (role.type == ListLayout::Role::QObject && wrapper) {
- QObject *o = wrapper->object();
- roleIndex = setQObjectProperty(role, o);
+ roleIndex = setQObjectProperty(role, wrapper);
} else if (role.type == ListLayout::Role::VariantMap) {
roleIndex = setVariantMapProperty(role, o);
} else if (role.type == ListLayout::Role::Url) {
@@ -2502,6 +2465,27 @@ void QQmlListModel::removeElements(int index, int removeCount)
destroyer();
}
+void QQmlListModel::updateTranslations()
+{
+ // assumption: it is impossible to have retranslatable strings in a
+ // dynamic list model, as they would already have "decayed" to strings
+ // when they were inserted
+ if (m_dynamicRoles)
+ return;
+ Q_ASSERT(m_listModel);
+
+ QList<int> roles;
+ for (int i = 0, end = m_listModel->roleCount(); i != end; ++i) {
+ if (m_listModel->getExistingRole(i).type == ListLayout::Role::String)
+ roles.append(i);
+ }
+
+ if (!roles.isEmpty())
+ emitItemsChanged(0, rowCount(QModelIndex()), roles);
+
+ m_listModel->updateTranslations();
+}
+
/*!
\qmlmethod ListModel::insert(int index, jsobject dict)
@@ -2847,7 +2831,7 @@ void QQmlListModel::sync()
bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
QString objName = compilationUnit->stringAt(target->inheritedTypeNameIndex);
@@ -2875,7 +2859,7 @@ bool QQmlListModelParser::verifyProperty(const QQmlRefPointer<QV4::ExecutableCom
if (!verifyProperty(compilationUnit, binding))
return false;
}
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (binding->type() == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (!binding->isFunctionExpression() && !definesEmptyList(scriptStr)) {
QByteArray script = scriptStr.toUtf8();
@@ -2898,7 +2882,8 @@ bool QQmlListModelParser::applyProperty(
const QString elementName = compilationUnit->stringAt(binding->propertyNameIndex);
bool roleSet = false;
- if (binding->type >= QV4::CompiledData::Binding::Type_Object) {
+ const QV4::CompiledData::Binding::Type bindingType = binding->type();
+ if (bindingType >= QV4::CompiledData::Binding::Type_Object) {
const quint32 targetObjectIndex = binding->value.objectIndex;
const QV4::CompiledData::Object *target = compilationUnit->objectAt(targetObjectIndex);
@@ -2927,17 +2912,18 @@ bool QQmlListModelParser::applyProperty(
} else {
QVariant value;
- if (binding->isTranslationBinding()) {
+ const bool isTranslationBinding = binding->isTranslationBinding();
+ if (isTranslationBinding) {
value = QVariant::fromValue<const QV4::CompiledData::Binding*>(binding);
} else if (binding->evaluatesToString()) {
value = compilationUnit->bindingValueAsString(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Number) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Number) {
value = compilationUnit->bindingValueAsNumber(binding);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Boolean) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Boolean) {
value = binding->valueAsBoolean();
- } else if (binding->type == QV4::CompiledData::Binding::Type_Null) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Null) {
value = QVariant::fromValue(nullptr);
- } else if (binding->type == QV4::CompiledData::Binding::Type_Script) {
+ } else if (bindingType == QV4::CompiledData::Binding::Type_Script) {
QString scriptStr = compilationUnit->bindingValueAsScriptString(binding);
if (definesEmptyList(scriptStr)) {
const ListLayout::Role &role = model->getOrCreateListRole(elementName);
@@ -2969,7 +2955,17 @@ bool QQmlListModelParser::applyProperty(
Q_UNREACHABLE();
}
+ if (!model)
+ return roleSet;
model->setOrCreateProperty(outterElementIndex, elementName, value);
+ auto listModel = model->m_modelCache;
+ if (isTranslationBinding && listModel) {
+ if (!listModel->translationChangeHandler) {
+ auto ep = QQmlEnginePrivate::get(compilationUnit->engine);
+ model->m_modelCache->translationChangeHandler = std::make_unique<QPropertyNotifier>(
+ ep->translationLanguage.addNotifier([listModel](){ listModel->updateTranslations(); }));
+ }
+ }
roleSet = true;
}
return roleSet;
@@ -3000,7 +2996,7 @@ void QQmlListModelParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::
bool setRoles = false;
for (const QV4::CompiledData::Binding *binding : bindings) {
- if (binding->type != QV4::CompiledData::Binding::Type_Object)
+ if (binding->type() != QV4::CompiledData::Binding::Type_Object)
continue;
setRoles |= applyProperty(compilationUnit, binding, rv->m_listModel, /*outter element index*/-1);
}
@@ -3070,4 +3066,6 @@ bool QQmlListModelParser::definesEmptyList(const QString &s)
QT_END_NAMESPACE
+#include "moc_qqmllistmodel_p_p.cpp"
+
#include "moc_qqmllistmodel_p.cpp"
diff --git a/src/qmlmodels/qqmllistmodel_p.h b/src/qmlmodels/qqmllistmodel_p.h
index 2e8181e10c..7cd2b4662b 100644
--- a/src/qmlmodels/qqmllistmodel_p.h
+++ b/src/qmlmodels/qqmllistmodel_p.h
@@ -148,6 +148,7 @@ private:
ListLayout *m_layout;
ListModel *m_listModel;
+ std::unique_ptr<QPropertyNotifier> translationChangeHandler;
QVector<class DynamicRoleModelNode *> m_modelObjects;
QVector<QString> m_roles;
@@ -169,6 +170,8 @@ private:
void emitItemsInserted();
void removeElements(int index, int removeCount);
+
+ void updateTranslations();
};
// ### FIXME
diff --git a/src/qmlmodels/qqmllistmodel_p_p.h b/src/qmlmodels/qqmllistmodel_p_p.h
index 6c40934c04..19cba980f4 100644
--- a/src/qmlmodels/qqmllistmodel_p_p.h
+++ b/src/qmlmodels/qqmllistmodel_p_p.h
@@ -281,43 +281,6 @@ public:
enum ObjectIndestructible { Indestructible = 1, ExplicitlySet = 2 };
enum { BLOCK_SIZE = 64 - sizeof(int) - sizeof(ListElement *) - sizeof(ModelNodeMetaObject *) };
- // This is a basic guarded QObject pointer, with tag. It cannot be copied or moved.
- class GuardedQObjectPointer
- {
- Q_DISABLE_COPY_MOVE(GuardedQObjectPointer)
-
- using RefCountData = QtSharedPointer::ExternalRefCountData;
- using Storage = QTaggedPointer<QObject, ObjectIndestructible>;
-
- public:
- GuardedQObjectPointer(QObject *o, ObjectIndestructible ownership)
- : storage(o, ownership)
- , refCount(o ? RefCountData::getAndRef(o) : nullptr)
- {}
-
- ~GuardedQObjectPointer()
- {
- if (refCount && !refCount->weakref.deref())
- delete refCount;
- }
-
- QObject *data() const
- {
- return (refCount == nullptr || refCount->strongref.loadRelaxed() == 0)
- ? nullptr
- : storage.data();
- }
-
- ObjectIndestructible tag() const
- {
- return storage.tag();
- }
-
- private:
- Storage storage;
- RefCountData *refCount = nullptr;
- };
-
ListElement();
ListElement(int existingUid);
~ListElement();
@@ -336,7 +299,7 @@ private:
int setDoubleProperty(const ListLayout::Role &role, double n);
int setBoolProperty(const ListLayout::Role &role, bool b);
int setListProperty(const ListLayout::Role &role, ListModel *m);
- int setQObjectProperty(const ListLayout::Role &role, QObject *o);
+ int setQObjectProperty(const ListLayout::Role &role, QV4::QObjectWrapper *o);
int setVariantMapProperty(const ListLayout::Role &role, QV4::Object *o);
int setVariantMapProperty(const ListLayout::Role &role, QVariantMap *m);
int setDateTimeProperty(const ListLayout::Role &role, const QDateTime &dt);
@@ -347,7 +310,7 @@ private:
void setStringPropertyFast(const ListLayout::Role &role, const QString &s);
void setDoublePropertyFast(const ListLayout::Role &role, double n);
void setBoolPropertyFast(const ListLayout::Role &role, bool b);
- void setQObjectPropertyFast(const ListLayout::Role &role, QObject *o);
+ void setQObjectPropertyFast(const ListLayout::Role &role, QV4::QObjectWrapper *o);
void setListPropertyFast(const ListLayout::Role &role, ListModel *m);
void setVariantMapFast(const ListLayout::Role &role, QV4::Object *o);
void setDateTimePropertyFast(const ListLayout::Role &role, const QDateTime &dt);
@@ -359,8 +322,8 @@ private:
QVariant getProperty(const ListLayout::Role &role, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
ListModel *getListProperty(const ListLayout::Role &role);
StringOrTranslation *getStringProperty(const ListLayout::Role &role);
- QObject *getQObjectProperty(const ListLayout::Role &role);
- GuardedQObjectPointer *getGuardProperty(const ListLayout::Role &role);
+ QV4::QObjectWrapper *getQObjectProperty(const ListLayout::Role &role);
+ QV4::PersistentValue *getGuardProperty(const ListLayout::Role &role);
QVariantMap *getVariantMapProperty(const ListLayout::Role &role);
QDateTime *getDateTimeProperty(const ListLayout::Role &role);
QUrl *getUrlProperty(const ListLayout::Role &role);
@@ -399,6 +362,8 @@ public:
QVariant getProperty(int elementIndex, int roleIndex, const QQmlListModel *owner, QV4::ExecutionEngine *eng);
ListModel *getListProperty(int elementIndex, const ListLayout::Role &role);
+ void updateTranslations();
+
int roleCount() const
{
return m_layout->roleCount();
diff --git a/src/qml/types/qqmlmodelindexvaluetype.cpp b/src/qmlmodels/qqmlmodelindexvaluetype.cpp
index cbf2fef348..cbf2fef348 100644
--- a/src/qml/types/qqmlmodelindexvaluetype.cpp
+++ b/src/qmlmodels/qqmlmodelindexvaluetype.cpp
diff --git a/src/qml/types/qqmlmodelindexvaluetype_p.h b/src/qmlmodels/qqmlmodelindexvaluetype_p.h
index 2c37d91c71..2c37d91c71 100644
--- a/src/qml/types/qqmlmodelindexvaluetype_p.h
+++ b/src/qmlmodels/qqmlmodelindexvaluetype_p.h
diff --git a/src/qmltest/CMakeLists.txt b/src/qmltest/CMakeLists.txt
index b823c48d82..7f55ebc8b0 100644
--- a/src/qmltest/CMakeLists.txt
+++ b/src/qmltest/CMakeLists.txt
@@ -2,9 +2,6 @@
## QuickTest Module:
#####################################################################
-set_source_files_properties(TestCase.qml SignalSpy.qml PROPERTIES
- QT_QML_SOURCE_VERSION "1.0;6.0"
-)
set_source_files_properties(testlogger.js PROPERTIES
QT_QML_SKIP_QMLDIR_ENTRY TRUE
)
@@ -36,12 +33,12 @@ qt_internal_add_qml_module(QuickTest
Qt::CorePrivate
Qt::Gui
Qt::QmlPrivate
- Qt::Quick
Qt::QuickPrivate
Qt::TestPrivate
PUBLIC_LIBRARIES
Qt::Core
Qt::Test
+ Qt::Quick
PRIVATE_MODULE_INTERFACE
Qt::TestPrivate
)
diff --git a/src/qmltest/SignalSpy.qml b/src/qmltest/SignalSpy.qml
index 52ed83e261..7257e4f3f3 100644
--- a/src/qmltest/SignalSpy.qml
+++ b/src/qmltest/SignalSpy.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -218,9 +218,14 @@ Item {
/*! \internal */
property bool qtest_valid:false
/*! \internal */
+ property bool qtest_reentrancy_guard: false
/*! \internal */
function qtest_update() {
+ if (qtest_reentrancy_guard)
+ return;
+ qtest_reentrancy_guard = true;
+
if (qtest_prevTarget != null) {
var prevHandlerName = qtest_signalHandlerName(qtest_prevSignalName)
var prevFunc = qtest_prevTarget[prevHandlerName]
@@ -251,6 +256,8 @@ Item {
} else {
spy.qtest_valid = false
}
+
+ qtest_reentrancy_guard = false;
}
/*! \internal */
diff --git a/src/qmltest/TestCase.qml b/src/qmltest/TestCase.qml
index 1c9011e01e..5a2cd1d5c4 100644
--- a/src/qmltest/TestCase.qml
+++ b/src/qmltest/TestCase.qml
@@ -1133,7 +1133,7 @@ Item {
\qmlmethod TestCase::warn(message)
Prints \a message as a warning message. Similar to
- \c{QWARN(message)} in C++.
+ \c{qWarning(message)} in C++.
\sa ignoreWarning()
*/
diff --git a/src/qmltest/doc/snippets/overview.cmake b/src/qmltest/doc/snippets/overview.cmake
index 5415e42a17..9ea4d01e83 100644
--- a/src/qmltest/doc/snippets/overview.cmake
+++ b/src/qmltest/doc/snippets/overview.cmake
@@ -1,4 +1,4 @@
#! [cmake_use]
-find_package(Qt6 COMPONENTS QuickTest REQUIRED)
+find_package(Qt6 REQUIRED COMPONENTS QuickTest)
target_link_libraries(mytarget PRIVATE Qt6::QuickTest)
#! [cmake_use]
diff --git a/src/qmltest/doc/src/qtquicktest-qmltypes.qdoc b/src/qmltest/doc/src/qtquicktest-qmltypes.qdoc
index d7cada0db2..d874b20a5a 100644
--- a/src/qmltest/doc/src/qtquicktest-qmltypes.qdoc
+++ b/src/qmltest/doc/src/qtquicktest-qmltypes.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtTest 1.\QtMinorVersion
+ \qmlmodule QtTest
\title Qt Quick Test QML Types
\brief Provides QML types to unit test your QML application.
\ingroup qmlmodules
diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp
index 276463c7c5..8b1aad5dc0 100644
--- a/src/qmltest/quicktest.cpp
+++ b/src/qmltest/quicktest.cpp
@@ -298,7 +298,7 @@ private:
if (!object) // Start at root of compilation unit if not enumerating a specific child
object = compilationUnit->objectAt(0);
- if (object->flags & Object::IsInlineComponentRoot)
+ if (object->hasFlag(Object::IsInlineComponentRoot))
return result;
if (const auto superTypeUnit = compilationUnit->resolvedTypes.value(
@@ -314,13 +314,13 @@ private:
// Look for override of name in this type
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
if (compilationUnit->stringAt(binding->propertyNameIndex) == QLatin1String("name")) {
- if (binding->type == QV4::CompiledData::Binding::Type_String) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_String) {
result.testCaseName = compilationUnit->stringAt(binding->stringIndex);
} else {
QQmlError error;
error.setUrl(compilationUnit->url());
- error.setLine(binding->location.line);
- error.setColumn(binding->location.column);
+ error.setLine(binding->location.line());
+ error.setColumn(binding->location.column());
error.setDescription(QStringLiteral("the 'name' property of a TestCase must be a literal string"));
result.errors << error;
}
@@ -344,7 +344,7 @@ private:
}
for (auto binding = object->bindingsBegin(); binding != object->bindingsEnd(); ++binding) {
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Object) {
const Object *child = compilationUnit->objectAt(binding->value.objectIndex);
result << enumerateTestCases(compilationUnit, child);
}
@@ -432,7 +432,7 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
testPath = s;
}
-#if defined(Q_OS_ANDROID)
+#if defined(Q_OS_ANDROID) || defined(Q_OS_INTEGRITY)
if (testPath.isEmpty())
testPath = QLatin1String(":/");
#endif
@@ -631,3 +631,5 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch
}
QT_END_NAMESPACE
+
+#include "moc_quicktest_p.cpp"
diff --git a/src/qmltest/quicktestevent.cpp b/src/qmltest/quicktestevent.cpp
index 1ed642fe07..c41061200e 100644
--- a/src/qmltest/quicktestevent.cpp
+++ b/src/qmltest/quicktestevent.cpp
@@ -227,7 +227,7 @@ namespace QtQuickTest
static const char *mouseActionNames[] =
{ "MousePress", "MouseRelease", "MouseClick", "MouseDoubleClick", "MouseMove", "MouseDoubleClickSequence" };
QString warning = QString::fromLatin1("Mouse event \"%1\" not accepted by receiving window");
- QWARN(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data());
+ QTest::qWarn(warning.arg(QString::fromLatin1(mouseActionNames[static_cast<int>(action)])).toLatin1().data());
}
}
@@ -482,3 +482,5 @@ QQuickTouchEventSequence *QuickTestEvent::touchEvent(QObject *item)
}
QT_END_NAMESPACE
+
+#include "moc_quicktestevent_p.cpp"
diff --git a/src/qmltest/quicktestresult.cpp b/src/qmltest/quicktestresult.cpp
index 0853c26f51..22edb95687 100644
--- a/src/qmltest/quicktestresult.cpp
+++ b/src/qmltest/quicktestresult.cpp
@@ -775,7 +775,8 @@ QObject *QuickTestResult::grabImage(QQuickItem *item)
if (item && item->window()) {
QQuickWindow *window = item->window();
QImage grabbed = window->grabWindow();
- QRectF rf(item->x(), item->y(), item->width(), item->height());
+ const auto dpi = grabbed.devicePixelRatio();
+ QRectF rf(item->x() * dpi, item->y() * dpi, item->width() * dpi, item->height() * dpi);
rf = rf.intersected(QRectF(0, 0, grabbed.width(), grabbed.height()));
QObject *o = new QuickTestImageObject(grabbed.copy(rf.toAlignedRect()));
QQmlEngine::setContextForObject(o, qmlContext(this));
diff --git a/src/qmltest/quicktestutil.cpp b/src/qmltest/quicktestutil.cpp
index 994c66845b..0e6694fd7b 100644
--- a/src/qmltest/quicktestutil.cpp
+++ b/src/qmltest/quicktestutil.cpp
@@ -111,3 +111,5 @@ int QuickTestUtil::callerLine(int frameIndex) const
}
QT_END_NAMESPACE
+
+#include "moc_quicktestutil_p.cpp"
diff --git a/src/qmltyperegistrar/metatypesjsonprocessor.cpp b/src/qmltyperegistrar/metatypesjsonprocessor.cpp
index 4d6f97e874..1c9e9dfddf 100644
--- a/src/qmltyperegistrar/metatypesjsonprocessor.cpp
+++ b/src/qmltyperegistrar/metatypesjsonprocessor.cpp
@@ -296,6 +296,7 @@ void MetaTypesJsonProcessor::processTypes(const QJsonObject &types)
if (!include.endsWith(QLatin1String(".h"))
&& !include.endsWith(QLatin1String(".hpp"))
&& !include.endsWith(QLatin1String(".hxx"))
+ && !include.endsWith(QLatin1String(".hh"))
&& include.contains(QLatin1Char('.'))) {
fprintf(stderr,
"Class %s is declared in %s, which appears not to be a header.\n"
@@ -317,7 +318,7 @@ void MetaTypesJsonProcessor::processTypes(const QJsonObject &types)
void MetaTypesJsonProcessor::processForeignTypes(const QJsonObject &types)
{
- const QString include = types[QLatin1String("inputFile")].toString();
+ const QString include = resolvedInclude(types[QLatin1String("inputFile")].toString());
const QJsonArray classes = types[QLatin1String("classes")].toArray();
for (const QJsonValue cls : classes) {
QJsonObject classDef = cls.toObject();
diff --git a/src/qmltyperegistrar/qmltyperegistrar.cpp b/src/qmltyperegistrar/qmltyperegistrar.cpp
index af266064c0..981f8bb86e 100644
--- a/src/qmltyperegistrar/qmltyperegistrar.cpp
+++ b/src/qmltyperegistrar/qmltyperegistrar.cpp
@@ -192,11 +192,20 @@ int main(int argc, char **argv)
fprintf(output, "\n\n");
+ // Keep this in sync with _qt_internal_get_escaped_uri in CMake
QString moduleAsSymbol = module;
- moduleAsSymbol.replace(QLatin1Char('.'), QLatin1Char('_'));
+ moduleAsSymbol.replace(QRegularExpression(QStringLiteral("[^A-Za-z0-9]")), QStringLiteral("_"));
- const QString functionName = QStringLiteral("qml_register_types_") + moduleAsSymbol;
+ QString underscoredModuleAsSymbol = module;
+ underscoredModuleAsSymbol.replace(QLatin1Char('.'), QLatin1Char('_'));
+
+ if (underscoredModuleAsSymbol != moduleAsSymbol
+ || underscoredModuleAsSymbol.isEmpty()
+ || underscoredModuleAsSymbol.front().isDigit()) {
+ qWarning() << module << "is an invalid QML module URI. You cannot import this.";
+ }
+ const QString functionName = QStringLiteral("qml_register_types_") + moduleAsSymbol;
fprintf(output,
"#if !defined(QT_STATIC)\n"
"#define Q_QMLTYPE_EXPORT Q_DECL_EXPORT\n"
diff --git a/src/qmltyperegistrar/qmltypes.prf b/src/qmltyperegistrar/qmltypes.prf
index 2c6e474a21..b6dea810cc 100644
--- a/src/qmltyperegistrar/qmltypes.prf
+++ b/src/qmltyperegistrar/qmltypes.prf
@@ -43,16 +43,35 @@ qt_module_deps = $$resolve_depends(qt_module_deps, "QT.", ".depends" ".run_depen
qt_module_deps = $$replace(qt_module_deps, _private$, '')
qt_module_deps = $$unique(qt_module_deps)
+# We know we need to prefer the CMake debug build type for qmake debug builds. Which of the CMake
+# release build types should be preferred for a qmake release build is guesswork. We apply a
+# heuristic here:
+#
+# If you've gone to the trouble of building a "minsizerel" Qt, you probably want to use it for your
+# qmake "release" builds. Conversely, if you have both a "release" and a "relwithdebinfo" Qt, you
+# probably want to use the "release" Qt build for qmake "release" builds and the "relwithdebinfo"
+# one for qmake "debug" builds.
+#
+# If no fitting build type exists, we accept the others. On linux, for example, we typically
+# have only a single "relwithdebinfo" Qt build for both debug and release builds of user projects.
+build_types = minsizerel release relwithdebinfo debug
+CONFIG(debug, debug|release): build_types = $$reverse(build_types)
+
for(dep, qt_module_deps) {
android:ABI = _$${ANDROID_TARGET_ARCH}
- METATYPES_FILENAME = $$lower($$eval(QT.$${dep}.module))$${ABI}_metatypes.json
- INSTALLED_METATYPES = $$[QT_INSTALL_LIBS]/metatypes/$$METATYPES_FILENAME
- isEmpty(MODULE_BASE_OUTDIR) {
- QML_FOREIGN_METATYPES += $$INSTALLED_METATYPES
- } else {
- MODULE_BASE_METATYPES = $$MODULE_BASE_OUTDIR/lib/metatypes/$$METATYPES_FILENAME
- exists($$MODULE_BASE_METATYPES): QML_FOREIGN_METATYPES += $$MODULE_BASE_METATYPES
- else: QML_FOREIGN_METATYPES += $$INSTALLED_METATYPES
+ infixed_module_name = $$eval(QT.$${dep}.module)
+
+ for(build_type, build_types) {
+ isEmpty(QT_LIBINFIX) {
+ metatypes_filename = $$lower($${infixed_module_name})$${ABI}_$${build_type}_metatypes.json
+ } else {
+ metatypes_filename = $$lower($$replace($${infixed_module_name}, $$QT_LIBINFIX, ''))$${ABI}_$${build_type}_metatypes.json
+ }
+ metatypes_filepath = $$[QT_INSTALL_LIBS]/metatypes/$${metatypes_filename}
+ exists($${metatypes_filepath}) {
+ QML_FOREIGN_METATYPES += $${metatypes_filepath}
+ break()
+ }
}
}
@@ -82,12 +101,18 @@ qmltyperegistrar_compiler.output = $$TYPEREGISTRATIONS
qmltyperegistrar_compiler.variable_out = SOURCES
qmltyperegistrar_compiler.name = Automatic QML type registration
qmltyperegistrar_compiler.dependency_type = TYPE_C
-
-qmltyperegistrar_qmltypes.input = METATYPES_JSON
-qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS
-qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME
-qmltyperegistrar_qmltypes.CONFIG = no_link
-qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule
+QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler
+
+!contains(TEMPLATE, "vc.*") { # work around QTBUG-91033
+ # Create a fake extra compiler to announce that we generate $$QMLTYPES_FILENAME.
+ # This allows us to use $$QMLTYPES_FILENAME as input in other extra compilers.
+ qmltyperegistrar_qmltypes.input = METATYPES_JSON
+ qmltyperegistrar_qmltypes.depends = $$TYPEREGISTRATIONS
+ qmltyperegistrar_qmltypes.output = $$QMLTYPES_FILENAME
+ qmltyperegistrar_qmltypes.CONFIG = no_link
+ qmltyperegistrar_qmltypes.commands = $$escape_expand(\\n) # force creation of rule
+ QMAKE_EXTRA_COMPILERS += qmltyperegistrar_qmltypes
+}
install_qmltypes {
INSTALL_QML_FILES = false
@@ -110,5 +135,3 @@ install_qmltypes {
else: COPIES += do_install_qmltypes
}
}
-
-QMAKE_EXTRA_COMPILERS += qmltyperegistrar_compiler qmltyperegistrar_qmltypes
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp
index bf6c0ca5ed..b58d4ac00a 100644
--- a/src/qmltyperegistrar/qmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp
@@ -261,11 +261,29 @@ void QmlTypesClassDescription::collect(
accessSemantics = QLatin1String("reference");
} else {
isCreatable = false;
- // If no classDef, we assume it's a value type defined by the foreign/extended trick.
- // Objects and namespaces always have metaobjects and therefore classDefs.
- accessSemantics = (!classDef || classDef->value(QLatin1String("gadget")).toBool())
- ? QLatin1String("value")
- : QLatin1String("none");
+
+ if (!classDef) {
+ if (elementName.isEmpty() || elementName[0].isLower()) {
+ // If no classDef, we generally assume it's a value type defined by the
+ // foreign/extended trick.
+ accessSemantics = QLatin1String("value");
+ } else {
+ // Objects and namespaces always have metaobjects and therefore classDefs.
+ // However, we may not be able to resolve the metaobject at compile time. See
+ // the "Invisible" test case. In that case, we must not assume anything about
+ // access semantics.
+ qWarning() << "Warning: Refusing to generate non-lowercase name"
+ << elementName << "for unknown foreign type";
+ elementName.clear();
+ // Make it completely inaccessible.
+ // We cannot get enums from anonymous types after all.
+ accessSemantics = QLatin1String("none");
+ }
+ } else if (classDef->value(QLatin1String("gadget")).toBool()) {
+ accessSemantics = QLatin1String("value");
+ } else {
+ accessSemantics = QLatin1String("none");
+ }
}
}
diff --git a/src/qmltyperegistrar/qmltypescreator.cpp b/src/qmltyperegistrar/qmltypescreator.cpp
index c5b4bfd54f..15740579c0 100644
--- a/src/qmltyperegistrar/qmltypescreator.cpp
+++ b/src/qmltyperegistrar/qmltypescreator.cpp
@@ -115,7 +115,7 @@ void QmlTypesCreator::writeClassProperties(const QmlTypesClassDescription &colle
m_qml.writeScriptBinding(QLatin1String("attachedType"), enquote(collector.attachedType));
}
-void QmlTypesCreator::writeType(const QJsonObject &property, const QString &key, bool parsePointer)
+void QmlTypesCreator::writeType(const QJsonObject &property, const QString &key)
{
auto it = property.find(key);
if (it == property.end())
@@ -153,7 +153,7 @@ void QmlTypesCreator::writeType(const QJsonObject &property, const QString &key,
type = type.mid(listPropertySize, type.size() - listPropertySize - 1);
}
- if (parsePointer && type.endsWith(QLatin1Char('*'))) {
+ if (type.endsWith(QLatin1Char('*'))) {
isPointer = true;
type = type.left(type.size() - 1);
}
@@ -178,7 +178,7 @@ void QmlTypesCreator::writeProperties(const QJsonArray &properties)
if (it != obj.end())
m_qml.writeScriptBinding(QLatin1String("revision"), QString::number(it.value().toInt()));
- writeType(obj, QLatin1String("type"), true);
+ writeType(obj, QLatin1String("type"));
if (!obj.contains(QStringLiteral("privateClass"))) {
const auto bindable = obj.constFind(QLatin1String("bindable"));
@@ -227,7 +227,7 @@ void QmlTypesCreator::writeMethods(const QJsonArray &methods, const QString &typ
m_qml.writeScriptBinding(QLatin1String("name"), enquote(name));
if (revision != obj.end())
m_qml.writeScriptBinding(QLatin1String("revision"), QString::number(revision.value().toInt()));
- writeType(obj, QLatin1String("returnType"), false);
+ writeType(obj, QLatin1String("returnType"));
const auto isConstructor = obj.find(QLatin1String("isConstructor"));
if (isConstructor != obj.constEnd() && isConstructor->toBool())
m_qml.writeScriptBinding(QLatin1String("isConstructor"), QLatin1String("true"));
@@ -237,7 +237,7 @@ void QmlTypesCreator::writeMethods(const QJsonArray &methods, const QString &typ
const QString name = obj[QLatin1String("name")].toString();
if (!name.isEmpty())
m_qml.writeScriptBinding(QLatin1String("name"), enquote(name));
- writeType(obj, QLatin1String("type"), true);
+ writeType(obj, QLatin1String("type"));
m_qml.writeEndObject();
}
m_qml.writeEndObject();
diff --git a/src/qmltyperegistrar/qmltypescreator.h b/src/qmltyperegistrar/qmltypescreator.h
index 0908a1e047..3e8fa480a2 100644
--- a/src/qmltyperegistrar/qmltypescreator.h
+++ b/src/qmltyperegistrar/qmltypescreator.h
@@ -50,7 +50,7 @@ public:
private:
void writeClassProperties(const QmlTypesClassDescription &collector);
- void writeType(const QJsonObject &property, const QString &key, bool parsePointer);
+ void writeType(const QJsonObject &property, const QString &key);
void writeProperties(const QJsonArray &properties);
void writeMethods(const QJsonArray &methods, const QString &type);
void writeEnums(const QJsonArray &enums);
diff --git a/src/qmlworkerscript/doc/src/qmlworkerscript.qdoc b/src/qmlworkerscript/doc/src/qmlworkerscript.qdoc
index 8f7f5e546c..4b01425ab1 100644
--- a/src/qmlworkerscript/doc/src/qmlworkerscript.qdoc
+++ b/src/qmlworkerscript/doc/src/qmlworkerscript.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQml.WorkerScript 2.\QtMinorVersion
+ \qmlmodule QtQml.WorkerScript
\title Qt QML WorkerScript QML Types
\ingroup qmlmodules
\brief Provides QML types for worker scripts.
diff --git a/src/qmlxmllistmodel/qqmlxmllistmodel.cpp b/src/qmlxmllistmodel/qqmlxmllistmodel.cpp
index 2249eaeac5..cf324c5740 100644
--- a/src/qmlxmllistmodel/qqmlxmllistmodel.cpp
+++ b/src/qmlxmllistmodel/qqmlxmllistmodel.cpp
@@ -991,3 +991,5 @@ void QQmlXmlListModelQueryRunnable::readSubTree(const QString &prefix, QXmlStrea
}
QT_END_NAMESPACE
+
+#include "moc_qqmlxmllistmodel_p.cpp"
diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 2c2324d896..372df6cfd8 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -237,7 +237,7 @@ qt_internal_add_shaders(Quick "scenegraph_shaders"
PRECOMPILE
OPTIMIZED
PREFIX
- "/qt-project.org/scenegraph/shaders_ng"
+ "/qt-project.org"
FILES
"scenegraph/shaders_ng/24bittextmask.frag"
"scenegraph/shaders_ng/32bitcolortext.frag"
@@ -345,7 +345,6 @@ qt_internal_extend_target(Quick CONDITION QT_FEATURE_quick_designer
designer/qquickdesignersupportproperties.cpp designer/qquickdesignersupportproperties_p.h
designer/qquickdesignersupportpropertychanges.cpp designer/qquickdesignersupportpropertychanges_p.h
designer/qquickdesignersupportstates.cpp designer/qquickdesignersupportstates_p.h
- designer/qquickdesignerwindowmanager.cpp designer/qquickdesignerwindowmanager_p.h
)
qt_internal_extend_target(Quick CONDITION QT_FEATURE_accessibility
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp
index 933a5b5cbe..9a4ce960f1 100644
--- a/src/quick/accessible/qaccessiblequickitem.cpp
+++ b/src/quick/accessible/qaccessiblequickitem.cpp
@@ -448,6 +448,11 @@ QList<QQuickItem *> QAccessibleQuickItem::childItems() const
return accessibleUnignoredChildren(item());
}
+static bool isTextRole(QAccessible::Role role)
+{
+ return role == QAccessible::EditableText || role == QAccessible::StaticText;
+}
+
QAccessible::State QAccessibleQuickItem::state() const
{
QQuickAccessibleAttached *attached = QQuickAccessibleAttached::attachedProperties(item());
@@ -465,7 +470,7 @@ QAccessible::State QAccessibleQuickItem::state() const
state.offscreen = true;
if ((role() == QAccessible::CheckBox || role() == QAccessible::RadioButton) && object()->property("checked").toBool())
state.checked = true;
- if (item()->activeFocusOnTab() || role() == QAccessible::EditableText)
+ if (item()->activeFocusOnTab() || isTextRole(role()))
state.focusable = true;
if (item()->hasActiveFocus())
state.focused = true;
diff --git a/src/quick/designer/qquickdesignersupport.cpp b/src/quick/designer/qquickdesignersupport.cpp
index fe9bb945b4..24b22a2d0f 100644
--- a/src/quick/designer/qquickdesignersupport.cpp
+++ b/src/quick/designer/qquickdesignersupport.cpp
@@ -47,7 +47,6 @@
#include <QtQml/private/qabstractanimationjob_p.h>
#include <private/qqmlengine_p.h>
#include <private/qquickview_p.h>
-#include <private/qsgrenderloop_p.h>
#include <QtQuick/private/qquickstategroup_p.h>
#include <QtGui/QImage>
#include <private/qqmlvme_p.h>
@@ -55,9 +54,6 @@
#include <private/qqmldata_p.h>
#include <private/qsgadaptationlayer_p.h>
-#include "qquickdesignerwindowmanager_p.h"
-
-
QT_BEGIN_NAMESPACE
QQuickDesignerSupport::QQuickDesignerSupport()
@@ -453,11 +449,6 @@ void QQuickDesignerSupport::updateDirtyNode(QQuickItem *item)
QQuickWindowPrivate::get(item->window())->updateDirtyNode(item);
}
-void QQuickDesignerSupport::activateDesignerWindowManager()
-{
- QSGRenderLoop::setInstance(new QQuickDesignerWindowManager);
-}
-
void QQuickDesignerSupport::activateDesignerMode()
{
QQmlEnginePrivate::activateDesignerMode();
@@ -473,11 +464,6 @@ void QQuickDesignerSupport::enableComponentComplete()
QQmlVME::enableComponentComplete();
}
-void QQuickDesignerSupport::createOpenGLContext(QQuickWindow *window)
-{
- QQuickDesignerWindowManager::createOpenGLContext(window);
-}
-
void QQuickDesignerSupport::polishItems(QQuickWindow *window)
{
QQuickWindowPrivate::get(window)->polishItems();
diff --git a/src/quick/designer/qquickdesignersupport_p.h b/src/quick/designer/qquickdesignersupport_p.h
index fc46745e15..6d2da6aa35 100644
--- a/src/quick/designer/qquickdesignersupport_p.h
+++ b/src/quick/designer/qquickdesignersupport_p.h
@@ -143,14 +143,11 @@ public:
static void updateDirtyNode(QQuickItem *item);
- static void activateDesignerWindowManager();
static void activateDesignerMode();
static void disableComponentComplete();
static void enableComponentComplete();
- static void createOpenGLContext(QQuickWindow *window);
-
static void polishItems(QQuickWindow *window);
private:
diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp
index 862b57f2b7..8a45209363 100644
--- a/src/quick/designer/qquickdesignersupportitems.cpp
+++ b/src/quick/designer/qquickdesignersupportitems.cpp
@@ -72,7 +72,6 @@ static void stopAnimation(QObject *object)
// QQuickScriptAction *scriptAimation = qobject_cast<QQuickScriptAction*>(animation);
// if (scriptAimation) FIXME
// scriptAimation->setScript(QQmlScriptString());
- animation->setLoops(1);
animation->complete();
animation->setDisableUserControl();
} else if (timer) {
diff --git a/src/quick/designer/qquickdesignerwindowmanager.cpp b/src/quick/designer/qquickdesignerwindowmanager.cpp
deleted file mode 100644
index 18daab70e8..0000000000
--- a/src/quick/designer/qquickdesignerwindowmanager.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qquickdesignerwindowmanager_p.h"
-#include "private/qquickwindow_p.h"
-#include "private/qquickitem_p.h"
-#include <QtQuick/QQuickWindow>
-#if QT_CONFIG(opengl)
-#include <private/qsgdefaultrendercontext_p.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-QQuickDesignerWindowManager::QQuickDesignerWindowManager()
- : m_sgContext(QSGContext::createDefaultContext())
-{
- m_renderContext.reset(m_sgContext.data()->createRenderContext());
-}
-
-void QQuickDesignerWindowManager::show(QQuickWindow *window)
-{
- makeOpenGLContext(window);
-}
-
-void QQuickDesignerWindowManager::hide(QQuickWindow *)
-{
-}
-
-void QQuickDesignerWindowManager::windowDestroyed(QQuickWindow *)
-{
-}
-
-void QQuickDesignerWindowManager::makeOpenGLContext(QQuickWindow *window)
-{
-#if QT_CONFIG(opengl)
- if (!m_openGlContext) {
- m_openGlContext.reset(new QOpenGLContext());
- m_openGlContext->setFormat(window->requestedFormat());
- m_openGlContext->create();
- if (!m_openGlContext->makeCurrent(window))
- qWarning("QQuickWindow: makeCurrent() failed...");
- QSGDefaultRenderContext::InitParams params;
- params.sampleCount = qMax(1, m_openGlContext->format().samples());
- // ### glpurge Designer's RHI migration is left as a future exercise (QTBUG-78598)
- //params.openGLContext = m_openGlContext.data();
- params.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
- params.maybeSurface = window;
- m_renderContext->initialize(&params);
- } else {
- m_openGlContext->makeCurrent(window);
- }
-#else
- Q_UNUSED(window);
-#endif
-}
-
-void QQuickDesignerWindowManager::exposureChanged(QQuickWindow *)
-{
-}
-
-QImage QQuickDesignerWindowManager::grab(QQuickWindow *)
-{
- return QImage();
-}
-
-void QQuickDesignerWindowManager::maybeUpdate(QQuickWindow *)
-{
-}
-
-QSGContext *QQuickDesignerWindowManager::sceneGraphContext() const
-{
- return m_sgContext.data();
-}
-
-void QQuickDesignerWindowManager::createOpenGLContext(QQuickWindow *window)
-{
- window->create();
- window->update();
-}
-
-void QQuickDesignerWindowManager::update(QQuickWindow *window)
-{
- makeOpenGLContext(window);
-}
-
-QT_END_NAMESPACE
-
-
-#include "moc_qquickdesignerwindowmanager_p.cpp"
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp b/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
new file mode 100644
index 0000000000..3edab7d7a1
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
Binary files differ
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp b/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp
new file mode 100644
index 0000000000..05cb2f2276
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerButtonWithinBounds.webp
Binary files differ
diff --git a/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp b/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp
new file mode 100644
index 0000000000..0455097159
--- /dev/null
+++ b/src/quick/doc/images/pointerHandlers/tapHandlerOverlappingButtons.webp
Binary files differ
diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf
index 7875b5bd8e..ff4fbbc38d 100644
--- a/src/quick/doc/qtquick.qdocconf
+++ b/src/quick/doc/qtquick.qdocconf
@@ -30,13 +30,13 @@ qhp.QtQuick.subprojects.qmltypes.sortPages = true
qhp.QtQuick.subprojects.classes.title = Classes
qhp.QtQuick.subprojects.classes.title = C++ Classes
qhp.QtQuick.subprojects.classes.indexTitle = Qt Quick C++ Classes
-qhp.QtQuick.subprojects.classes.selectors = class fake:headerfile
+qhp.QtQuick.subprojects.classes.selectors = class doc:headerfile
qhp.QtQuick.subprojects.classes.sortPages = true
qhp.QtQuick.subprojects.examples.title = Examples
qhp.QtQuick.subprojects.examples.indexTitle = Qt Quick Examples and Tutorials
-qhp.QtQuick.subprojects.examples.selectors = fake:example
+qhp.QtQuick.subprojects.examples.selectors = doc:example
-tagfile = ../../../doc/qtquick/qtquick.tags
+tagfile = qtquick.tags
depends += \
qtcore \
@@ -58,35 +58,37 @@ depends += \
qtcmake
{headerdirs,sourcedirs} += \
- ..\
+ .. \
../../quick \
../../quickwidgets \
../../qmllocalstorage \
../../quicklayouts \
- ../../labs/animation \
- ../../labs/folderlistmodel
+ ../../labs
-exampledirs += ../../../examples/quick \
- snippets
+# both have their own documentation project
+excludedirs += \
+ ../../labs/platform \
+ ../../labs/models
-imagedirs += images
+exampledirs += \
+ ../../../examples/quick \
+ ../../qmlmodels/doc/snippets \
+ snippets
-#add particles and shapes sources
-headerdirs += ../../particles \
- ../../quickshapes
-sourcedirs += ../../particles \
- ../../quickshapes
+imagedirs += images
-#add imports directory because of dependencies
-headerdirs += ../../imports
-sourcedirs += ../../imports
+# Add particles and shapes sources
+{headerdirs,sourcedirs} += \
+ ../../particles \
+ ../../quickshapes
-#add plugins directory because of dependencies
-headerdirs += ../../plugins
-sourcedirs += ../../plugins
+# Add imports and plugins directories because of dependencies
+{headerdirs,sourcedirs} += \
+ ../../imports \
+ ../../plugins
excludefiles += ../util/qquickpropertychanges_p.h
-examples.fileextensions += "*.qm"
+examples.fileextensions += "*.qm"
manifestmeta.thumbnail.names += "QtQuick/Threaded ListModel Example" \
"QtQuick/QML Dynamic View Ordering Tutorial*"
@@ -100,6 +102,5 @@ navigation.qmltypespage = "Qt Quick QML Types"
# \svgcolor {#ffdead}
macro.svgcolor.HTML = "<div style=\"padding:10px;color:#fff;background:\1;\"></div>"
-# youtube video thumbnails that show up in offline and online docs
-HTML.extraimages += images/9BcAYDlpuT8.jpg
-qhp.QtQuick.extraFiles += images/9BcAYDlpuT8.jpg
+# YouTube video thumbnail that show up in offline docs
+{HTML.extraimages,qhp.QtQuick.extraFiles} += images/9BcAYDlpuT8.jpg
diff --git a/src/quick/doc/snippets/cmake-macros/examples.cmake b/src/quick/doc/snippets/cmake-macros/examples.cmake
deleted file mode 100644
index cecc59debc..0000000000
--- a/src/quick/doc/snippets/cmake-macros/examples.cmake
+++ /dev/null
@@ -1,6 +0,0 @@
-#! [qt5_import_qml_plugins]
-find_package(Qt5 COMPONENTS Quick QmlImportScanner)
-add_executable(myapp main.cpp)
-target_link_libraries(myapp Qt5::Quick)
-qt5_import_qml_plugins(myapp)
-#! [qt5_import_qml_plugins]
diff --git a/src/quick/doc/snippets/code/doc_src_qtquick.cmake b/src/quick/doc/snippets/code/doc_src_qtquick.cmake
index f575b40acc..733145fdc5 100644
--- a/src/quick/doc/snippets/code/doc_src_qtquick.cmake
+++ b/src/quick/doc/snippets/code/doc_src_qtquick.cmake
@@ -1,4 +1,4 @@
#! [0]
-find_package(Qt6 COMPONENTS Quick REQUIRED)
+find_package(Qt6 REQUIRED COMPONENTS Quick)
target_link_libraries(mytarget PRIVATE Qt6::Quick)
#! [0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
new file mode 100644
index 0000000000..b8a378ddcf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverModifiers.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: control.hovered ? "goldenrod" : shift.hovered ? "wheat" : "beige"
+
+ HoverHandler {
+ id: control
+ acceptedModifiers: Qt.ControlModifier
+ cursorShape: Qt.PointingHandCursor
+ }
+
+ HoverHandler {
+ id: shift
+ acceptedModifiers: Qt.ShiftModifier
+ cursorShape: Qt.CrossCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
new file mode 100644
index 0000000000..6bd6a40b1a
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverMouseOrStylus.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ width: 150; height: 50; radius: 3
+ color: mouse.hovered ? "goldenrod" : stylus.hovered ? "tomato" : "wheat"
+
+ HoverHandler {
+ id: stylus
+ acceptedDevices: PointerDevice.Stylus
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: mouse
+ acceptedDevices: PointerDevice.Mouse
+ cursorShape: Qt.PointingHandCursor
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
new file mode 100644
index 0000000000..5d82158baf
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverStylusOrEraser.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ id: rect
+ width: 150; height: 150
+
+ HoverHandler {
+ id: stylus
+ acceptedPointerTypes: PointerDevice.Pen
+ cursorShape: Qt.CrossCursor
+ }
+
+ HoverHandler {
+ id: eraser
+ acceptedPointerTypes: PointerDevice.Eraser
+ cursorShape: Qt.BlankCursor
+ target: Image {
+ parent: rect
+ source: "images/cursor-eraser.png"
+ visible: eraser.hovered
+ x: eraser.point.position.x
+ y: eraser.point.position.y - 32
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml
new file mode 100644
index 0000000000..1564aa16b5
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick 2.12
+
+Rectangle {
+ id: button
+ signal clicked
+
+ width: 150; height: 50; radius: 3
+ color: tapHandler.pressed ? "goldenrod" : hoverHandler.hovered ? "wheat" : "beige"
+ border.color: activeFocus ? "brown" : "transparent"
+ focus: true
+
+ HoverHandler {
+ id: hoverHandler
+ }
+
+ TapHandler {
+ id: tapHandler
+ onTapped: button.clicked()
+ }
+
+ Keys.onEnterPressed: button.clicked()
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
new file mode 100644
index 0000000000..e5488a89f2
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/images/cursor-eraser.png
Binary files differ
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandler.qml b/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
index 20be120120..138ad332d9 100644
--- a/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandler.qml
@@ -48,8 +48,7 @@
**
****************************************************************************/
//![0]
-import QtQuick 2.12
-import QtQuick.Window 2.2
+import QtQuick
Window {
width: 480
@@ -61,6 +60,7 @@ Window {
z: 10000
anchors.fill: parent
+ //![1]
PointHandler {
id: handler
acceptedDevices: PointerDevice.TouchScreen | PointerDevice.TouchPad
@@ -73,6 +73,7 @@ Window {
width: 20; height: width; radius: width / 2
}
}
+ //![1]
}
}
//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml
new file mode 100644
index 0000000000..a884672b0d
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedButtons.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 480; height: 320
+
+ Rectangle {
+ color: handler.active ? "tomato" : "wheat"
+ x: handler.point.position.x - width / 2
+ y: handler.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+
+ PointHandler {
+ id: handler
+ acceptedButtons: Qt.MiddleButton | Qt.RightButton
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml
new file mode 100644
index 0000000000..0229f3bb0a
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerAcceptedModifiers.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ id: feedbackPane
+ width: 480; height: 320
+
+ PointHandler {
+ id: control
+ acceptedModifiers: Qt.ControlModifier
+ cursorShape: Qt.PointingHandCursor
+ target: Rectangle {
+ parent: feedbackPane
+ color: control.active ? "indianred" : "khaki"
+ x: control.point.position.x - width / 2
+ y: control.point.position.y - height / 2
+ width: 20; height: width; radius: width / 2
+ }
+ }
+
+ PointHandler {
+ id: shift
+ acceptedModifiers: Qt.ShiftModifier | Qt.MetaModifier
+ cursorShape: Qt.CrossCursor
+ target: Rectangle {
+ parent: feedbackPane
+ color: shift.active ? "darkslateblue" : "lightseagreen"
+ x: shift.point.position.x - width / 2
+ y: shift.point.position.y - height / 2
+ width: 30; height: width; radius: width / 2
+ }
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml
new file mode 100644
index 0000000000..5bc98c1230
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerCanvasDrawing.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![0]
+import QtQuick
+
+Canvas {
+ id: canvas
+ width: 800
+ height: 600
+ antialiasing: true
+ renderTarget: Canvas.FramebufferObject
+ property var points: []
+ onPaint: {
+ if (points.length < 2)
+ return
+ var ctx = canvas.getContext('2d');
+ ctx.save()
+ ctx.strokeStyle = stylusHandler.active ? "blue" : "white"
+ ctx.lineCap = "round"
+ ctx.beginPath()
+ ctx.moveTo(points[0].x, points[0].y)
+ for (var i = 1; i < points.length; i++)
+ ctx.lineTo(points[i].x, points[i].y)
+ ctx.lineWidth = 3
+ ctx.stroke()
+ points = points.slice(points.length - 2, 1)
+ ctx.restore()
+ }
+
+ PointHandler {
+ id: stylusHandler
+ acceptedPointerTypes: PointerDevice.Pen
+ onPointChanged: {
+ canvas.points.push(point.position)
+ canvas.requestPaint()
+ }
+ }
+
+ PointHandler {
+ id: eraserHandler
+ acceptedPointerTypes: PointerDevice.Eraser
+ onPointChanged: {
+ canvas.points.push(point.position)
+ canvas.requestPaint()
+ }
+ }
+
+ Rectangle {
+ width: 10; height: 10
+ color: stylusHandler.active ? "green" : eraserHandler.active ? "red" : "beige"
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml b/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml
new file mode 100644
index 0000000000..49161f0abe
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/pointHandlerMargin.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 480; height: 320
+
+ Rectangle {
+ anchors.fill: handlingContainer
+ anchors.margins: -handler.margin
+ color: "beige"
+ }
+
+ Rectangle {
+ id: handlingContainer
+ width: 200; height: 200
+ anchors.centerIn: parent
+ border.color: "green"
+ color: handler.active ? "lightsteelblue" : "khaki"
+
+ Text {
+ text: "X"
+ x: handler.point.position.x - width / 2
+ y: handler.point.position.y - height / 2
+ visible: handler.active
+ }
+
+ PointHandler {
+ id: handler
+ margin: 30
+ }
+ }
+
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerButton.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerButton.qml
new file mode 100644
index 0000000000..02d0b4213b
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerButton.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Rectangle {
+ id: button
+ signal clicked
+ property alias text: buttonLabel.text
+
+ height: Math.max(Screen.pixelDensity * 7, buttonLabel.implicitHeight * 1.2)
+ width: Math.max(Screen.pixelDensity * 11, buttonLabel.implicitWidth * 1.3)
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.ReleaseWithinBounds
+ onTapped: button.clicked()
+ }
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml
new file mode 100644
index 0000000000..a6b1673d4c
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ id: button
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.ReleaseWithinBounds
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml
new file mode 100644
index 0000000000..f2e968599c
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerButtonWithinBounds.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ id: button
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.WithinBounds
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+}
+//![0]
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml
index deff59d034..2c682df584 100644
--- a/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerOnTapped.qml
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -48,7 +48,7 @@
**
****************************************************************************/
//![0]
-import QtQuick 2.12
+import QtQuick
Rectangle {
width: 100
@@ -56,8 +56,8 @@ Rectangle {
TapHandler {
acceptedButtons: Qt.LeftButton | Qt.RightButton
- onTapped: (eventPoint)=> console.log("tapped", eventPoint.event.device.name,
- "button", eventPoint.event.button,
+ onTapped: (eventPoint, button)=> console.log("tapped", eventPoint.device.name,
+ "button", button,
"@", eventPoint.scenePosition)
}
}
diff --git a/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml b/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml
new file mode 100644
index 0000000000..993330a5ec
--- /dev/null
+++ b/src/quick/doc/snippets/pointerHandlers/tapHandlerOverlappingButtons.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+//![0]
+import QtQuick
+
+Item {
+ width: 120; height: 80
+
+ component Button : Rectangle {
+ signal clicked
+ property alias text: buttonLabel.text
+
+ width: 80
+ height: 40
+ radius: 3
+ property color dark: Qt.darker(palette.button, 1.3)
+ gradient: Gradient {
+ GradientStop { position: 0.0; color: tapHandler.pressed ? dark : palette.button }
+ GradientStop { position: 1.0; color: dark }
+ }
+
+ SequentialAnimation on border.width {
+ id: tapFlash
+ running: false
+ loops: 3
+ PropertyAction { value: 2 }
+ PauseAnimation { duration: 100 }
+ PropertyAction { value: 0 }
+ PauseAnimation { duration: 100 }
+ }
+
+ //![1]
+ TapHandler {
+ id: tapHandler
+ gesturePolicy: TapHandler.DragThreshold // the default
+ onTapped: tapFlash.start()
+ }
+ //![1]
+
+ Text {
+ id: buttonLabel
+ text: "Click Me"
+ color: palette.buttonText
+ anchors.centerIn: parent
+ }
+ }
+
+ Button { x: 10; y: 10 }
+ Button { x: 30; y: 30 }
+}
+//![0]
diff --git a/src/quick/doc/src/advtutorial.qdoc b/src/quick/doc/src/advtutorial.qdoc
index 63c70067fd..66d0d125da 100644
--- a/src/quick/doc/src/advtutorial.qdoc
+++ b/src/quick/doc/src/advtutorial.qdoc
@@ -298,9 +298,6 @@ until the next chapter - where your application becomes alive!
Now we're going to do two things to liven up the game: animate the blocks and add a High Score system.
-We've also cleaned up the directory structure for our application files. We now have a lot of files, so all the
-JavaScript and QML files outside of \c samegame.qml have been moved into a new sub-directory named "content".
-
In anticipation of the new block animations, \c Block.qml file is now renamed to \c BoomBlock.qml.
\section3 Animating Block Movement
@@ -311,7 +308,7 @@ In \c BoomBlock.qml, we apply a \l SpringAnimation behavior to the \c x and \c y
block will follow and animate its movement in a spring-like fashion towards the specified position (whose
values will be set by \c samegame.js).Here is the code added to \c BoomBlock.qml:
-\snippet tutorials/samegame/samegame4/content/BoomBlock.qml 1
+\snippet tutorials/samegame/samegame4/BoomBlock.qml 1
The \c spring and \c damping values can be changed to modify the spring-like effect of the animation.
@@ -328,7 +325,7 @@ animate the opacity value so that it gradually fades in and out, instead of abru
visible and invisible. To do this, we'll apply a \l Behavior on the \c opacity property of the \c Image
type in \c BoomBlock.qml:
-\snippet tutorials/samegame/samegame4/content/BoomBlock.qml 2
+\snippet tutorials/samegame/samegame4/BoomBlock.qml 2
Note the \c{opacity: 0} which means the block is transparent when it is first created. We could set the opacity
in \c samegame.js when we create and destroy the blocks,
@@ -354,14 +351,14 @@ To fade out, we set \c dying to true instead of setting opacity to 0 when a bloc
Finally, we'll add a cool-looking particle effect to the blocks when they are destroyed. To do this, we first add a \l ParticleSystem in
\c BoomBlock.qml, like so:
-\snippet tutorials/samegame/samegame4/content/BoomBlock.qml 3
+\snippet tutorials/samegame/samegame4/BoomBlock.qml 3
To fully understand this you should read \l {Using the Qt Quick Particle System}, but it's important to note that \c emitRate is set
to zero so that particles are not emitted normally.
Also, we extend the \c dying State, which creates a burst of particles by calling the \c burst() method on the particles type. The code for the states now look
like this:
-\snippet tutorials/samegame/samegame4/content/BoomBlock.qml 4
+\snippet tutorials/samegame/samegame4/BoomBlock.qml 4
Now the game is beautifully animated, with subtle (or not-so-subtle) animations added for all of the
player's actions. The end result is shown below, with a different set of images to demonstrate basic theming:
@@ -378,20 +375,20 @@ To do this, we will show a dialog when the game is over to request the player's
This requires a few changes to \c Dialog.qml. In addition to a \c Text type, it now has a
\c TextInput child item for receiving keyboard text input:
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 0
+\snippet tutorials/samegame/samegame4/Dialog.qml 0
\dots 4
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 2
+\snippet tutorials/samegame/samegame4/Dialog.qml 2
\dots 4
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 3
+\snippet tutorials/samegame/samegame4/Dialog.qml 3
We'll also add a \c showWithInput() function. The text input will only be visible if this function
is called instead of \c show(). When the dialog is closed, it emits a \c closed() signal, and
other types can retrieve the text entered by the user through an \c inputText property:
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 0
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 1
+\snippet tutorials/samegame/samegame4/Dialog.qml 0
+\snippet tutorials/samegame/samegame4/Dialog.qml 1
\dots 4
-\snippet tutorials/samegame/samegame4/content/Dialog.qml 3
+\snippet tutorials/samegame/samegame4/Dialog.qml 3
Now the dialog can be used in \c samegame.qml:
@@ -401,9 +398,9 @@ When the dialog emits the \c closed signal, we call the new \c saveHighScore() f
The \c nameInputDialog is activated in the \c victoryCheck() function in \c samegame.js:
-\snippet tutorials/samegame/samegame4/content/samegame.js 3
+\snippet tutorials/samegame/samegame4/samegame.js 3
\dots 4
-\snippet tutorials/samegame/samegame4/content/samegame.js 4
+\snippet tutorials/samegame/samegame4/samegame.js 4
\section3 Storing High Scores Offline
@@ -411,7 +408,7 @@ Now we need to implement the functionality to actually save the High Scores tabl
Here is the \c saveHighScore() function in \c samegame.js:
-\snippet tutorials/samegame/samegame4/content/samegame.js 2
+\snippet tutorials/samegame/samegame4/samegame.js 2
First we call \c sendHighScore() (explained in the section below) if it is possible to send the high scores to an online database.
@@ -430,7 +427,7 @@ If the player entered their name we can send the data to the web service us
If the player enters a name, we send the data to the service using this code in \c samegame.js:
-\snippet tutorials/samegame/samegame4/content/samegame.js 1
+\snippet tutorials/samegame/samegame4/samegame.js 1
The \l XMLHttpRequest in this code is the same as the \c XMLHttpRequest() as you'll find in standard browser JavaScript, and can be used in the same way to dynamically get XML
or QML from the web service to display the high scores. We don't worry about the response in this case - we just post the high
diff --git a/src/quick/doc/src/concepts/effects/particles.qdoc b/src/quick/doc/src/concepts/effects/particles.qdoc
index abe721c5ab..aa89450439 100644
--- a/src/quick/doc/src/concepts/effects/particles.qdoc
+++ b/src/quick/doc/src/concepts/effects/particles.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQuick.Particles 2.\QtMinorVersion
+ \qmlmodule QtQuick.Particles
\title Qt Quick Particles QML Types
\ingroup qmlmodules
\brief Provides QML types for particle effects
diff --git a/src/quick/doc/src/concepts/input/focus.qdoc b/src/quick/doc/src/concepts/input/focus.qdoc
index 9862489f42..6dd5a4b4bc 100644
--- a/src/quick/doc/src/concepts/input/focus.qdoc
+++ b/src/quick/doc/src/concepts/input/focus.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -76,8 +76,9 @@ type whose text is determined by whether or not it has active focus.
An \l Item requests focus by setting the \c focus property to \c true.
For very simple cases simply setting the \c focus property is sometimes
-sufficient. If we run the following example with \l{qtquick-qmlscene.html}
-{qmlscene}, we see that the \c {keyHandler} type has active focus and
+sufficient. If we run the following example with the
+\l {Prototyping with the QML Runtime Tool}{qml tool},
+we see that the \c {keyHandler} type has active focus and
pressing the \c A, \c B, or \c C keys modifies the text appropriately.
\snippet qml/focus/basicwidget.qml focus true
@@ -196,7 +197,7 @@ property. As the \l ListView is a focus scope, this doesn't affect the
rest of the application. However, if the \l ListView itself has
active focus this causes the delegate itself to receive active focus.
In this example, the root type of the delegate is also a focus scope,
-which in turn gives active focus to the \c {Text} type that actually performs
+which in turn gives active focus to the \l {TextInput} type that actually performs
the work of handling the \c {Return} key.
All of the QML view classes, such as \l PathView and \l GridView, behave
diff --git a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
index 2ac9860e6f..7a05583a82 100644
--- a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
+++ b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -30,20 +30,23 @@
\title Qt Quick Input Handlers
\brief A module with a set of QML elements that handle events from input devices in a user interface.
- Qt Quick Input Handlers are a set of QML types used to handle events from
- keyboard, touch, mouse, and stylus devices in a UI. In contrast to event-handling
- items, such as \l MouseArea and \l Flickable, input handlers are explicitly non-visual,
- require less memory and are intended to be used in greater numbers: one
- handler instance per aspect of interaction. Each input handler instance
- handles certain events on behalf of its \c parent Item. Thus the visual and
+ Qt Quick Input Handlers are a set of QML types used to handle
+ \l {QInputEvent}{events} from keyboard, touch, mouse, and stylus
+ \l {QInputDevice}{devices} in a UI. In contrast to event-handling
+ items, such as \l MouseArea and \l Flickable, input handlers are explicitly
+ non-visual, require less memory and are intended to be used in greater
+ numbers: one handler instance per aspect of interaction. Each input handler
+ instance handles certain events on behalf of its
+ \l {QQuickPointerHandler::parent()}{parent} Item. Thus the visual and
behavioral concerns are better separated, and the behavior is built up by
finer-grained composition.
- In Qt 5.10, these handlers were introduced in a separate Qt.labs.handlers module.
- Now they are included with Qt Quick since 5.12. The pre-existing
- \l Keys attached property is similar in concept, so we refer to the
- pointing-device-oriented handlers plus \c Keys together as the set of Input Handlers.
- We expect to offer more attached-property use cases in future versions of Qt.
+ The \l {Pointer Handlers Example} demonstrates some use cases for these.
+
+ The pre-existing \l Keys attached property is similar in concept, so we
+ refer to the pointing-device-oriented handlers plus \c Keys together as the
+ set of Input Handlers. We expect to offer more attached-property use cases
+ in future versions of Qt.
\section1 Input Handlers
@@ -60,7 +63,45 @@
\li Each Item can have unlimited Handlers
\endlist
- \omit TODO actual overview with snippets and stuff \endomit
+ \section1 Handlers Manipulating Items
+
+ Some Handlers add interactivity simply by being declared inside an Item:
+
+ \snippet pointerHandlers/dragHandler.qml 0
+
+ \section1 Handler Properties and Signals
+
+ All Handlers have properties that can be used in bindings, and signals that
+ can be handled to react to input:
+
+ \snippet pointerHandlers/hoverTapKeyButton.qml 0
+
+ \section1 Pointer Grab
+
+ An important concept with Pointer Handlers is the type of grabs that they
+ perform. The only kind of grab an Item can take is the exclusive grab: for
+ example if you call \l QPointerEvent::setExclusiveGrabber(), the following
+ mouse moves and mouse release event will be sent only to that object. (As a
+ workaround to this exclusivity, see \l QQuickItem::setFiltersChildMouseEvents()
+ and \l QQuickItem::childMouseEventFilter().) However Pointer Handlers have
+ an additional mechanism available: the
+ \l {QPointerEvent::addPassiveGrabber()} {passive grab}. Mouse and touch
+ \l {QEventPoint::state()}{press} events are delivered by visiting all the
+ Items in top-down Z order: first each Item's child Handlers, and then the
+ \l {QQuickItem::event()}{Item} itself. At the time a press event is
+ delivered, a Handler can take either a passive or an exclusive grab
+ depending on its needs. If it takes a passive grab, it is guaranteed to
+ receive the updates and the release, even if other Items or Handlers in the
+ scene take any kind of grab, passive or exclusve. Some Handlers (such as
+ PointHandler) can work only with passive grabs; others require exclusive
+ grabs; and others can "lurk" with passive grabs until they detect that a
+ gesture is being performed, and then make the transition from passive to
+ exclusive grab. TapHandler's grabbing behavior is
+ \l {TapHandler::gesturePolicy}{configurable}.
+
+ When a grab transition is requested, \l PointerHandler::grabPermissions,
+ \l QQuickItem::keepMouseGrab() and \l QQuickItem::keepTouchGrab() control
+ whether the transition will be allowed.
\section1 Related Information
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
index 369c2f4444..429bd6e854 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc
@@ -103,9 +103,16 @@
\l{Layout::minimumWidth}{minimum}, \l{Layout::preferredWidth}{preferred},
and \l{Layout::maximumWidth}{maximum} sizes of all items where \l{Layout::fillWidth}{Layout.fillWidth} or
\l{Layout::fillHeight}{Layout.fillHeight} is set to \c true.
+
+ The \l{Layout::preferredWidth}{preferred} width and height is the \e actual width and
+ height of an item if the layout is not bound to a specific size itself. If the layout is set
+ to a specific size, it will distribute additional space based on the ratio of preferred sizes
+ of its items (taking minimum and maximum sizes into account).
+
For instance, the following will produce a layout with two rectangles lying side-by-side that
stretches horizontally. The azure rectangle can be resized from 50x150 to 300x150, and the plum
- rectangle can be resized from 100x100 to ∞x100.
+ rectangle can be resized from 100x100 to ∞x100. As long as the minimum and maximum width of each
+ item is not reached, the plum rectangle will have two times the width of the azure one.
\snippet qml/windowconstraints.qml rowlayout
diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
index 9ea8759318..0df832cca9 100644
--- a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
+++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
- \qmlmodule QtQuick.Layouts 1.\QtMinorVersion
+ \qmlmodule QtQuick.Layouts
\title Qt Quick Layouts QML Types
\ingroup qmlmodules
\brief Provides QML types for arranging QML items in a user interface.
diff --git a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
index 1f3602cde1..574dfcb58f 100644
--- a/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
+++ b/src/quick/doc/src/concepts/positioning/righttoleft.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -175,17 +175,11 @@ You can test that the layout direction works as expected by running your Qt Quic
the compiled translation file:
\code
-qmlscene myapp.qml -translation myapp.qm
+qml myapp.qml -translation myapp.qm
\endcode
-You can test your application in right-to-left layout direction simply by executing qmlscene with a
-command-line parameter "-reverse":
-
-\code
-qmlscene myapp.qml -reverse
-\endcode
-
-The layout direction can also be set from C++ by calling the static function \l QGuiApplication::setLayoutDirection():
+You can test your application in right-to-left layout direction by calling the
+static function \l QGuiApplication::setLayoutDirection():
\code
QGuiApplication app(argc, argv);
diff --git a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
index faec8df7e4..b0a66cfb5f 100644
--- a/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
+++ b/src/quick/doc/src/concepts/visualcanvas/scenegraph.qdoc
@@ -194,6 +194,7 @@ throttling, use the \c basic render loop instead by setting \c
{QSG_RENDER_LOOP=basic} in the environment.
\section2 Threaded Render Loop ('threaded')
+\target threaded_render_loop
On many configurations, the scene graph rendering will happen on a
dedicated render thread. This is done to increase parallelism of
diff --git a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
index 7f5e0fa760..9aa404a612 100644
--- a/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-bestpractices.qdoc
@@ -52,11 +52,16 @@ options that align with the latest UI design trends. If these UI controls do not
satisfy your application's needs, only then it is recommended to create a
custom control.
+You can use the controls when you design UIs in Qt Design Studio. In addition,
+it provides timeline-based animations, visual effects, layouts, and a
+live-preview for prototyping applications.
\section2 Related Information
\list
\li \l{Qt Quick Controls}
+\li \l{Customizing Qt Quick Controls}
\li \l{Qt Quick}
+\li \l{Qt Design Studio Manual}
\endlist
\omit
@@ -87,66 +92,37 @@ of the target OS.
For example, consider the following project directory structure:
\badcode
-project
+MyModule
├── images
│ ├── image1.png
│ └── image2.png
-├── project.pro
-└── qml
- └── main.qml
+├── CMakeLists.txt
+└── main.qml
\endcode
-The following entry in \c project.pro ensures that the resources are built into
-the application binary, making them available when needed:
+You may represent this structure as a \l{qt_add_qml_module}{CMake QML Module} in the following way:
-\badcode
- RESOURCES += \
- qml/main.qml \
- images/image1.png \
- images/image2.png
-\endcode
-
-A more convenient approach is to use the
-\l {files(pattern[, recursive=false])}{wildcard syntax} to select several files
-at once:
-
-\badcode
- RESOURCES += \
- $$files(qml/*.qml) \
- $$files(images/*.png)
-\endcode
-
-This approach is convenient for applications that depend on a limited number
-of resources. However, whenever a new file is added to \c RESOURCES using this
-approach, it causes \e all of the other files in \c RESOURCES to be recompiled
-as well. This can be inefficient, especially for large sets of files.
-In this case, a better approach is to separate each type of resource into its
-own \l [Qt Core] {Resource Collection Files}{.qrc} file. For example, the snippet
-above could be changed to the following:
-
-\badcode
- qml.files = $$files(*.qml)
- qml.prefix = /qml
- RESOURCES += qml
-
- images.files = $$files(*.png)
- images.prefix = /images
- RESOURCES += images
+\code
+qt_add_qml_module(my_module
+ URI MyModule
+ VERSION 1.0
+ QML_FILES
+ main.qml
+ RESOURCES
+ images/image1.png
+ images/image2.png
+ # ...
+)
\endcode
-Now, whenever a QML file is changed, only the QML files have to be recompiled.
-
-Sometimes it can be necessary to have more control over the path for a
-specific file managed by the resource system. For example, if we wanted to give
-\c image2.png an alias, we would need to switch to an explicit \c .qrc file.
-\l {Creating Resource Files} explains how to do this in detail.
+All QML files listed under \c {QML_FILES} will automatically get compiled \l {Ahead-of-Time Compilation}{ahead of time}.
\section2 Related Information
\list
\li \l{The Qt Resource System}
\endlist
-\section1 Separate UI from Logic
+\section1 Separate UI from Business Logic
One of the key goals that most application developers want to achieve is to
create a maintainable application. One of the ways to achieve this goal is
@@ -162,8 +138,8 @@ reasons why an application's UI should be written in QML:
\li JavaScript can easily be used in QML to respond to events.
\endlist
-Being a strongly typed language, C++ is best suited for an application's logic.
-Typically, such code performs tasks such as complex calculations
+Being a strongly typed language, C++ is best suited for an application's
+business logic. Typically, such code performs tasks such as complex calculations
or data processing, which are faster in C++ than QML.
Qt offers various approaches to integrate QML and C++ code in an application.
@@ -174,12 +150,6 @@ sufficient.
The following snippet demonstrates examples of models written in QML:
\qml
- model: ListModel {
- ListElement { name: "Item 1" }
- ListElement { name: "Item 2" }
- ListElement { name: "Item 3" }
- }
-
model: [ "Item 1", "Item 2", "Item 3" ]
model: 10
@@ -188,135 +158,21 @@ The following snippet demonstrates examples of models written in QML:
Use \l {QAbstractItemModel Subclass}{C++} for dynamic data sets that are large
or frequently modified.
-\section2 Interacting with QML from C++
-
-Although Qt enables you to manipulate QML from C++, it is not recommended to do
-so. To explain why, let's take a look at a simplified example.
-
-\section3 Pulling References from QML
-
-Suppose we were writing the UI for a settings page:
-
-\qml
- import QtQuick
- import QtQuick.Controls
-
- Page {
- Button {
- text: qsTr("Restore default settings")
- }
- }
-\endqml
-
-We want the button to do something in C++ when it is clicked. We know objects
-in QML can emit change signals just like they can in C++, so we give the button
-an \l [QML]{QtObject::}{objectName} so that we can find it from C++:
-
-\qml
- Button {
- objectName: "restoreDefaultsButton"
- text: qsTr("Restore default settings")
- }
-\endqml
-
-Then, in C++, we find that object and connect to its change signal:
-
-\code
- #include <QGuiApplication>
- #include <QQmlApplicationEngine>
- #include <QSettings>
-
- class Backend : public QObject
- {
- Q_OBJECT
-
- public:
- Backend() {}
-
- public slots:
- void restoreDefaults() {
- settings.setValue("loadLastProject", QVariant(false));
- }
-
- private:
- QSettings settings;
- };
-
- int main(int argc, char *argv[])
- {
- QGuiApplication app(argc, argv);
-
- QQmlApplicationEngine engine;
- engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
- if (engine.rootObjects().isEmpty())
- return -1;
-
- Backend backend;
-
- QObject *rootObject = engine.rootObjects().first();
- QObject *restoreDefaultsButton = rootObject->findChild<QObject*>("restoreDefaultsButton");
- QObject::connect(restoreDefaultsButton, SIGNAL(clicked()),
- &backend, SLOT(restoreDefaults()));
-
- return app.exec();
- }
-
- #include "main.moc"
-\endcode
-
-With this approach, references to objects are "pulled" from QML.
-The problem with this is that the C++ logic layer depends on the QML
-presentation layer. If we were to refactor the QML in such a way that the
-\c objectName changes, or some other change breaks the ability for the C++
-to find the QML object, our workflow becomes much more complicated and tedious.
-
-\section3 Pushing References to QML
+\section2 Exposing Data from C++ to QML
Refactoring QML is a lot easier than refactoring C++, so in order to make
maintenance pain-free, we should strive to keep C++ types unaware of QML as
much as possible. This can be achieved by "pushing" references to C++ types
-into QML:
-
-\code
- int main(int argc, char *argv[])
- {
- QGuiApplication app(argc, argv);
-
- Backend backend;
+into QML.
- QQmlApplicationEngine engine;
- engine.rootContext()->setContextProperty("backend", &backend);
- engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
- if (engine.rootObjects().isEmpty())
- return -1;
-
- return app.exec();
- }
-\endcode
-
-The QML then calls the C++ slot directly:
-
-\qml
- import QtQuick
- import QtQuick.Controls
-
- Page {
- Button {
- text: qsTr("Restore default settings")
- onClicked: backend.restoreDefaults()
- }
- }
-\endqml
+This can be done by using \l {Required properties}{required properties} and
+setting them via \l QQmlApplicationEngine::setInitialProperties. It is also
+possible to create one or multiple \l {QML_SINGLETON}{singletons} which will
+return all the data the C++ side wants to provide to QML.
With this approach, the C++ remains unchanged in the event that the QML needs
to be refactored in the future.
-In the example above, we set a context property on the root context to expose
-the C++ object to QML. This means that the property is available to every
-component loaded by the engine. Context properties are useful for objects that
-must be available as soon as the QML is loaded and cannot be instantiated in
-QML.
-
For a quick guide to choosing the correct approach to expose C++ types to QML,
see \l {Choosing the Correct Integration Method Between C++ and QML}.
@@ -326,6 +182,22 @@ see \l {Choosing the Correct Integration Method Between C++ and QML}.
\li \l{Qt Quick Controls - Chat Tutorial}{Chat application tutorial}
\endlist
+\section1 Using Qt Design Studio
+
+Qt Design Studio uses UI files that have the filename extension \e {.ui.qml}
+to separate the visual parts of the UI from the UI logic you implement in
+\e {.qml} files. You should edit UI files only in the \uicontrol {2D} view in
+Qt Design Studio. If you use some other tool to add code that Qt Design Studio
+does not support, it displays error messages. Fix the errors to enable visual
+editing of the UI files again. Typically, you should move the unsupported code
+to a \e {.qml} file.
+
+\section2 Related Information
+
+\list
+ \li \l{Qt Design Studio: UI Files}
+\endlist
+
\section1 Using Qt Quick Layouts
Qt offers Qt Quick Layouts to arrange Qt Quick items visually in a layout.
diff --git a/src/quick/doc/src/guidelines/qtquick-tool-qmllint.qdoc b/src/quick/doc/src/guidelines/qtquick-tool-qmllint.qdoc
index ad40e850d5..0f21e1cae3 100644
--- a/src/quick/doc/src/guidelines/qtquick-tool-qmllint.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-tool-qmllint.qdoc
@@ -65,6 +65,47 @@ add them via the \c{-I} flag.
To get an overview and explanation of all available command line options, run \c{qmllint --help}.
+\section2 Disabling warnings inline
+
+You may at any point disable warnings temporarily in a file using \c{// qmllint
+disable}.
+
+You can do this at the end of a line when a single line produces warnings:
+
+\code
+Item {
+ property string foo
+ Item {
+ property string bar: foo // qmllint disable unqualified
+ }
+}
+\endcode
+
+Alternatively you can disable comments for a block of lines by putting the
+comment in a line only containing \c{// qmllint disable}, ending the block with
+\c{// qmllint enable}:
+
+\code
+Item {
+ property string foo
+ Item {
+ // qmllint disable unqualified
+ property string bar: foo
+ property string bar2: foo
+ // qmllint enable unqualified
+ }
+}
+\endcode
+
+qmllint interprets all single line comments starting with \c {qmllint} as
+directives. Thus you may not start a comment that way unless you wish to enable
+or disable warnings.
+
+\note As done in the examples above it is preferable to explicitly specify the
+warning or a list of warnings you want to disable instead of disabling all
+warnings. This can be done by simply listing warning categories after \c{qmllint disable} (the names are
+the same as the options listed in \c{--help}).
+
\section2 Settings
In addition to passing command-line options, you can also
@@ -94,5 +135,5 @@ level.
This can be used to more easily integrate qmllint in your pre-commit hooks or
CI testing.
-\sa \l{Type Description Files}{qmltypes}
+\sa {Type Description Files}
*/
diff --git a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
index 34dc4c2c22..96d2163eda 100644
--- a/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
+++ b/src/quick/doc/src/guidelines/qtquick-toolsnutilities.qdoc
@@ -35,83 +35,64 @@ especially for Qt Quick developers. The following sections provide a brief
introduction to those tools and utilities, and provide links to further
information about them.
-\section1 Qt Quick Designer
+\section1 Qt Creator
+
+The \l{Qt Creator Manual}{Qt Creator} IDE is the key tool that enhances the overall developer
+experience of working with Qt and Qt Quick. Its editing, formatting, profiling and
+debugging features for Qt Quick make working with Qt Quick easier.
+
+\section1 Qt Design Studio
-The Qt Quick Designer enables designing Qt Quick-based UIs using simple
+\l{Qt Design Studio} enables designing Qt Quick-based UIs using simple
drag-n-drop gestures that most designers are familiar with. It offers UI
elements from the Qt Quick and Qt Quick Controls modules, as well as
integration for custom UI elements.
-The following is a list of example applications that use UIs created by
-the Qt Quick Designer:
-
-\list
- \li \l{Qt Quick Controls - Contact List}
- \li \l{Qt Quick Controls - Flat Style}
-\endlist
-
-\section2 QML Debugger and Profiler
+\section1 QML Debugger
-Being a declarative language, a piece of QML code provides minimal details
-about the entities defined. In such a scenario, the QML debugger is a very
-useful utility that enables:
+The \l{QML debugger} is a very useful utility that enables:
\list
\li debugging JavaScript functions,
\li executing JavaScript expressions,
\li and inspecting QML properties.
\endlist
-Besides this, a QML profiler enables you to get necessary diagnostic information,
+The QML debugger is part of both \l{Qt Creator} and \l{Qt Design Studio}.
+
+\section1 QML Profiler
+
+The \l{QML profiler} enables you to get necessary diagnostic information,
allowing you to analyze the application code for performance issues. For
example, too much JavaScript in each frame, long-running C++ functions, and
so on.
-\section2 Related Information
-\list
- \li \l{QML Debugger}
- \li \l{QML Profiler}
-\endlist
+The profiler is part of both \l{Qt Creator} and \l{Qt Design Studio}.
-\section1 QmlLive, GammaRay, and Squish
+\section1 QmlLive
-QmlLive is a 3rd party tool that offers a QML runtime capable of rendering
+\l{QmlLive} is a 3rd party tool that offers a QML runtime capable of rendering
changes to the code in realtime. It avoids the need to rebuild the
application after every code change and install it on the target device.
You can also extend it to build a custom runtime that suits your needs.
-GammaRay is a useful utility that provides diagnostic information
+\section1 GammaRay
+
+\l{GammaRay} is a useful utility that provides diagnostic information
about your application. It is similar to the QML Profiler described in the
earlier section, but offers a lot more. For example, the number of items or
QObjects created, function calls made, time taken by each function call,
property value introspection at runtime, and so on. Such information is very
handy, especially while debugging QML applications.
-Squish is a well-known testing tool that automates UI testing by recording
+\section1 Squish
+
+\l{Squish} is a well-known testing tool that automates UI testing by recording
your actions or running scripts. Once the tests are setup, UI tests are a lot
easier to run.
-\section2 Related Information
-\list
- \li \l{QmlLive}
- \li \l{GammaRay}
- \li \l{Squish}
-\endlist
-
-\section1 Qt Creator
-
-The Qt Creator IDE is the key tool that enhances the overall developer experience of
-working with Qt Quick. Its auto-completion and debugging features make working
-with Qt Quick easier. Besides this, most of the tools and utilities
-mentioned in the earlier sections are integrated into it, with the possibility of
-integrating 3rd party tools such as QmlLive and GammaRay.
-
-\section2 Related Information
-\list
-\li \l{Qt Creator Manual}
-\endlist
-
\section1 qmllint
-\e qmllint is a tool shipped with Qt, that verifies the syntatic validity of QML files.
+
+\l{qmllint} is a tool shipped with Qt, that verifies the syntatic validity of QML files.
It also warns about some QML anti-patterns. If you want to disable a specific
warning type, you can find the appropriate flag for doing so by passing \c{--help} on the command line.
@@ -130,7 +111,4 @@ by specifying the \c{-n} flag.
By default, qmlformat writes the formatted version of the file to stdout.
If you wish to have your file updated in-place specify the \c{-i} flag.
-
-\section2 Related Information
-\sa {QML Coding Conventions}
*/
diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc
index b86725f4ad..e47a137330 100644
--- a/src/quick/doc/src/qmltypereference.qdoc
+++ b/src/quick/doc/src/qmltypereference.qdoc
@@ -26,7 +26,7 @@
****************************************************************************/
/*!
-\qmlmodule QtQuick 2.\QtMinorVersion
+\qmlmodule QtQuick
\title Qt Quick QML Types
\ingroup qmlmodules
\brief Provides graphical QML types.
diff --git a/src/quick/doc/src/qt6-changes.qdoc b/src/quick/doc/src/qt6-changes.qdoc
index 58a7ebb3e1..defacd95a1 100644
--- a/src/quick/doc/src/qt6-changes.qdoc
+++ b/src/quick/doc/src/qt6-changes.qdoc
@@ -138,7 +138,7 @@
OpenGL. It will not be functional when using another graphics API, such as
Vulkan or Metal. Applications relying on QQuickWidget should force the usage
of OpenGL by calling
- \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi)} in their
+ \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL)} in their
main() function.
\section2 Changes to QQuick* APIs
@@ -206,7 +206,7 @@
not be functional when using another graphics API, such as Vulkan or Metal.
Applications relying on QQuickFramebufferObject should force the usage of
OpenGL by calling
- \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi)} in their
+ \c{QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL)} in their
main() function.
\li QQuickRenderControl has a slightly changed API: grab() is now
diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc
index 46dfa5651f..a8665a3641 100644
--- a/src/quick/doc/src/qtquick.qdoc
+++ b/src/quick/doc/src/qtquick.qdoc
@@ -148,6 +148,7 @@ Additional Qt Quick information:
\li \l{Qt Quick Test QML Types}{Tests} - contains types for writing unit test for a QML application
\endlist
\li \l{Qt Quick Examples and Tutorials}
+\li \l{Qt Quick Tools and Utilities}
\li \l{Best Practices for QML and Qt Quick}{Qt Quick Guidelines}
\endlist
diff --git a/src/quick/doc/src/tutorial.qdoc b/src/quick/doc/src/tutorial.qdoc
index e84753d895..040685fae2 100644
--- a/src/quick/doc/src/tutorial.qdoc
+++ b/src/quick/doc/src/tutorial.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@@ -100,11 +100,13 @@ The \c font.pointSize and \c font.bold properties are related to fonts and use t
\section2 Viewing the Example
-To view what you have created, run the \l{Prototyping with qmlscene}{qmlscene} tool (located in the \c bin directory) with your filename as the first argument.
-For example, to run the provided completed Tutorial 1 example from the install location, you would type:
+To view what you have created, run the
+\l{Prototyping with the QML Runtime Tool}{qml tool} (located in the
+\c bin directory) with your filename as the first argument. For example, to run
+the provided completed Tutorial 1 example from the install location, you would type:
\code
-qmlscene tutorials/helloworld/tutorial1.qml
+qml tutorials/helloworld/tutorial1.qml
\endcode
*/
diff --git a/src/quick/handlers/qquickdragaxis.cpp b/src/quick/handlers/qquickdragaxis.cpp
index 88470c8a7d..806b5d705a 100644
--- a/src/quick/handlers/qquickdragaxis.cpp
+++ b/src/quick/handlers/qquickdragaxis.cpp
@@ -76,3 +76,5 @@ void QQuickDragAxis::setEnabled(bool enabled)
}
QT_END_NAMESPACE
+
+#include "moc_qquickdragaxis_p.cpp"
diff --git a/src/quick/handlers/qquickdraghandler.cpp b/src/quick/handlers/qquickdraghandler.cpp
index 233516c3a3..8c9464ee55 100644
--- a/src/quick/handlers/qquickdraghandler.cpp
+++ b/src/quick/handlers/qquickdraghandler.cpp
@@ -88,7 +88,7 @@ Q_LOGGING_CATEGORY(lcDragHandler, "qt.quick.handler.drag")
At this time, drag-and-drop is not yet supported.
- \sa Drag, MouseArea
+ \sa Drag, MouseArea, {Pointer Handlers Example}
*/
QQuickDragHandler::QQuickDragHandler(QQuickItem *parent)
@@ -131,13 +131,13 @@ void QQuickDragHandler::onGrabChanged(QQuickPointerHandler *grabber, QPointingDe
This property holds the snap mode.
- The snap mode configures snapping of the \l target item's center to the event point.
+ The snap mode configures snapping of the \l target item's center to the \l eventPoint.
Possible values:
\value DragHandler.SnapNever Never snap
- \value DragHandler.SnapAuto The \l target snaps if the event point was pressed outside of the \l target
- item \e and the \l target is a descendant of \l parentItem (default)
- \value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the event point was pressed outside of the \l target
+ \value DragHandler.SnapAuto The \l target snaps if the \l eventPoint was pressed outside of the \l target
+ item \e and the \l target is a descendant of \l {PointerHandler::}{parent} item (default)
+ \value DragHandler.SnapWhenPressedOutsideTarget The \l target snaps if the \l eventPoint was pressed outside of the \l target
\value DragHandler.SnapAlways Always snap
*/
QQuickDragHandler::SnapMode QQuickDragHandler::snapMode() const
@@ -371,7 +371,7 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
/*!
\readonly
\qmlproperty QVector2D QtQuick::DragHandler::translation
- \deprecated Use activeTranslation
+ \deprecated [6.2] Use activeTranslation
*/
/*!
@@ -395,3 +395,5 @@ void QQuickDragHandler::setActiveTranslation(const QVector2D &trans)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickdraghandler_p.cpp"
diff --git a/src/quick/handlers/qquickhandlerpoint.cpp b/src/quick/handlers/qquickhandlerpoint.cpp
index c3149983c0..52513f8273 100644
--- a/src/quick/handlers/qquickhandlerpoint.cpp
+++ b/src/quick/handlers/qquickhandlerpoint.cpp
@@ -49,7 +49,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
\inqmlmodule QtQuick
\brief An event point.
- A QML representation of a QEventPoint.
+ A handler-owned QML representation of a QEventPoint.
It's possible to make bindings to properties of a handler's current
\l {SinglePointHandler::point}{point} or
@@ -58,12 +58,12 @@ Q_DECLARE_LOGGING_CATEGORY(lcTouchTarget)
\snippet pointerHandlers/dragHandlerNullTarget.qml 0
The point is kept up-to-date when the DragHandler is actively responding to
- an EventPoint; but after the point is released, or when the current point is
+ an \l eventPoint; but after the point is released, or when the current point is
being handled by a different handler, \c position.x and \c position.y are 0.
- \note This is practically identical to QtQuick::EventPoint; however an
- EventPoint is a long-lived QObject which is invalidated between gestures
- and reused for subsequent event deliveries. Continuous bindings to its
+ \note This is practically identical to \l eventPoint; however an eventPoint
+ is a short-lived copy of a long-lived Q_GADGET which is invalidated between
+ gestures and reused for subsequent event deliveries. Continuous bindings to its
properties are not possible, and an individual handler cannot rely on it
outside the period when that point is part of an active gesture which that
handler is handling. HandlerPoint is a Q_GADGET that the handler owns.
@@ -186,7 +186,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
During a touch gesture, from the time that the first finger is pressed
until the last finger is released, each touchpoint will have a unique ID
number. Likewise, if input from multiple devices occurs (for example
- simultaneous mouse and touch presses), all the current event points from
+ simultaneous mouse and touch presses), all the current \l{eventPoint}{eventPoints} from
all the devices will have unique IDs.
\note Do not assume that id numbers start at zero or that they are
@@ -223,7 +223,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\qmlproperty QPointF QtQuick::HandlerPoint::position
\brief The position within the \c parent Item
- This is the position of the event point relative to the bounds of
+ This is the position of the \l eventPoint relative to the bounds of
the \l {PointerHandler::parent} {parent}.
*/
@@ -232,7 +232,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\qmlproperty QPointF QtQuick::HandlerPoint::scenePosition
\brief The position within the scene
- This is the position of the event point relative to the bounds of the Qt
+ This is the position of the \l eventPoint relative to the bounds of the Qt
Quick scene (typically the whole window).
*/
@@ -290,7 +290,7 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
This is a velocity vector pointing in the direction of movement, in logical
pixels per second. It has x and y components, at least one of which will be
nonzero when this point is in motion. It holds the average recent velocity:
- how fast and in which direction the event point has been moving recently.
+ how fast and in which direction the \l eventPoint has been moving recently.
\sa QtQuick::TouchPoint::velocity, QEventPoint::velocity
*/
@@ -345,4 +345,13 @@ void QQuickHandlerPoint::reset(const QVector<QQuickHandlerPoint> &points)
\sa QtQuick::TouchPoint::ellipseDiameters, QEventPoint::ellipseDiameters
*/
+/*!
+ \readonly
+ \qmlproperty PointerDevice QtQuick::handlerPoint::device
+
+ This property holds the device that the point (and its event) came from.
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qquickhandlerpoint_p.cpp"
diff --git a/src/quick/handlers/qquickhoverhandler.cpp b/src/quick/handlers/qquickhoverhandler.cpp
index e953a5b311..c5067881a6 100644
--- a/src/quick/handlers/qquickhoverhandler.cpp
+++ b/src/quick/handlers/qquickhoverhandler.cpp
@@ -67,7 +67,7 @@ Q_LOGGING_CATEGORY(lcHoverHandler, "qt.quick.handler.hover")
The \l cursorShape property allows changing the cursor whenever
\l hovered changes to \c true.
- \sa MouseArea, PointHandler
+ \sa MouseArea, PointHandler, {Pointer Handlers Example}
*/
QQuickHoverHandler::QQuickHoverHandler(QQuickItem *parent)
@@ -101,10 +101,9 @@ bool QQuickHoverHandler::event(QEvent *event)
void QQuickHoverHandler::componentComplete()
{
- if (auto par = parentItem()) {
- par->setAcceptHoverEvents(true);
+ QQuickSinglePointHandler::componentComplete();
+ if (auto par = parentItem())
QQuickItemPrivate::get(par)->setHasHoverInChild(true);
- }
}
bool QQuickHoverHandler::wantsPointerEvent(QPointerEvent *event)
@@ -164,6 +163,98 @@ void QQuickHoverHandler::setHovered(bool hovered)
}
/*!
+ \internal
+ \qmlproperty flags QtQuick::HoverHandler::acceptedButtons
+
+ This property is not used in HoverHandler.
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedDevices
+
+ The types of pointing devices that can activate the pointer handler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore pointer
+ events from the non-matching devices.
+
+ For example, an item could be made to respond to mouse hover in one way,
+ and stylus hover in another way, with two handlers:
+
+ \snippet pointerHandlers/hoverMouseOrStylus.qml 0
+
+ The available device types are as follows:
+
+ \value PointerDevice.Mouse A mouse.
+ \value PointerDevice.TouchScreen A touchscreen.
+ \value PointerDevice.TouchPad A touchpad or trackpad.
+ \value PointerDevice.Stylus A stylus on a graphics tablet.
+ \value PointerDevice.Airbrush An airbrush on a graphics tablet.
+ \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet.
+ \value PointerDevice.AllDevices Any type of pointing device.
+
+ \sa QInputDevice::DeviceType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedPointerTypes
+
+ The types of pointing instruments (generic, stylus, eraser, and so on)
+ that can activate the pointer handler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching events.
+
+ For example, you could provide feedback by changing the cursor depending on
+ whether a stylus or eraser is hovering over a graphics tablet:
+
+ \snippet pointerHandlers/hoverStylusOrEraser.qml 0
+
+ The available pointer types are as follows:
+
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen (hover detection is unlikely).
+ \value PointerDevice.Pen A stylus on a graphics tablet.
+ \value PointerDevice.Eraser An eraser on a graphics tablet.
+ \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet.
+ \value PointerDevice.AllPointerTypes Any type of pointing device.
+
+ \sa QPointingDevice::PointerType
+*/
+
+/*!
+ \qmlproperty flags QtQuick::HoverHandler::acceptedModifiers
+
+ If this property is set, a hover event is handled only if the given keyboard
+ modifiers are pressed. The event is ignored without the modifiers.
+
+ This property is set to \c Qt.KeyboardModifierMask by default, resulting
+ in handling hover events regardless of any modifier keys.
+
+ For example, an \l[QML]{Item} could have two handlers of the same type, one
+ of which is enabled only if the required keyboard modifiers are pressed:
+
+ \snippet pointerHandlers/hoverModifiers.qml 0
+
+ The available modifiers are as follows:
+
+ \value Qt.NoModifier No modifier key is allowed.
+ \value Qt.ShiftModifier A Shift key on the keyboard must be pressed.
+ \value Qt.ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value Qt.AltModifier An Alt key on the keyboard must be pressed.
+ \value Qt.MetaModifier A Meta key on the keyboard must be pressed.
+ \value Qt.KeypadModifier A keypad button must be pressed.
+ \value Qt.GroupSwitchModifier A Mode_switch key on the keyboard must be pressed.
+ X11 only (unless activated on Windows by a command line argument).
+ \value Qt.KeyboardModifierMask The handler ignores modifier keys.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
\since 5.15
\qmlproperty Qt::CursorShape QtQuick::HoverHandler::cursorShape
This property holds the cursor shape that will appear whenever
@@ -211,4 +302,13 @@ void QQuickHoverHandler::setHovered(bool hovered)
\sa Qt::CursorShape, QQuickItem::cursor()
*/
+/*!
+ \internal
+ \qmlproperty flags HoverHandler::dragThreshold
+
+ This property is not used in HoverHandler.
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qquickhoverhandler_p.cpp"
diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp
index 8c13c84914..70ceeb47fc 100644
--- a/src/quick/handlers/qquickmultipointhandler.cpp
+++ b/src/quick/handlers/qquickmultipointhandler.cpp
@@ -185,7 +185,7 @@ QVector<QEventPoint> QQuickMultiPointHandler::eligiblePoints(QPointerEvent *even
// In other cases however, check whether it would be OK to steal the grab if the handler chooses to do that.
bool stealingAllowed = event->isBeginEvent() || event->isEndEvent();
for (int i = 0; i < event->pointCount(); ++i) {
- auto &p = QMutableEventPoint::from(event->point(i));
+ auto &p = event->point(i);
if (QQuickDeliveryAgentPrivate::isMouseEvent(event)) {
if (static_cast<QMouseEvent *>(event)->buttons() == Qt::NoButton)
continue;
@@ -398,7 +398,7 @@ bool QQuickMultiPointHandler::grabPoints(QPointerEvent *event, const QVector<QEv
}
}
if (allowed) {
- for (auto point : points)
+ for (const auto &point : qAsConst(points))
setExclusiveGrab(event, point);
}
return allowed;
@@ -444,3 +444,5 @@ QMetaProperty &QQuickMultiPointHandlerPrivate::yMetaProperty() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickmultipointhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpinchhandler.cpp b/src/quick/handlers/qquickpinchhandler.cpp
index bdacc6f46d..cb45509de0 100644
--- a/src/quick/handlers/qquickpinchhandler.cpp
+++ b/src/quick/handlers/qquickpinchhandler.cpp
@@ -92,7 +92,7 @@ Q_LOGGING_CATEGORY(lcPinchHandler, "qt.quick.handler.pinch")
but if it's a disallowed number, it does not scale or rotate
its \l target, and the \l active property remains \c false.
- \sa PinchArea, QPointerEvent::pointCount(), QNativeGestureEvent::fingerCount()
+ \sa PinchArea, QPointerEvent::pointCount(), QNativeGestureEvent::fingerCount(), {Pointer Handlers Example}
*/
QQuickPinchHandler::QQuickPinchHandler(QQuickItem *parent)
@@ -217,6 +217,7 @@ bool QQuickPinchHandler::wantsPointerEvent(QPointerEvent *event)
*/
/*!
+ \readonly
\qmlproperty bool QtQuick::PinchHandler::active
This property is \c true when all the constraints (epecially
@@ -238,8 +239,8 @@ void QQuickPinchHandler::onActiveChanged()
m_startRotation = t->rotation();
m_startPos = t->position();
} else {
- m_startScale = 1;
- m_startRotation = 0;
+ m_startScale = m_accumulatedScale;
+ m_startRotation = 0; // TODO m_accumulatedRotation (QTBUG-94168)
}
qCDebug(lcPinchHandler) << "activated with starting scale" << m_startScale << "rotation" << m_startRotation;
} else {
@@ -271,6 +272,7 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
return;
case Qt::ZoomNativeGesture:
m_activeScale *= 1 + gesture->value();
+ m_activeScale = qBound(m_minimumScale, m_activeScale, m_maximumScale);
break;
case Qt::RotateNativeGesture:
m_activeRotation += gesture->value();
@@ -460,6 +462,13 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
}
/*!
+ \internal
+ \qmlproperty flags QtQuick::PinchHandler::acceptedButtons
+
+ This property is not used in PinchHandler.
+*/
+
+/*!
\readonly
\qmlproperty QtQuick::HandlerPoint QtQuick::PinchHandler::centroid
@@ -506,6 +515,11 @@ void QQuickPinchHandler::handlePointerEventImpl(QPointerEvent *event)
The translation of the gesture \l centroid. It is \c (0, 0) when the
gesture begins.
+
+ \note On some touchpads, such as on a \macos trackpad, native gestures do
+ not generate any translation values, and this property stays at \c (0, 0).
*/
QT_END_NAMESPACE
+
+#include "moc_qquickpinchhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerdevicehandler.cpp b/src/quick/handlers/qquickpointerdevicehandler.cpp
index 27f9c3fc36..9fe214824f 100644
--- a/src/quick/handlers/qquickpointerdevicehandler.cpp
+++ b/src/quick/handlers/qquickpointerdevicehandler.cpp
@@ -175,7 +175,7 @@ void QQuickPointerDeviceHandler::setAcceptedDevices(QPointingDevice::DeviceTypes
By default, this property is set to
\l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
If you set it to an OR combination of device types, it will ignore events
- from non-matching events.
+ from non-matching \l {PointerDevice}{devices}.
For example, a control could be made to respond to mouse, touch, and stylus clicks
in some way, but delete itself if tapped with an eraser tool on a graphics tablet,
@@ -315,3 +315,5 @@ bool QQuickPointerDeviceHandler::wantsPointerEvent(QPointerEvent *event)
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerdevicehandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp
index 597ce17c35..ec3c972af3 100644
--- a/src/quick/handlers/qquickpointerhandler.cpp
+++ b/src/quick/handlers/qquickpointerhandler.cpp
@@ -92,7 +92,7 @@ QQuickPointerHandler::~QQuickPointerHandler()
\qmlproperty real PointerHandler::margin
The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
- item within which an event point can activate this handler. For example, on
+ item within which an \l eventPoint can activate this handler. For example, on
a PinchHandler where the \l {PointerHandler::target}{target} is also the
\c parent, it's useful to set this to a distance at least half the width
of a typical user's finger, so that if the \c parent has been scaled down
@@ -125,7 +125,7 @@ void QQuickPointerHandler::setMargin(qreal pointDistanceThreshold)
\qmlproperty int PointerHandler::dragThreshold
\since 5.15
- The distance in pixels that the user must drag an event point in order to
+ The distance in pixels that the user must drag an \l eventPoint in order to
have it treated as a drag gesture.
The default value depends on the platform and screen resolution.
@@ -217,9 +217,11 @@ void QQuickPointerHandler::setCursorShape(Qt::CursorShape shape)
return;
d->cursorShape = shape;
d->cursorSet = true;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = true;
- itemPriv->setHasCursorInChild(true);
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
emit cursorShapeChanged();
}
@@ -230,9 +232,11 @@ void QQuickPointerHandler::resetCursorShape()
return;
d->cursorShape = Qt::ArrowCursor;
d->cursorSet = false;
- QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parentItem());
- itemPriv->hasCursorHandler = false;
- itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = false;
+ itemPriv->setHasCursorInChild(itemPriv->hasCursor);
+ }
emit cursorShapeChanged();
}
@@ -248,8 +252,8 @@ bool QQuickPointerHandler::isCursorShapeExplicitlySet() const
The \a grabber (subject) will be the Input Handler whose state is changing,
or null if the state change regards an Item.
The \a transition (verb) tells what happened.
- The \a point (object) is the point that was grabbed or ungrabbed.
- EventPoint has the sole responsibility to call this function.
+ The \a point (object) is the \l eventPoint that was grabbed or ungrabbed.
+ QQuickDeliveryAgent calls this function.
The Input Handler must react in whatever way is appropriate, and must
emit the relevant signals (for the benefit of QML code).
A subclass is allowed to override this virtual function, but must always
@@ -432,6 +436,8 @@ bool QQuickPointerHandler::approveGrabTransition(QPointerEvent *event, const QEv
This handler can take the exclusive grab from another handler of the same class.
\value PointerHandler.CanTakeOverFromHandlersOfDifferentType
This handler can take the exclusive grab from any kind of handler.
+ \value PointerHandler.CanTakeOverFromItems
+ This handler can take the exclusive grab from any type of Item.
\value PointerHandler.CanTakeOverFromAnything
This handler can take the exclusive grab from any type of Item or Handler.
\value PointerHandler.ApprovesTakeOverByHandlersOfSameType
@@ -472,6 +478,14 @@ void QQuickPointerHandler::classBegin()
void QQuickPointerHandler::componentComplete()
{
+ Q_D(const QQuickPointerHandler);
+ if (d->cursorSet) {
+ if (auto *parent = parentItem()) {
+ QQuickItemPrivate *itemPriv = QQuickItemPrivate::get(parent);
+ itemPriv->hasCursorHandler = true;
+ itemPriv->setHasCursorInChild(true);
+ }
+ }
}
QPointerEvent *QQuickPointerHandler::currentEvent()
@@ -646,10 +660,12 @@ bool QQuickPointerHandler::event(QEvent *e)
void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event)
{
+ Q_D(QQuickPointerHandler);
bool wants = wantsPointerEvent(event);
qCDebug(lcPointerHandlerDispatch) << metaObject()->className() << objectName()
<< "on" << parent()->metaObject()->className() << parent()->objectName()
<< (wants ? "WANTS" : "DECLINES") << event;
+ d->currentEvent = event;
if (wants) {
handlePointerEventImpl(event);
} else {
@@ -665,6 +681,7 @@ void QQuickPointerHandler::handlePointerEvent(QPointerEvent *event)
}
}
}
+ d->currentEvent = nullptr;
QQuickPointerHandlerPrivate::deviceDeliveryTargets(event->device()).append(this);
}
@@ -690,9 +707,9 @@ bool QQuickPointerHandler::wantsEventPoint(const QPointerEvent *event, const QEv
\qmlproperty bool QtQuick::PointerHandler::active
This holds true whenever this Input Handler has taken sole responsibility
- for handing one or more EventPoints, by successfully taking an exclusive
- grab of those points. This means that it is keeping its properties
- up-to-date according to the movements of those Event Points and actively
+ for handing one or more \l {eventPoint}{eventPoints}, by successfully taking an
+ exclusive grab of those points. This means that it is keeping its properties
+ up-to-date according to the movements of those eventPoints and actively
manipulating its \l target (if any).
*/
void QQuickPointerHandler::setActive(bool active)
@@ -706,10 +723,8 @@ void QQuickPointerHandler::setActive(bool active)
}
}
-void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *event)
+void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *)
{
- Q_D(QQuickPointerHandler);
- d->currentEvent = event;
}
/*!
@@ -718,7 +733,7 @@ void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *event)
The \l Item which is the scope of the handler; the Item in which it was declared.
The handler will handle events on behalf of this Item, which means a
- pointer event is relevant if at least one of its event points occurs within
+ pointer event is relevant if at least one of its \l {eventPoint}{eventPoints} occurs within
the Item's interior. Initially \l [QML] {target} {target()} is the same, but it
can be reassigned.
@@ -729,7 +744,7 @@ void QQuickPointerHandler::handlePointerEventImpl(QPointerEvent *event)
*/
/*!
- \qmlsignal QtQuick::PointerHandler::grabChanged(GrabTransition transition, EventPoint point)
+ \qmlsignal QtQuick::PointerHandler::grabChanged(PointerDevice::GrabTransition transition, eventPoint point)
This signal is emitted when the grab has changed in some way which is
relevant to this handler.
@@ -793,3 +808,5 @@ QVector<QObject *> &QQuickPointerHandlerPrivate::deviceDeliveryTargets(const QIn
}
QT_END_NAMESPACE
+
+#include "moc_qquickpointerhandler_p.cpp"
diff --git a/src/quick/handlers/qquickpointhandler.cpp b/src/quick/handlers/qquickpointhandler.cpp
index 3ce95db51a..94d1f2f75c 100644
--- a/src/quick/handlers/qquickpointhandler.cpp
+++ b/src/quick/handlers/qquickpointhandler.cpp
@@ -102,7 +102,8 @@ QT_BEGIN_NAMESPACE
PointHandler will not automatically manipulate the \c target item in any way.
You need to use bindings to make it react to the \l point.
- \note On macOS, PointHandler does not react to the trackpad by default.
+ \note On macOS, PointHandler does not react to multiple fingers on the
+ trackpad by default, although it does react to a pressed point (mouse position).
That is because macOS can provide either native gesture recognition, or raw
touchpoints, but not both. We prefer to use the native gesture event in
PinchHandler, so we do not want to disable it by enabling touch. However
@@ -111,7 +112,7 @@ QT_BEGIN_NAMESPACE
want to react to all the touchpoints but do not require the smooth
native-gesture experience.
- \sa MultiPointTouchArea
+ \sa MultiPointTouchArea, HoverHandler, {Pointer Handlers Example}
*/
QQuickPointHandler::QQuickPointHandler(QQuickItem *parent)
@@ -164,4 +165,127 @@ QVector2D QQuickPointHandler::translation() const
return QVector2D(point().position() - point().pressPosition());
}
+/*!
+ \qmlproperty flags PointHandler::acceptedButtons
+
+ The mouse buttons that can activate this PointHandler.
+
+ By default, this property is set to \l {QtQuick::MouseEvent::button} {Qt.LeftButton}.
+ It can be set to an OR combination of mouse buttons, and will ignore events
+ in which other buttons are pressed or held.
+
+ \snippet pointerHandlers/pointHandlerAcceptedButtons.qml 0
+
+ \note On a touchscreen, there are no buttons, so this property does not
+ prevent PointHandler from reacting to touchpoints.
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedDevices
+
+ The types of pointing devices that can activate this PointHandler.
+
+ By default, this property is set to
+ \l{QInputDevice::DeviceType}{PointerDevice.AllDevices}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching \l {PointerDevice}{devices}:
+
+ \snippet pointerHandlers/pointHandler.qml 1
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedPointerTypes
+
+ The types of pointing instruments (finger, stylus, eraser, etc.)
+ that can activate this PointHandler.
+
+ By default, this property is set to
+ \l {QPointingDevice::PointerType} {PointerDevice.AllPointerTypes}.
+ If you set it to an OR combination of device types, it will ignore events
+ from non-matching \l {PointerDevice}{devices}:
+
+ \snippet pointerHandlers/pointHandlerCanvasDrawing.qml 0
+
+ The \l {Pointer Handlers Example} includes a more complex example for
+ drawing on a Canvas with a graphics tablet.
+*/
+
+/*!
+ \qmlproperty flags PointHandler::acceptedModifiers
+
+ If this property is set, PointHandler requires the given keyboard modifiers
+ to be pressed in order to react to \l {PointerEvent}{PointerEvents}, and
+ otherwise ignores them.
+
+ If this property is set to \c Qt.KeyboardModifierMask (the default value),
+ then PointHandler ignores the modifier keys.
+
+ For example, an \l [QML] Item could have two handlers, one of which is
+ enabled only if the required keyboard modifier is pressed:
+
+ \snippet pointerHandlers/pointHandlerAcceptedModifiers.qml 0
+
+ If you set \c acceptedModifiers to an OR combination of modifier keys,
+ it means \e all of those modifiers must be pressed to activate the handler.
+
+ The available modifiers are as follows:
+
+ \value NoModifier No modifier key is allowed.
+ \value ShiftModifier A Shift key on the keyboard must be pressed.
+ \value ControlModifier A Ctrl key on the keyboard must be pressed.
+ \value AltModifier An Alt key on the keyboard must be pressed.
+ \value MetaModifier A Meta key on the keyboard must be pressed.
+ \value KeypadModifier A keypad button must be pressed.
+ \value GroupSwitchModifier X11 only (unless activated on Windows by a command line argument).
+ A Mode_switch key on the keyboard must be pressed.
+ \value KeyboardModifierMask The handler does not care which modifiers are pressed.
+
+ \sa Qt::KeyboardModifier
+*/
+
+/*!
+ \readonly
+ \qmlproperty bool PointHandler::active
+
+ This holds \c true whenever the constraints are satisfied and this
+ PointHandler is reacting. This means that it is keeping its properties
+ up-to-date according to the movements of the \l {eventPoint}{eventPoints}
+ that satisfy the constraints.
+*/
+
+/*!
+ \internal
+ \qmlproperty flags PointHandler::dragThreshold
+
+ This property is not used in PointHandler.
+*/
+
+/*!
+ \qmlproperty real PointHandler::margin
+
+ The margin beyond the bounds of the \l {PointerHandler::parent}{parent}
+ item within which an \l eventPoint can activate this handler.
+
+ The default value is \c 0.
+
+ \snippet pointerHandlers/pointHandlerMargin.qml 0
+*/
+
+/*!
+ \qmlproperty real PointHandler::target
+
+ A property that can conveniently hold an Item to be manipulated or to show
+ feedback. Unlike other \l {Qt Quick Input Handlers}{Pointer Handlers},
+ PointHandler does not do anything with the \c target on its own: you
+ usually need to create reactive bindings to properties such as
+ \l SinglePointHandler::point and \l PointHandler::active. If you declare
+ an Item instance here, you need to explicitly set its \l {Item::}{parent},
+ because PointHandler is not an Item.
+
+ By default, it is the same as the \l {PointerHandler::}{parent}, the Item
+ within which the handler is declared.
+*/
+
QT_END_NAMESPACE
+
+#include "moc_qquickpointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicksinglepointhandler.cpp b/src/quick/handlers/qquicksinglepointhandler.cpp
index aa650654eb..22b475637a 100644
--- a/src/quick/handlers/qquicksinglepointhandler.cpp
+++ b/src/quick/handlers/qquicksinglepointhandler.cpp
@@ -209,7 +209,7 @@ QQuickHandlerPoint QQuickSinglePointHandler::point() const
\readonly
\qmlproperty HandlerPoint QtQuick::SinglePointHandler::point
- The event point currently being handled. When no point is currently being
+ The \l eventPoint currently being handled. When no point is currently being
handled, this object is reset to default values (all coordinates are 0).
*/
@@ -226,3 +226,5 @@ void QQuickSinglePointHandlerPrivate::reset()
}
QT_END_NAMESPACE
+
+#include "moc_qquicksinglepointhandler_p.cpp"
diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp
index d16c9e23cb..3abb366676 100644
--- a/src/quick/handlers/qquicktaphandler.cpp
+++ b/src/quick/handlers/qquicktaphandler.cpp
@@ -77,12 +77,14 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1);
button in order to cancel the click. For this use case, set the
\l gesturePolicy to \c TapHandler.ReleaseWithinBounds.
+ \snippet pointerHandlers/tapHandlerButton.qml 0
+
For multi-tap gestures (double-tap, triple-tap etc.), the distance moved
must not exceed QStyleHints::mouseDoubleClickDistance() with mouse and
QStyleHints::touchDoubleTapDistance() with touch, and the time between
taps must not exceed QStyleHints::mouseDoubleClickInterval().
- \sa MouseArea
+ \sa MouseArea, {Pointer Handlers Example}
*/
QQuickTapHandler::QQuickTapHandler(QQuickItem *parent)
@@ -180,7 +182,7 @@ void QQuickTapHandler::handleEventPoint(QPointerEvent *event, QEventPoint &point
/*!
\qmlproperty real QtQuick::TapHandler::longPressThreshold
- The time in seconds that an event point must be pressed in order to
+ The time in seconds that an \l eventPoint must be pressed in order to
trigger a long press gesture and emit the \l longPressed() signal.
If the point is released before this time limit, a tap can be detected
if the \l gesturePolicy constraint is satisfied. The default value is
@@ -225,31 +227,79 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event)
If the spatial constraint is violated, \l pressed transitions immediately
from true to false, regardless of the time held.
- \value TapHandler.DragThreshold
- (the default value) The event point must not move significantly.
- If the mouse, finger or stylus moves past the system-wide drag
- threshold (QStyleHints::startDragDistance), the tap gesture is
- canceled, even if the button or finger is still pressed. This policy
- can be useful whenever TapHandler needs to cooperate with other
- input handlers (for example \l DragHandler) or event-handling Items
- (for example QtQuick Controls), because in this case TapHandler
- will not take the exclusive grab, but merely a passive grab.
-
- \value TapHandler.WithinBounds
- If the event point leaves the bounds of the \c parent Item, the tap
- gesture is canceled. The TapHandler will take the exclusive grab on
- press, but will release the grab as soon as the boundary constraint
- is no longer satisfied.
-
- \value TapHandler.ReleaseWithinBounds
- At the time of release (the mouse button is released or the finger
- is lifted), if the event point is outside the bounds of the
- \c parent Item, a tap gesture is not recognized. This corresponds to
- typical behavior for button widgets: you can cancel a click by
- dragging outside the button, and you can also change your mind by
- dragging back inside the button before release. Note that it's
- necessary for TapHandler take the exclusive grab on press and retain
- it until release in order to detect this gesture.
+ The \c gesturePolicy also affects grab behavior as described below.
+
+ \table
+ \header
+ \li Constant
+ \li Description
+ \row
+ \li \c TapHandler.DragThreshold
+ \image pointerHandlers/tapHandlerOverlappingButtons.webp
+ Grab on press: \e passive
+ \li (the default value) The \l eventPoint must not move significantly.
+ If the mouse, finger or stylus moves past the system-wide drag
+ threshold (QStyleHints::startDragDistance), the tap gesture is
+ canceled, even if the device or finger is still pressed. This policy
+ can be useful whenever TapHandler needs to cooperate with other
+ input handlers (for example \l DragHandler) or event-handling Items
+ (for example \l {Qt Quick Controls}), because in this case TapHandler
+ will not take the exclusive grab, but merely a
+ \l {QPointerEvent::addPassiveGrabber()}{passive grab}.
+ That is, \c DragThreshold is especially useful to \e augment
+ existing behavior: it reacts to tap/click/long-press even when
+ another item or handler is already reacting, perhaps even in a
+ different layer of the UI. The following snippet shows one
+ TapHandler as used in one component; but if we stack up two
+ instances of the component, you will see the handlers in both of them
+ react simultaneously when a press occurs over both of them, because
+ the passive grab does not stop event propagation:
+ \quotefromfile pointerHandlers/tapHandlerOverlappingButtons.qml
+ \skipto Item
+ \printuntil component Button
+ \skipto TapHandler
+ \printuntil }
+ \skipuntil Text {
+ \skipuntil }
+ \printuntil Button
+ \printuntil Button
+ \printuntil }
+
+ \row
+ \li \c TapHandler.WithinBounds
+ \image pointerHandlers/tapHandlerButtonWithinBounds.webp
+ Grab on press: \e exclusive
+ \li If the \l eventPoint leaves the bounds of the \c parent Item, the tap
+ gesture is canceled. The TapHandler will take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on
+ press, but will release the grab as soon as the boundary constraint
+ is no longer satisfied.
+ \snippet pointerHandlers/tapHandlerButtonWithinBounds.qml 1
+
+ \row
+ \li \c TapHandler.ReleaseWithinBounds
+ \image pointerHandlers/tapHandlerButtonReleaseWithinBounds.webp
+ Grab on press: \e exclusive
+ \li At the time of release (the mouse button is released or the finger
+ is lifted), if the \l eventPoint is outside the bounds of the
+ \c parent Item, a tap gesture is not recognized. This corresponds to
+ typical behavior for button widgets: you can cancel a click by
+ dragging outside the button, and you can also change your mind by
+ dragging back inside the button before release. Note that it's
+ necessary for TapHandler to take the
+ \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press
+ and retain it until release in order to detect this gesture.
+ \snippet pointerHandlers/tapHandlerButtonReleaseWithinBounds.qml 1
+ \endtable
+
+ The \l {Pointer Handlers Example} demonstrates some use cases for these.
+
+ \note If you find that TapHandler is reacting in cases that conflict with
+ some other behavior, the first thing you should try is to think about which
+ \c gesturePolicy is appropriate. If you cannot fix it by changing \c gesturePolicy,
+ some cases are better served by adjusting \l {PointerHandler::}{grabPermissions},
+ either in this handler, or in another handler that should \e prevent TapHandler
+ from reacting.
*/
void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gesturePolicy)
{
@@ -266,7 +316,7 @@ void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gestureP
Holds true whenever the mouse or touch point is pressed,
and any movement since the press is compliant with the current
- \l gesturePolicy. When the event point is released or the policy is
+ \l gesturePolicy. When the \l eventPoint is released or the policy is
violated, \e pressed will change to false.
*/
void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event, QEventPoint &point)
@@ -303,12 +353,13 @@ void QQuickTapHandler::setPressed(bool press, bool cancel, QPointerEvent *event,
else
m_tapCount = 1;
qCDebug(lcTapHandler) << objectName() << "tapped" << m_tapCount << "times";
- emit tapped(point);
+ auto button = event->isSinglePointEvent() ? static_cast<QSinglePointEvent *>(event)->button() : Qt::NoButton;
+ emit tapped(point, button);
emit tapCountChanged();
if (m_tapCount == 1)
- emit singleTapped(point);
+ emit singleTapped(point, button);
else if (m_tapCount == 2)
- emit doubleTapped(point);
+ emit doubleTapped(point, button);
m_lastTapTimestamp = ts;
m_lastTapPos = point.scenePosition();
} else {
@@ -392,7 +443,7 @@ void QQuickTapHandler::updateTimeHeld()
*/
/*!
- \qmlsignal QtQuick::TapHandler::tapped(EventPoint eventPoint)
+ \qmlsignal QtQuick::TapHandler::tapped(EventPoint eventPoint, Qt::MouseButton button)
This signal is emitted each time the \c parent Item is tapped.
@@ -400,24 +451,28 @@ void QQuickTapHandler::updateTimeHeld()
period less than \l longPressThreshold, while any movement does not exceed
the drag threshold, then the \c tapped signal will be emitted at the time
of release. The \a eventPoint signal parameter contains information
- from the release event about the point that was tapped:
+ from the release event about the point that was tapped, and \a button
+ is the \l {Qt::MouseButton}{mouse button} that was clicked, or \c NoButton
+ on a touchscreen.
\snippet pointerHandlers/tapHandlerOnTapped.qml 0
*/
/*!
- \qmlsignal QtQuick::TapHandler::singleTapped(EventPoint eventPoint)
+ \qmlsignal QtQuick::TapHandler::singleTapped(EventPoint eventPoint, Qt::MouseButton button)
\since 5.11
This signal is emitted when the \c parent Item is tapped once.
After an amount of time greater than QStyleHints::mouseDoubleClickInterval,
it can be tapped again; but if the time until the next tap is less,
\l tapCount will increase. The \a eventPoint signal parameter contains
- information from the release event about the point that was tapped.
+ information from the release event about the point that was tapped, and
+ \a button is the \l {Qt::MouseButton}{mouse button} that was clicked, or
+ \c NoButton on a touchscreen.
*/
/*!
- \qmlsignal QtQuick::TapHandler::doubleTapped(EventPoint eventPoint)
+ \qmlsignal QtQuick::TapHandler::doubleTapped(EventPoint eventPoint, Qt::MouseButton button)
\since 5.11
This signal is emitted when the \c parent Item is tapped twice within a
@@ -426,7 +481,9 @@ void QQuickTapHandler::updateTimeHeld()
QStyleHints::touchDoubleTapDistance()). This signal always occurs after
\l singleTapped, \l tapped, and \l tapCountChanged. The \a eventPoint
signal parameter contains information from the release event about the
- point that was tapped.
+ point that was tapped, and \a button is the
+ \l {Qt::MouseButton}{mouse button} that was clicked, or \c NoButton
+ on a touchscreen.
*/
/*!
@@ -447,3 +504,5 @@ void QQuickTapHandler::updateTimeHeld()
from the previous \c tapCount.
*/
QT_END_NAMESPACE
+
+#include "moc_qquicktaphandler_p.cpp"
diff --git a/src/quick/handlers/qquicktaphandler_p.h b/src/quick/handlers/qquicktaphandler_p.h
index d75547eee2..2e0c8e211f 100644
--- a/src/quick/handlers/qquicktaphandler_p.h
+++ b/src/quick/handlers/qquicktaphandler_p.h
@@ -97,9 +97,10 @@ Q_SIGNALS:
void timeHeldChanged();
void longPressThresholdChanged();
void gesturePolicyChanged();
- void tapped(QEventPoint eventPoint);
- void singleTapped(QEventPoint eventPoint);
- void doubleTapped(QEventPoint eventPoint);
+ // the second argument (Qt::MouseButton) was added in 6.2: avoid name clashes with IDs by not naming it for now
+ void tapped(QEventPoint eventPoint, Qt::MouseButton /* button */);
+ void singleTapped(QEventPoint eventPoint, Qt::MouseButton /* button */);
+ void doubleTapped(QEventPoint eventPoint, Qt::MouseButton /* button */);
void longPressed();
protected:
diff --git a/src/quick/handlers/qquickwheelhandler.cpp b/src/quick/handlers/qquickwheelhandler.cpp
index 7045f10d8e..f1e40ba35c 100644
--- a/src/quick/handlers/qquickwheelhandler.cpp
+++ b/src/quick/handlers/qquickwheelhandler.cpp
@@ -81,7 +81,7 @@ Q_LOGGING_CATEGORY(lcWheelHandler, "qt.quick.handler.wheel")
WheelHandler handles only a rotating mouse wheel by default; this
can be changed by setting acceptedDevices.
- \sa MouseArea, Flickable
+ \sa MouseArea, Flickable, {Pointer Handlers Example}
*/
QQuickWheelHandler::QQuickWheelHandler(QQuickItem *parent)
@@ -91,7 +91,7 @@ QQuickWheelHandler::QQuickWheelHandler(QQuickItem *parent)
}
/*!
- \qmlproperty enum QtQuick::WheelHandler::orientation
+ \qmlproperty enumeration QtQuick::WheelHandler::orientation
Which wheel to react to. The default is \c Qt.Vertical.
@@ -502,7 +502,7 @@ void QQuickWheelHandler::timerEvent(QTimerEvent *event)
}
/*!
- \qmlsignal QtQuick::WheelHandler::wheel(PointerScrollEvent event)
+ \qmlsignal QtQuick::WheelHandler::wheel(WheelEvent event)
This signal is emitted every time this handler receives an \a event
of type \l QWheelEvent: that is, every time the wheel is moved or the
@@ -548,3 +548,5 @@ QMetaProperty &QQuickWheelHandlerPrivate::targetMetaProperty() const
*/
QT_END_NAMESPACE
+
+#include "moc_qquickwheelhandler_p.cpp"
diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp
index e13c0f6dae..89fafbe44d 100644
--- a/src/quick/items/context2d/qquickcanvasitem.cpp
+++ b/src/quick/items/context2d/qquickcanvasitem.cpp
@@ -288,7 +288,7 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate()
QPainter instead of the more expensive and likely less performing
JavaScript and Context2D approach.
- \sa Context2D QQuickPaintedItem
+ \sa Context2D, QQuickPaintedItem, {Pointer Handlers Example}
*/
QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent)
@@ -652,6 +652,10 @@ void QQuickCanvasItem::invalidateSceneGraph()
d->textureProvider = nullptr;
delete d->nodeTexture;
d->nodeTexture = nullptr;
+
+ // As we can expect(/hope) that the SG will be "good again", we can requestPaint ( which does 'markDirty(canvasWindow);' )
+ // Otherwise this Canvas will be "blank" when SG comes back
+ requestPaint();
}
void QQuickCanvasItem::schedulePolish()
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index 64b8b80f8b..32546c5299 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -2459,7 +2459,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(const QV4::Funct
\image qml-item-canvas-bezierCurveTo.png
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
- \sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
+ \sa {https://web.archive.org/web/20130505222636if_/http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
*/
QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::FunctionObject *b, const QV4::Value *thisObject, const QV4::Value *argv, int argc)
{
@@ -3884,16 +3884,16 @@ void QQuickContext2D::bezierCurveTo(qreal cp1x, qreal cp1y,
m_path.cubicTo(QPointF(cp1x, cp1y), QPointF(cp2x, cp2y), pt);
}
-void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radius)
+void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, qreal radius)
{
QPointF p0(m_path.currentPosition());
QPointF p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
QPointF p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
- float p1p0_length = std::sqrt(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
- float p1p2_length = std::sqrt(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+ qreal p1p0_length = std::hypot(p1p0.x(), p1p0.y());
+ qreal p1p2_length = std::hypot(p1p2.x(), p1p2.y());
- double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+ qreal cos_phi = QPointF::dotProduct(p1p0, p1p2) / (p1p0_length * p1p2_length);
// The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
// We could have used areCollinear() here, but since we're reusing
@@ -3903,16 +3903,16 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
return;
}
- float tangent = radius / std::tan(std::acos(cos_phi) / 2);
- float factor_p1p0 = tangent / p1p0_length;
+ qreal tangent = radius / std::tan(std::acos(cos_phi) / 2);
+ qreal factor_p1p0 = tangent / p1p0_length;
QPointF t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
QPointF orth_p1p0(p1p0.y(), -p1p0.x());
- float orth_p1p0_length = std::sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
- float factor_ra = radius / orth_p1p0_length;
+ qreal orth_p1p0_length = std::hypot(orth_p1p0.x(), orth_p1p0.y());
+ qreal factor_ra = radius / orth_p1p0_length;
// angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
- double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ qreal cos_alpha = QPointF::dotProduct(orth_p1p0, p1p2) / (orth_p1p0_length * p1p2_length);
if (cos_alpha < 0.f)
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
@@ -3920,20 +3920,15 @@ void QQuickContext2D::addArcTo(const QPointF& p1, const QPointF& p2, float radiu
// calculate angles for addArc
orth_p1p0 = QPointF(-orth_p1p0.x(), -orth_p1p0.y());
- float sa = std::acos(orth_p1p0.x() / orth_p1p0_length);
- if (orth_p1p0.y() < 0.f)
- sa = 2 * M_PI - sa;
+ qreal sa = std::atan2(orth_p1p0.y(), orth_p1p0.x());
// anticlockwise logic
bool anticlockwise = false;
- float factor_p1p2 = tangent / p1p2_length;
+ qreal factor_p1p2 = tangent / p1p2_length;
QPointF t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
QPointF orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
- float orth_p1p2_length = std::sqrt(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
- float ea = std::acos(orth_p1p2.x() / orth_p1p2_length);
- if (orth_p1p2.y() < 0)
- ea = 2 * M_PI - ea;
+ qreal ea = std::atan2(orth_p1p2.y(), orth_p1p2.x());
if ((sa > ea) && ((sa - ea) < M_PI))
anticlockwise = true;
if ((sa < ea) && ((ea - sa) > M_PI))
diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h
index 92ec1e6470..ea1354725f 100644
--- a/src/quick/items/context2d/qquickcontext2d_p.h
+++ b/src/quick/items/context2d/qquickcontext2d_p.h
@@ -240,7 +240,7 @@ public:
void arc(qreal x, qreal y, qreal radius,
qreal startAngle, qreal endAngle,
bool anticlockwise);
- void addArcTo(const QPointF& p1, const QPointF& p2, float radius);
+ void addArcTo(const QPointF& p1, const QPointF& p2, qreal radius);
bool isPointInPath(qreal x, qreal y) const;
diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp
index e111f908d0..71a5e414f6 100644
--- a/src/quick/items/context2d/qquickcontext2dtexture.cpp
+++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp
@@ -120,8 +120,15 @@ void QQuickContext2DTexture::setItem(QQuickCanvasItem* item)
bool QQuickContext2DTexture::setCanvasWindow(const QRect& r)
{
- qreal canvasDevicePixelRatio = (m_item && m_item->window()) ?
- m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+ bool ok = false;
+ static qreal overriddenDevicePixelRatio =
+ !qEnvironmentVariableIsEmpty("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO") ?
+ qgetenv("QT_CANVAS_OVERRIDE_DEVICEPIXELRATIO").toFloat(&ok) : 0.0;
+ qreal canvasDevicePixelRatio = overriddenDevicePixelRatio;
+ if (overriddenDevicePixelRatio == 0.0) {
+ canvasDevicePixelRatio = (m_item && m_item->window()) ?
+ m_item->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+ }
if (!qFuzzyCompare(m_canvasDevicePixelRatio, canvasDevicePixelRatio)) {
qCDebug(lcCanvas, "%s device pixel ratio %.1lf -> %.1lf",
(m_item->objectName().isEmpty() ? "Canvas" : qPrintable(m_item->objectName())),
diff --git a/src/quick/items/qquickaccessibleattached.cpp b/src/quick/items/qquickaccessibleattached.cpp
index 0b593c0089..f63ab764f1 100644
--- a/src/quick/items/qquickaccessibleattached.cpp
+++ b/src/quick/items/qquickaccessibleattached.cpp
@@ -109,7 +109,7 @@ QT_BEGIN_NAMESPACE
This property sets an accessible description.
Similar to the name it describes the item. The description
can be a little more verbose and tell what the item does,
- for example the functionallity of the button it describes.
+ for example the functionality of the button it describes.
*/
/*!
@@ -406,9 +406,10 @@ void QQuickAccessibleAttached::setRole(QAccessible::Role role)
m_state.focusable = true;
break;
case QAccessible::StaticText:
- if (!m_stateExplicitlySet.readOnly) {
+ if (!m_stateExplicitlySet.readOnly)
m_state.readOnly = true;
- }
+ if (!m_stateExplicitlySet.focusable)
+ m_state.focusable = true;
break;
default:
break;
diff --git a/src/quick/items/qquickaccessibleattached_p.h b/src/quick/items/qquickaccessibleattached_p.h
index 6d7d46bfd4..13f4b1f52f 100644
--- a/src/quick/items/qquickaccessibleattached_p.h
+++ b/src/quick/items/qquickaccessibleattached_p.h
@@ -189,7 +189,7 @@ public:
bool doAction(const QString &actionName);
void availableActions(QStringList *actions) const;
- Q_INVOKABLE static QString stripHtml(const QString &html);
+ Q_REVISION(6, 2) Q_INVOKABLE static QString stripHtml(const QString &html);
public Q_SLOTS:
void valueChanged() {
diff --git a/src/quick/items/qquickanchors.cpp b/src/quick/items/qquickanchors.cpp
index 8ee4229013..a2657c19f4 100644
--- a/src/quick/items/qquickanchors.cpp
+++ b/src/quick/items/qquickanchors.cpp
@@ -1409,5 +1409,7 @@ bool QQuickAnchorsPrivate::checkVAnchorValid(QQuickAnchorLine anchor) const
QT_END_NAMESPACE
+#include "moc_qquickanchors_p_p.cpp"
+
#include <moc_qquickanchors_p.cpp>
diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp
index 5b3d9db091..a3f2494fba 100644
--- a/src/quick/items/qquickanimatedsprite.cpp
+++ b/src/quick/items/qquickanimatedsprite.cpp
@@ -894,7 +894,7 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
maybeUpdate();
}
- qreal frameCount = d->m_spriteEngine->spriteFrames();
+ int frameCount = d->m_spriteEngine->spriteFrames();
bool reverse = d->m_spriteEngine->sprite()->reverse();
if (reverse)
frameAt = (frameCount - 1) - frameAt;
@@ -931,15 +931,15 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 - w;
y2 = y1;
} else {
- x2 = 1.0 - w;
+ x2 = d->m_sheetSize.width() - w;
y2 = y1 - h;
- if (y2 < 0.0) {
+ if (y2 < 0) {
//the last row may not fill the entire width
int maxRowFrames = d->m_sheetSize.width() / d->m_spriteEngine->spriteWidth();
if (d->m_spriteEngine->maxFrames() % maxRowFrames)
x2 = ((d->m_spriteEngine->maxFrames() % maxRowFrames) - 1) * w;
- y2 = 1.0 - h;
+ y2 = d->m_sheetSize.height() - h;
}
}
} else {
@@ -947,10 +947,10 @@ void QQuickAnimatedSprite::prepareNextFrame(QSGSpriteNode *node)
x2 = x1 + w;
y2 = y1;
} else {
- x2 = 0.0;
+ x2 = 0;
y2 = y1 + h;
- if (y2 >= 1.0)
- y2 = 0.0;
+ if (y2 >= d->m_sheetSize.height())
+ y2 = 0;
}
}
diff --git a/src/quick/items/qquickcolorgroup.cpp b/src/quick/items/qquickcolorgroup.cpp
index ebbbf07499..2a039ec1b4 100644
--- a/src/quick/items/qquickcolorgroup.cpp
+++ b/src/quick/items/qquickcolorgroup.cpp
@@ -47,6 +47,8 @@
QT_BEGIN_NAMESPACE
/*!
+ \internal
+
\class QQuickColorGroup
\brief The QQuickColorGroup class represents a set of colors.
\inmodule QtQuick
@@ -592,3 +594,5 @@ void QQuickColorGroup::resetColor(QPalette::ColorRole role, Notifier notifier)
}
QT_END_NAMESPACE
+
+#include "moc_qquickcolorgroup_p.cpp"
diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp
index e6ffcee2aa..ba81028822 100644
--- a/src/quick/items/qquickdrag.cpp
+++ b/src/quick/items/qquickdrag.cpp
@@ -482,7 +482,9 @@ void QQuickDragAttached::setKeys(const QStringList &keys)
\qmlattachedproperty stringlist QtQuick::Drag::mimeData
\since 5.2
- This property holds a map of mimeData that is used during startDrag.
+ This property holds a map from mime type to data that is used during startDrag.
+ The mime data needs to be a \c string, or an \c ArrayBuffer with the data encoded
+ according to the mime type.
*/
QVariantMap QQuickDragAttached::mimeData() const
@@ -767,8 +769,12 @@ Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedAct
QDrag *drag = new QDrag(source ? source : q);
QMimeData *mimeData = new QMimeData();
- for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
- mimeData->setData(it.key(), it.value().toString().toUtf8());
+ for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it) {
+ if (it.value().typeId() == QMetaType::QByteArray)
+ mimeData->setData(it.key(), it.value().toByteArray());
+ else
+ mimeData->setData(it.key(), it.value().toString().toUtf8());
+ }
drag->setMimeData(mimeData);
if (pixmapLoader.isReady()) {
diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h
index b02a0ea2e1..38ec278adb 100644
--- a/src/quick/items/qquickdrag_p.h
+++ b/src/quick/items/qquickdrag_p.h
@@ -109,9 +109,12 @@ public:
void grab(QQuickItem *item) { m_items.insert(new Item(item)); }
iterator release(iterator at) { Item *item = *at; at = at.erase(); delete item; return at; }
+ auto& ignoreList() { return m_ignoreDragItems; }
+
private:
ItemList m_items;
+ QVarLengthArray<QQuickItem *, 4> m_ignoreDragItems;
QObject *m_target;
};
diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp
index 21dc0979a9..077574cbd1 100644
--- a/src/quick/items/qquickdroparea.cpp
+++ b/src/quick/items/qquickdroparea.cpp
@@ -226,7 +226,7 @@ void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
emit d->drag->positionChanged();
event->accept();
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit positionChanged(&dragTargetEvent);
}
@@ -276,7 +276,7 @@ void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event)
event->accept();
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit entered(&dragTargetEvent);
if (!event->isAccepted())
return;
@@ -325,7 +325,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
if (!d->containsDrag)
return;
- QQuickDropEvent dragTargetEvent(d, event);
+ QQuickDragEvent dragTargetEvent(d, event);
emit dropped(&dragTargetEvent);
d->containsDrag = false;
@@ -337,7 +337,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
/*!
\qmltype DragEvent
- \instantiates QQuickDropEvent
+ \instantiates QQuickDragEvent
\inqmlmodule QtQuick
\ingroup qtquick-input-events
\brief Provides information about a drag event.
@@ -514,7 +514,7 @@ void QQuickDropArea::dropEvent(QDropEvent *event)
easily be translated into a QByteArray. \a format should be one contained in the \l formats property.
*/
-QObject *QQuickDropEvent::source() const
+QObject *QQuickDragEvent::source() const
{
if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(event->mimeData()))
return dragMime->source();
@@ -522,57 +522,57 @@ QObject *QQuickDropEvent::source() const
return event->source();
}
-QStringList QQuickDropEvent::keys() const
+QStringList QQuickDragEvent::keys() const
{
return d->getKeys(event->mimeData());
}
-bool QQuickDropEvent::hasColor() const
+bool QQuickDragEvent::hasColor() const
{
return event->mimeData()->hasColor();
}
-bool QQuickDropEvent::hasHtml() const
+bool QQuickDragEvent::hasHtml() const
{
return event->mimeData()->hasHtml();
}
-bool QQuickDropEvent::hasText() const
+bool QQuickDragEvent::hasText() const
{
return event->mimeData()->hasText();
}
-bool QQuickDropEvent::hasUrls() const
+bool QQuickDragEvent::hasUrls() const
{
return event->mimeData()->hasUrls();
}
-QVariant QQuickDropEvent::colorData() const
+QVariant QQuickDragEvent::colorData() const
{
return event->mimeData()->colorData();
}
-QString QQuickDropEvent::html() const
+QString QQuickDragEvent::html() const
{
return event->mimeData()->html();
}
-QString QQuickDropEvent::text() const
+QString QQuickDragEvent::text() const
{
return event->mimeData()->text();
}
-QList<QUrl> QQuickDropEvent::urls() const
+QList<QUrl> QQuickDragEvent::urls() const
{
return event->mimeData()->urls();
}
-QStringList QQuickDropEvent::formats() const
+QStringList QQuickDragEvent::formats() const
{
return event->mimeData()->formats();
}
-void QQuickDropEvent::getDataAsString(QQmlV4Function *args)
+void QQuickDragEvent::getDataAsString(QQmlV4Function *args)
{
if (args->length() != 0) {
QV4::ExecutionEngine *v4 = args->v4engine();
@@ -584,7 +584,7 @@ void QQuickDropEvent::getDataAsString(QQmlV4Function *args)
}
}
-void QQuickDropEvent::getDataAsArrayBuffer(QQmlV4Function *args)
+void QQuickDragEvent::getDataAsArrayBuffer(QQmlV4Function *args)
{
if (args->length() != 0) {
QV4::ExecutionEngine *v4 = args->v4engine();
@@ -595,12 +595,12 @@ void QQuickDropEvent::getDataAsArrayBuffer(QQmlV4Function *args)
}
}
-void QQuickDropEvent::acceptProposedAction(QQmlV4Function *)
+void QQuickDragEvent::acceptProposedAction(QQmlV4Function *)
{
event->acceptProposedAction();
}
-void QQuickDropEvent::accept(QQmlV4Function *args)
+void QQuickDragEvent::accept(QQmlV4Function *args)
{
Qt::DropAction action = event->dropAction();
diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h
index 74f16df9cc..122029a18a 100644
--- a/src/quick/items/qquickdroparea_p.h
+++ b/src/quick/items/qquickdroparea_p.h
@@ -61,7 +61,7 @@ QT_REQUIRE_CONFIG(quick_draganddrop);
QT_BEGIN_NAMESPACE
class QQuickDropAreaPrivate;
-class QQuickDropEvent : public QObject
+class QQuickDragEvent : public QObject
{
Q_OBJECT
Q_PROPERTY(qreal x READ x)
@@ -81,10 +81,11 @@ class QQuickDropEvent : public QObject
Q_PROPERTY(QString text READ text)
Q_PROPERTY(QList<QUrl> urls READ urls)
Q_PROPERTY(QStringList formats READ formats)
- QML_ANONYMOUS
+ QML_NAMED_ELEMENT(DragEvent)
+ QML_UNCREATABLE("DragEvent is only meant to be created by DropArea")
QML_ADDED_IN_VERSION(2, 0)
public:
- QQuickDropEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {}
+ QQuickDragEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {}
qreal x() const { return event->position().x(); }
qreal y() const { return event->position().y(); }
@@ -176,10 +177,10 @@ Q_SIGNALS:
void keysChanged();
void sourceChanged();
- void entered(QQuickDropEvent *drag);
+ void entered(QQuickDragEvent *drag);
void exited();
- void positionChanged(QQuickDropEvent *drag);
- void dropped(QQuickDropEvent *drop);
+ void positionChanged(QQuickDragEvent *drag);
+ void dropped(QQuickDragEvent *drop);
protected:
void dragMoveEvent(QDragMoveEvent *event) override;
@@ -194,7 +195,6 @@ private:
QT_END_NAMESPACE
-QML_DECLARE_TYPE(QQuickDropEvent)
QML_DECLARE_TYPE(QQuickDropArea)
#endif // QQUICKDROPAREA_P_H
diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp
index ba9082cc2a..f9b5b80a92 100644
--- a/src/quick/items/qquickevents.cpp
+++ b/src/quick/items/qquickevents.cpp
@@ -289,6 +289,7 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
/*!
\qmlproperty int QtQuick::MouseEvent::source
\since 5.7
+ \deprecated [6.2] Use \l {Qt Quick Input Handlers}{input handlers} with \l {PointerDeviceHandler::acceptedDevices}{acceptedDevices} set.
This property holds the source of the mouse event.
@@ -364,10 +365,9 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\ingroup qtquick-input-events
\brief Provides information about a mouse wheel event.
- The position of the mouse can be found via the
- \l {Item::x} {x} and \l {Item::y} {y} properties.
+ The position of the mouse can be found via the \l x and \l y properties.
- \sa MouseArea
+ \sa WheelHandler, MouseArea
*/
/*!
@@ -380,16 +380,20 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\qmlproperty real QtQuick::WheelEvent::y
These properties hold the coordinates of the position supplied by the wheel event.
+
+ \sa QWheelEvent::position()
*/
/*!
\qmlproperty bool QtQuick::WheelEvent::accepted
- Setting \a accepted to true prevents the wheel event from being
- propagated to items below this item.
+ Setting \a accepted to \c true prevents the wheel event from being
+ propagated to items below the receiving item or handler.
- Generally, if the item acts on the wheel event then it should be accepted
+ Generally, if the item acts on the wheel event, it should be accepted
so that items lower in the stacking order do not also respond to the same event.
+
+ \sa QWheelEvent::accepted
*/
/*!
@@ -403,32 +407,39 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
\li \l {Qt::RightButton} {Qt.RightButton}
\li \l {Qt::MiddleButton} {Qt.MiddleButton}
\endlist
+
+ \sa QWheelEvent::buttons()
*/
/*!
\qmlproperty point QtQuick::WheelEvent::angleDelta
- This property holds the distance that the wheel is rotated in wheel degrees.
- The x and y cordinate of this property holds the delta in horizontal and
- vertical orientation.
+ This property holds the relative amount that the wheel was rotated, in
+ eighths of a degree. The \c x and \c y coordinates of this property hold
+ the delta in horizontal and vertical orientations, respectively.
A positive value indicates that the wheel was rotated up/right;
a negative value indicates that the wheel was rotated down/left.
- Most mouse types work in steps of 15 degrees, in which case the delta value is a
- multiple of 120; i.e., 120 units * 1/8 = 15 degrees.
+ Most mouse types work in steps of \c 15 degrees, in which case the delta value is a
+ multiple of \c 120; i.e., \c {120 units * 1/8 = 15 degrees}.
+
+ \sa QWheelEvent::angleDelta()
*/
/*!
\qmlproperty point QtQuick::WheelEvent::pixelDelta
This property holds the delta in screen pixels and is available in platforms that
- have high-resolution trackpads, such as \macos.
- The x and y cordinate of this property holds the delta in horizontal and
- vertical orientation. The value should be used directly to scroll content on screen.
+ have high-resolution \l {QInputDevice::DeviceType::TouchPad}{trackpads}, such as \macos.
+ The \c x and \c y coordinates of this property hold the delta in horizontal
+ and vertical orientations, respectively. The values can be used directly to
+ scroll content on screen.
- For platforms without high-resolution trackpad support, pixelDelta will always be (0,0),
- and angleDelta should be used instead.
+ For platforms without \l {QInputDevice::Capability::PixelScroll}{high-resolution trackpad}
+ support, pixelDelta will always be \c {(0,0)}, and \l angleDelta should be used instead.
+
+ \sa QWheelEvent::pixelDelta()
*/
/*!
@@ -449,7 +460,7 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
For example, to react to a Control key pressed during the wheel event:
\qml
- MouseArea {
+ WheelHandler {
onWheel: (wheel)=> {
if (wheel.modifiers & Qt.ControlModifier) {
adjustZoom(wheel.angleDelta.y / 120);
@@ -457,6 +468,8 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
}
}
\endqml
+
+ \sa QWheelEvent::modifiers()
*/
/*!
@@ -478,7 +491,11 @@ bool QQuickKeyEvent::matches(QKeySequence::StandardKey matchKey) const
negate the angleDelta or pixelDelta values.
\note Many platforms provide no such information. On such platforms
- \l inverted always returns false.
+ \c inverted always returns \c false.
+
+ \sa QWheelEvent::inverted()
*/
QT_END_NAMESPACE
+
+#include "moc_qquickevents_p_p.cpp"
diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp
index 14bf190fe9..e050561ac5 100644
--- a/src/quick/items/qquickflickable.cpp
+++ b/src/quick/items/qquickflickable.cpp
@@ -43,6 +43,8 @@
#include "qquickwindow.h"
#include "qquickwindow_p.h"
#include "qquickevents_p_p.h"
+#include "qquickmousearea_p.h"
+#include "qquickdrag_p.h"
#include <QtQuick/private/qquickpointerhandler_p.h>
#include <QtQuick/private/qquicktransition_p.h>
@@ -52,6 +54,7 @@
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/qstylehints.h>
#include <QtCore/qmath.h>
#include "qplatformdefs.h"
@@ -137,7 +140,8 @@ void QQuickFlickableVisibleArea::updateVisible()
qreal pagePos = 0;
qreal pageSize = 0;
if (!qFuzzyIsNull(maxYBounds)) {
- pagePos = (-p->vData.move.value() + flickable->minYExtent()) / maxYBounds;
+ qreal y = p->pixelAligned ? Round(p->vData.move.value()) : p->vData.move.value();
+ pagePos = (-y + flickable->minYExtent()) / maxYBounds;
pageSize = viewheight / maxYBounds;
}
@@ -155,7 +159,8 @@ void QQuickFlickableVisibleArea::updateVisible()
const qreal maxxextent = -flickable->maxXExtent() + flickable->minXExtent();
const qreal maxXBounds = maxxextent + viewwidth;
if (!qFuzzyIsNull(maxXBounds)) {
- pagePos = (-p->hData.move.value() + flickable->minXExtent()) / maxXBounds;
+ qreal x = p->pixelAligned ? Round(p->hData.move.value()) : p->hData.move.value();
+ pagePos = (-x + flickable->minXExtent()) / maxXBounds;
pageSize = viewwidth / maxXBounds;
} else {
pagePos = 0;
@@ -253,9 +258,27 @@ QQuickFlickablePrivate::AxisData::~AxisData()
delete transitionToBounds;
}
+class QQuickFlickableContentItem : public QQuickItem
+{
+ /*!
+ \internal
+ The flickable area inside the viewport can be bigger than the bounds of the
+ content item itself, if the flickable is using non-zero extents (as returned
+ by e.g minXExtent()). Since the default implementation in QQuickItem::contains()
+ only checks if the point is inside the bounds of the item, we need to override it
+ to check the extents as well. The easist way to do this is to simply check if the
+ point is inside the bounds of the flickable rather than the content item.
+ */
+ bool contains(const QPointF &point) const override
+ {
+ const QQuickItem *flickable = parentItem();
+ const QPointF posInFlickable = flickable->mapFromItem(this, point);
+ return flickable->contains(posInFlickable);
+ }
+};
QQuickFlickablePrivate::QQuickFlickablePrivate()
- : contentItem(new QQuickItem)
+ : contentItem(new QQuickFlickableContentItem)
, hData(this, &QQuickFlickablePrivate::setViewportX)
, vData(this, &QQuickFlickablePrivate::setViewportY)
, hMoved(false), vMoved(false)
@@ -293,16 +316,17 @@ void QQuickFlickablePrivate::init()
viewportPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
}
-/*
- Returns the amount to overshoot by given a velocity.
- Will be roughly in range 0 - size/4
+/*!
+ \internal
+ Returns the distance to overshoot, given \a velocity.
+ Will be in range 0 - velocity / 3, but limited to a max of QML_FLICK_OVERSHOOT
*/
-qreal QQuickFlickablePrivate::overShootDistance(qreal size) const
+qreal QQuickFlickablePrivate::overShootDistance(qreal velocity) const
{
if (maxVelocity <= 0)
- return 0.0;
+ return 0;
- return qMin(qreal(QML_FLICK_OVERSHOOT), size/3);
+ return qMin(qreal(QML_FLICK_OVERSHOOT), velocity / 3);
}
void QQuickFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity)
@@ -329,7 +353,7 @@ void QQuickFlickablePrivate::AxisData::updateVelocity()
}
}
-void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &)
+void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &oldGeom)
{
Q_Q(QQuickFlickable);
if (item == contentItem) {
@@ -338,8 +362,14 @@ void QQuickFlickablePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometr
orient |= Qt::Horizontal;
if (change.yChange())
orient |= Qt::Vertical;
- if (orient)
+ if (orient) {
q->viewportMoved(orient);
+ const QPointF deltaMoved = item->position() - oldGeom.topLeft();
+ if (hData.contentPositionChangedExternallyDuringDrag)
+ hData.pressPos += deltaMoved.x();
+ if (vData.contentPositionChangedExternallyDuringDrag)
+ vData.pressPos += deltaMoved.y();
+ }
if (orient & Qt::Horizontal)
emit q->contentXChanged();
if (orient & Qt::Vertical)
@@ -531,8 +561,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxyextent = -q->maxYExtent();
const qreal minyextent = -q->minYExtent();
const qreal ypos = -vData.move.value();
- bool atBeginning = fuzzyLessThanOrEqualTo(ypos, minyextent);
- bool atEnd = fuzzyLessThanOrEqualTo(maxyextent, ypos);
+ bool atBeginning = fuzzyLessThanOrEqualTo(ypos, std::ceil(minyextent));
+ bool atEnd = fuzzyLessThanOrEqualTo(std::floor(maxyextent), ypos);
if (atBeginning != vData.atBeginning) {
vData.atBeginning = atBeginning;
@@ -551,8 +581,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
const qreal maxxextent = -q->maxXExtent();
const qreal minxextent = -q->minXExtent();
const qreal xpos = -hData.move.value();
- atBeginning = fuzzyLessThanOrEqualTo(xpos, minxextent);
- atEnd = fuzzyLessThanOrEqualTo(maxxextent, xpos);
+ atBeginning = fuzzyLessThanOrEqualTo(xpos, std::ceil(minxextent));
+ atEnd = fuzzyLessThanOrEqualTo(std::floor(maxxextent), xpos);
if (atBeginning != hData.atBeginning) {
hData.atBeginning = atBeginning;
@@ -722,7 +752,8 @@ void QQuickFlickablePrivate::updateBeginningEnd()
/*!
\qmlsignal QtQuick::Flickable::flickEnded()
- This signal is emitted when the view stops moving due to a flick.
+ This signal is emitted when the view stops moving after a flick
+ or a series of flicks.
*/
/*!
@@ -799,8 +830,11 @@ void QQuickFlickable::setContentX(qreal pos)
d->hData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(true, false);
- if (!qFuzzyCompare(-pos, d->hData.move.value()))
+ if (!qFuzzyCompare(-pos, d->hData.move.value())) {
+ d->hData.contentPositionChangedExternallyDuringDrag = d->hData.dragging;
d->hData.move.setValue(-pos);
+ d->hData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
qreal QQuickFlickable::contentY() const
@@ -817,8 +851,11 @@ void QQuickFlickable::setContentY(qreal pos)
d->vData.vTime = d->timeline.time();
if (isMoving() || isFlicking())
movementEnding(false, true);
- if (!qFuzzyCompare(-pos, d->vData.move.value()))
+ if (!qFuzzyCompare(-pos, d->vData.move.value())) {
+ d->vData.contentPositionChangedExternallyDuringDrag = d->vData.dragging;
d->vData.move.setValue(-pos);
+ d->vData.contentPositionChangedExternallyDuringDrag = false;
+ }
}
/*!
@@ -1032,6 +1069,17 @@ void QQuickFlickable::setSynchronousDrag(bool v)
}
}
+/*! \internal
+ Take the velocity of the first point from the given \a event and transform
+ it to the local coordinate system (taking scale and rotation into account).
+*/
+QVector2D QQuickFlickablePrivate::firstPointLocalVelocity(QPointerEvent *event)
+{
+ QTransform transform = windowToItemTransform();
+ // rotate and scale the velocity vector from scene to local
+ return QVector2D(transform.map(event->point(0).velocity().toPointF()) - transform.map(QPointF()));
+}
+
qint64 QQuickFlickablePrivate::computeCurrentTime(QInputEvent *event) const
{
if (0 != event->timestamp())
@@ -1103,7 +1151,9 @@ void QQuickFlickablePrivate::maybeBeginDrag(qint64 currentTimestamp, const QPoin
pressPos = pressPosn;
hData.pressPos = hData.move.value();
vData.pressPos = vData.move.value();
- bool wasFlicking = hData.flicking || vData.flicking;
+ const bool wasFlicking = hData.flicking || vData.flicking;
+ hData.flickingWhenDragBegan = hData.flicking;
+ vData.flickingWhenDragBegan = vData.flicking;
if (hData.flicking) {
hData.flicking = false;
emit q->flickingHorizontallyChanged();
@@ -1333,15 +1383,15 @@ void QQuickFlickablePrivate::handleMoveEvent(QPointerEvent *event)
{
Q_Q(QQuickFlickable);
if (!interactive || lastPosTime == -1 ||
- (event->isSinglePointEvent() && static_cast<QSinglePointEvent *>(event)->buttons() == Qt::NoButton))
+ (event->isSinglePointEvent() && !static_cast<QSinglePointEvent *>(event)->buttons().testFlag(Qt::LeftButton)))
return;
qint64 currentTimestamp = computeCurrentTime(event);
const auto &firstPoint = event->points().first();
const auto &pos = firstPoint.position();
- QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
+ const QVector2D deltas = QVector2D(pos - q->mapFromGlobal(firstPoint.globalPressPosition()));
+ const QVector2D velocity = firstPointLocalVelocity(event);
bool overThreshold = false;
- QVector2D velocity = event->point(0).velocity();
if (q->yflick())
overThreshold |= QQuickDeliveryAgentPrivate::dragOverThreshold(deltas.y(), Qt::YAxis, firstPoint);
@@ -1373,12 +1423,14 @@ void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
bool canBoost = false;
const auto pos = event->points().first().position();
- const auto pressPos = event->points().first().pressPosition();
+ const auto pressPos = q->mapFromGlobal(event->points().first().globalPressPosition());
+ const QVector2D eventVelocity = firstPointLocalVelocity(event);
+ qCDebug(lcVel) << event->deviceType() << event->type() << "velocity" << event->points().first().velocity() << "transformed to local" << eventVelocity;
qreal vVelocity = 0;
if (elapsed < 100 && vData.velocity != 0.) {
vVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
- ? event->point(0).velocity().y() : vData.velocity);
+ ? eventVelocity.y() : vData.velocity);
}
if ((vData.atBeginning && vVelocity > 0.) || (vData.atEnd && vVelocity < 0.)) {
vVelocity /= 2;
@@ -1393,7 +1445,7 @@ void QQuickFlickablePrivate::handleReleaseEvent(QPointerEvent *event)
qreal hVelocity = 0;
if (elapsed < 100 && hData.velocity != 0.) {
hVelocity = (event->device()->capabilities().testFlag(QInputDevice::Capability::Velocity)
- ? event->point(0).velocity().x() : hData.velocity);
+ ? eventVelocity.x() : hData.velocity);
}
if ((hData.atBeginning && hVelocity > 0.) || (hData.atEnd && hVelocity < 0.)) {
hVelocity /= 2;
@@ -1599,7 +1651,7 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
return;
}
- if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull()) {
+ if (event->source() == Qt::MouseEventNotSynthesized || event->pixelDelta().isNull() || event->phase() == Qt::NoScrollPhase) {
// no pixel delta (physical mouse wheel, or "dumb" touchpad), so use angleDelta
int xDelta = event->angleDelta().x();
int yDelta = event->angleDelta().y();
@@ -1620,9 +1672,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->vData.addVelocitySample(instVelocity, d->maxVelocity);
d->vData.updateVelocity();
if ((yDelta > 0 && contentY() > -minYExtent()) || (yDelta < 0 && contentY() < -maxYExtent())) {
- d->flickY(d->vData.velocity);
- d->flickingStarted(false, true);
- if (d->vData.flicking) {
+ const bool newFlick = d->flickY(d->vData.velocity);
+ if (newFlick && (d->vData.atBeginning != (yDelta > 0) || d->vData.atEnd != (yDelta < 0))) {
+ d->flickingStarted(false, true);
d->vMoved = true;
movementStarting();
}
@@ -1637,9 +1689,9 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event)
d->hData.addVelocitySample(instVelocity, d->maxVelocity);
d->hData.updateVelocity();
if ((xDelta > 0 && contentX() > -minXExtent()) || (xDelta < 0 && contentX() < -maxXExtent())) {
- d->flickX(d->hData.velocity);
- d->flickingStarted(true, false);
- if (d->hData.flicking) {
+ const bool newFlick = d->flickX(d->hData.velocity);
+ if (newFlick && (d->hData.atBeginning != (xDelta > 0) || d->hData.atEnd != (xDelta < 0))) {
+ d->flickingStarted(true, false);
d->hMoved = true;
movementStarting();
}
@@ -1867,13 +1919,13 @@ void QQuickFlickable::viewportMoved(Qt::Orientations orient)
{
Q_D(QQuickFlickable);
if (orient & Qt::Vertical)
- d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), height(), d->fixupY_callback);
+ d->viewportAxisMoved(d->vData, minYExtent(), maxYExtent(), d->fixupY_callback);
if (orient & Qt::Horizontal)
- d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), width(), d->fixupX_callback);
+ d->viewportAxisMoved(d->hData, minXExtent(), maxXExtent(), d->fixupX_callback);
d->updateBeginningEnd();
}
-void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
QQuickTimeLineCallback::Callback fixupCallback)
{
if (!scrollingPhase && (pressed || calcVelocity)) {
@@ -1889,10 +1941,15 @@ void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent,
} else {
if (timeline.time() > data.vTime) {
velocityTimeline.reset(data.smoothVelocity);
- qreal velocity = (data.lastPos - data.move.value()) * 1000 / (timeline.time() - data.vTime);
- if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
- qCDebug(lcVel) << "velocity" << data.smoothVelocity.value() << "->" << velocity;
- data.smoothVelocity.setValue(velocity);
+ int dt = timeline.time() - data.vTime;
+ if (dt > 2) {
+ qreal velocity = (data.lastPos - data.move.value()) * 1000 / dt;
+ if (!qFuzzyCompare(data.smoothVelocity.value(), velocity))
+ qCDebug(lcVel) << "velocity" << data.smoothVelocity.value() << "->" << velocity
+ << "computed as (" << data.lastPos << "-" << data.move.value() << ") * 1000 / ("
+ << timeline.time() << "-" << data.vTime << ")";
+ data.smoothVelocity.setValue(velocity);
+ }
}
}
@@ -1904,7 +1961,7 @@ void QQuickFlickablePrivate::viewportAxisMoved(AxisData &data, qreal minExtent,
? data.move.value() - minExtent
: maxExtent - data.move.value();
data.inOvershoot = true;
- qreal maxDistance = overShootDistance(vSize) - overBound;
+ qreal maxDistance = overShootDistance(qAbs(data.smoothVelocity.value())) - overBound;
resetTimeline(data);
if (maxDistance > 0)
timeline.accel(data.move, -data.smoothVelocity.value(), deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance);
@@ -2513,6 +2570,23 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool receiverDisabled = receiver && !receiver->isEnabled();
bool stealThisEvent = d->stealMouse;
bool receiverKeepsGrab = receiver && (receiver->keepMouseGrab() || receiver->keepTouchGrab());
+ bool receiverRelinquishGrab = false;
+
+ // Special case for MouseArea, try to guess what it does with the event
+ if (auto *mouseArea = qmlobject_cast<QQuickMouseArea *>(receiver)) {
+ bool preventStealing = mouseArea->preventStealing();
+ if (mouseArea->drag() && mouseArea->drag()->target())
+ preventStealing = true;
+ if (!preventStealing && receiverKeepsGrab) {
+ receiverRelinquishGrab = !receiverDisabled
+ || (QQuickDeliveryAgentPrivate::isMouseEvent(event)
+ && firstPoint.state() == QEventPoint::State::Pressed
+ && (receiver->acceptedMouseButtons() & static_cast<QMouseEvent *>(event)->button()));
+ if (receiverRelinquishGrab)
+ receiverKeepsGrab = false;
+ }
+ }
+
if ((stealThisEvent || contains(localPos)) && (!receiver || !receiverKeepsGrab || receiverDisabled)) {
QScopedPointer<QPointerEvent> localizedEvent(QQuickDeliveryAgentPrivate::clonePointerEvent(event, localPos));
localizedEvent->setAccepted(false);
@@ -2523,7 +2597,9 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
case QEventPoint::State::Pressed:
d->handlePressEvent(localizedEvent.data());
d->captureDelayedPress(receiver, event);
- stealThisEvent = d->stealMouse; // Update stealThisEvent in case changed by function call above
+ // never grab the pointing device on press during filtering: do it later, during a move
+ d->stealMouse = false;
+ stealThisEvent = false;
break;
case QEventPoint::State::Released:
d->handleReleaseEvent(localizedEvent.data());
@@ -2540,7 +2616,7 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
event->setExclusiveGrabber(firstPoint, this);
}
- const bool filtered = stealThisEvent || d->delayedPressEvent || receiverDisabled;
+ const bool filtered = !receiverRelinquishGrab && (stealThisEvent || d->delayedPressEvent || receiverDisabled);
if (filtered) {
event->setAccepted(true);
}
@@ -2566,8 +2642,19 @@ bool QQuickFlickable::filterPointerEvent(QQuickItem *receiver, QPointerEvent *ev
bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
{
Q_D(QQuickFlickable);
+ QPointerEvent *pointerEvent = e->isPointerEvent() ? static_cast<QPointerEvent *>(e) : nullptr;
+
+ auto wantsPointerEvent_helper = [this, d, i, pointerEvent]() {
+ Q_ASSERT(pointerEvent);
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, this);
+ const bool wants = d->wantsPointerEvent(pointerEvent);
+ // re-localize event back to \a i before returning
+ QQuickDeliveryAgentPrivate::localizePointerEvent(pointerEvent, i);
+ return wants;
+ };
+
if (!isVisible() || !isEnabled() || !isInteractive() ||
- (e->isPointerEvent() && !d->wantsPointerEvent(static_cast<QPointerEvent *>(e)))) {
+ (pointerEvent && !wantsPointerEvent_helper())) {
d->cancelInteraction();
return QQuickItem::childMouseEventFilter(i, e);
}
@@ -2579,8 +2666,8 @@ bool QQuickFlickable::childMouseEventFilter(QQuickItem *i, QEvent *e)
qCDebug(lcFilter) << "filtering UngrabMouse" << spe->points().first() << "for" << i << "grabber is" << grabber;
if (grabber != this)
mouseUngrabEvent(); // A child has been ungrabbed
- } else if (e->isPointerEvent()) {
- return filterPointerEvent(i, static_cast<QPointerEvent *>(e));
+ } else if (pointerEvent) {
+ return filterPointerEvent(i, pointerEvent);
}
return QQuickItem::childMouseEventFilter(i, e);
@@ -2848,6 +2935,12 @@ void QQuickFlickable::movementStarting()
if (!wasMoving && (d->hData.moving || d->vData.moving)) {
emit movingChanged();
emit movementStarted();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingStart);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
}
@@ -2861,7 +2954,7 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
Q_D(QQuickFlickable);
// emit flicking signals
- bool wasFlicking = d->hData.flicking || d->vData.flicking;
+ const bool wasFlicking = d->hData.flicking || d->vData.flicking;
if (hMovementEnding && d->hData.flicking) {
d->hData.flicking = false;
emit flickingHorizontallyChanged();
@@ -2873,6 +2966,10 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasFlicking && (!d->hData.flicking || !d->vData.flicking)) {
emit flickingChanged();
emit flickEnded();
+ } else if (d->hData.flickingWhenDragBegan || d->vData.flickingWhenDragBegan) {
+ d->hData.flickingWhenDragBegan = !hMovementEnding;
+ d->vData.flickingWhenDragBegan = !vMovementEnding;
+ emit flickEnded();
}
// emit moving signals
@@ -2892,6 +2989,12 @@ void QQuickFlickable::movementEnding(bool hMovementEnding, bool vMovementEnding)
if (wasMoving && !isMoving()) {
emit movingChanged();
emit movementEnded();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive()) {
+ QAccessibleEvent ev(this, QAccessible::ScrollingEnd);
+ QAccessible::updateAccessibility(&ev);
+ }
+#endif
}
if (hMovementEnding) {
@@ -3019,4 +3122,6 @@ void QQuickFlickable::setBoundsMovement(BoundsMovement movement)
QT_END_NAMESPACE
+#include "moc_qquickflickable_p_p.cpp"
+
#include "moc_qquickflickable_p.cpp"
diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h
index a003a69b9f..c748bb9f43 100644
--- a/src/quick/items/qquickflickable_p_p.h
+++ b/src/quick/items/qquickflickable_p_p.h
@@ -107,8 +107,9 @@ public:
, smoothVelocity(fp), atEnd(false), atBeginning(true)
, transitionToSet(false)
, fixingUp(false), inOvershoot(false), inRebound(false), moving(false), flicking(false)
- , dragging(false), extentsChanged(false)
+ , flickingWhenDragBegan(false), dragging(false), extentsChanged(false)
, explicitValue(false), minExtentDirty(true), maxExtentDirty(true)
+ , contentPositionChangedExternallyDuringDrag(false)
, unused(0)
{}
@@ -119,6 +120,7 @@ public:
dragStartOffset = 0;
fixingUp = false;
inOvershoot = false;
+ contentPositionChangedExternallyDuringDrag = false;
}
void markExtentsDirty() {
@@ -156,20 +158,22 @@ public:
int vTime;
QQuickFlickablePrivate::Velocity smoothVelocity;
QPODVector<qreal,10> velocityBuffer;
- bool atEnd : 1;
- bool atBeginning : 1;
- bool transitionToSet : 1;
- bool fixingUp : 1;
- bool inOvershoot : 1;
- bool inRebound : 1;
- bool moving : 1;
- bool flicking : 1;
- bool dragging : 1;
- bool extentsChanged : 1;
- bool explicitValue : 1;
- mutable bool minExtentDirty : 1;
- mutable bool maxExtentDirty : 1;
- uint unused : 19;
+ uint atEnd : 1;
+ uint atBeginning : 1;
+ uint transitionToSet : 1;
+ uint fixingUp : 1;
+ uint inOvershoot : 1;
+ uint inRebound : 1;
+ uint moving : 1;
+ uint flicking : 1;
+ uint flickingWhenDragBegan : 1;
+ uint dragging : 1;
+ uint extentsChanged : 1;
+ uint explicitValue : 1;
+ mutable uint minExtentDirty : 1;
+ mutable uint maxExtentDirty : 1;
+ uint contentPositionChangedExternallyDuringDrag : 1;
+ uint unused : 17;
};
bool flickX(qreal velocity);
@@ -195,7 +199,7 @@ public:
void setViewportX(qreal x);
void setViewportY(qreal y);
- qreal overShootDistance(qreal size) const;
+ qreal overShootDistance(qreal velocity) const;
void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
@@ -256,7 +260,7 @@ public:
QQuickFlickable::BoundsMovement boundsMovement;
QQuickTransition *rebound;
- void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize,
+ void viewportAxisMoved(AxisData &data, qreal minExtent, qreal maxExtent,
QQuickTimeLineCallback::Callback fixupCallback);
void handlePressEvent(QPointerEvent *);
@@ -268,6 +272,7 @@ public:
const QVector2D &deltas, bool overThreshold, bool momentum,
bool velocitySensitiveOverBounds, const QVector2D &velocity);
+ QVector2D firstPointLocalVelocity(QPointerEvent *event);
qint64 computeCurrentTime(QInputEvent *event) const;
qreal devicePixelRatio() const;
@@ -278,7 +283,7 @@ public:
static void data_clear(QQmlListProperty<QObject> *);
};
-class QQuickFlickableVisibleArea : public QObject
+class Q_QUICK_PRIVATE_EXPORT QQuickFlickableVisibleArea : public QObject
{
Q_OBJECT
diff --git a/src/quick/items/qquickflipable.cpp b/src/quick/items/qquickflipable.cpp
index a338985622..87112c8b93 100644
--- a/src/quick/items/qquickflipable.cpp
+++ b/src/quick/items/qquickflipable.cpp
@@ -39,7 +39,7 @@
#include "qquickflipable_p.h"
#include "qquickitem_p.h"
-
+#include "qquicktranslate_p.h"
#include <QtQml/qqmlinfo.h>
@@ -237,9 +237,20 @@ void QQuickFlipable::updatePolish()
d->updateSide();
}
-// determination on the currently visible side of the flipable
-// has to be done on the complete scene transform to give
-// correct results.
+/*! \internal
+ Flipable must use the complete scene transform to correctly determine the
+ currently visible side.
+
+ It must also be independent of camera distance, in case the contents are
+ too wide: for rotation transforms we simply call QMatrix4x4::rotate(),
+ whereas QQuickRotation::applyTo(QMatrix4x4*) calls
+ QMatrix4x4::projectedRotate() which by default assumes the camera distance
+ is 1024 virtual pixels. So for example if contents inside Flipable are to
+ be flipped around the y axis, and are wider than 1024*2, some of the
+ rendering goes behind the "camera". That's expected for rendering (since we
+ didn't provide API to change camera distance), but not ok for deciding when
+ to flip.
+*/
void QQuickFlipablePrivate::updateSide()
{
Q_Q(QQuickFlipable);
@@ -249,8 +260,39 @@ void QQuickFlipablePrivate::updateSide()
sideDirty = false;
- QTransform sceneTransform;
- itemToParentTransform(sceneTransform);
+ QMatrix4x4 sceneTransform;
+
+ const qreal tx = x.value();
+ const qreal ty = y.value();
+ if (!qFuzzyIsNull(tx) || !qFuzzyIsNull(ty))
+ sceneTransform.translate(tx, ty);
+
+ for (const auto *transform : std::as_const(transforms)) {
+ if (const auto *rot = qobject_cast<const QQuickRotation *>(transform)) {
+ // rotation is a special case: we want to call rotate() instead of projectedRotate()
+ const auto angle = rot->angle();
+ const auto axis = rot->axis();
+ if (!(qFuzzyIsNull(angle) || axis.isNull())) {
+ sceneTransform.translate(rot->origin());
+ sceneTransform.rotate(angle, axis.x(), axis.y(), axis.z());
+ sceneTransform.translate(-rot->origin());
+ }
+ } else {
+ transform->applyTo(&sceneTransform);
+ }
+ }
+
+ const bool hasRotation = !qFuzzyIsNull(rotation());
+ const bool hasScale = !qFuzzyCompare(scale(), 1);
+ if (hasScale || hasRotation) {
+ QPointF tp = computeTransformOrigin();
+ sceneTransform.translate(tp.x(), tp.y());
+ if (hasScale)
+ sceneTransform.scale(scale(), scale());
+ if (hasRotation)
+ sceneTransform.rotate(rotation(), 0, 0, 1);
+ sceneTransform.translate(-tp.x(), -tp.y());
+ }
QPointF p1(0, 0);
QPointF p2(1, 0);
diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp
index 90fa05f492..73fe84fdef 100644
--- a/src/quick/items/qquickgridview.cpp
+++ b/src/quick/items/qquickgridview.cpp
@@ -208,6 +208,8 @@ public:
void updateHeader() override;
void updateFooter() override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -349,9 +351,27 @@ qreal QQuickGridViewPrivate::rowPosAt(int modelIndex) const
return lastItem->rowPos() + rows * rowSize();
}
}
- return (modelIndex / columns) * rowSize();
-}
+ qreal rowPos = ((modelIndex / columns) * rowSize());
+
+ if (flow == QQuickGridView::FlowLeftToRight && verticalLayoutDirection == QQuickItemView::TopToBottom) {
+ // Add the effective startpos of row 0. Start by subtracting minExtent, which will contain the
+ // height of the rows outside the beginning of the content item. (Rows can end up outside if
+ // e.g flicking the viewport a long way down, changing cellSize, and then flick back).
+ // NOTE: It's not clearly understood why the flow == QQuickGridView::FlowLeftToRight guard is
+ // needed, since the flow shouldn't normally affect the y postition of an index. But without
+ // it, several auto tests start failing, so we keep it until this part is better understood.
+ rowPos -= minExtent;
+ // minExtent will also contain the size of the topMargin (vData.startMargin), the header, and
+ // the highlightRangeStart. Those should be added before the start of row 0. So we need to subtract
+ // them from the rowPos. But only the largest of topMargin and highlightRangeStart will need
+ // to be taken into account, since having a topMargin will also ensure that currentItem ends
+ // up within the requested highlight range when view is positioned at the beginning.
+ rowPos += qMax(vData.startMargin, highlightRangeStart) + headerSize();
+ }
+
+ return rowPos;
+}
qreal QQuickGridViewPrivate::snapPosAt(qreal pos) const
{
@@ -835,6 +855,14 @@ void QQuickGridViewPrivate::updateFooter()
emit q->footerItemChanged();
}
+void QQuickGridViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickGridViewAttached *attached = static_cast<QQuickGridViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickGridView>(item));
+ if (attached)
+ attached->setView(const_cast<QQuickGridView*>(q_func()));
+}
+
void QQuickGridViewPrivate::updateHeader()
{
Q_Q(QQuickGridView);
diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp
index 4226bb7a57..4426c26cab 100644
--- a/src/quick/items/qquickimage.cpp
+++ b/src/quick/items/qquickimage.cpp
@@ -494,6 +494,8 @@ qreal QQuickImage::paintedHeight() const
\note \e {Changing this property dynamically causes the image source to be reloaded,
potentially even from the network, if it is not in the disk cache.}
+
+ \sa {Pointer Handlers Example}
*/
/*!
@@ -970,3 +972,7 @@ void QQuickImage::setMipmap(bool use)
*/
QT_END_NAMESPACE
+
+#include "moc_qquickimage_p_p.cpp"
+
+#include "moc_qquickimage_p.cpp"
diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp
index 619b3c299b..596cd7d63a 100644
--- a/src/quick/items/qquickimagebase.cpp
+++ b/src/quick/items/qquickimagebase.cpp
@@ -51,6 +51,17 @@
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"));
+}
+
// This function gives derived classes the chance set the devicePixelRatio
// if they're not happy with our implementation of it.
bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
@@ -58,17 +69,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.
- bool setDevicePixelRatio = false;
- if (url.scheme() == QLatin1String("image")) {
- setDevicePixelRatio = true;
- } else {
- QString stringUrl = url.path(QUrl::PrettyDecoded);
- if (stringUrl.endsWith(QLatin1String("svg")) ||
- stringUrl.endsWith(QLatin1String("svgz")) ||
- stringUrl.endsWith(QLatin1String("pdf"))) {
- setDevicePixelRatio = true;
- }
- }
+ const bool setDevicePixelRatio = isScalableImageFormat(url);
if (setDevicePixelRatio)
devicePixelRatio = targetDevicePixelRatio;
@@ -326,8 +327,10 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
const qreal targetDevicePixelRatio = (window() ? window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio());
d->devicePixelRatio = 1.0;
bool updatedDevicePixelRatio = false;
- if (d->sourcesize.isValid())
+ if (d->sourcesize.isValid()
+ || (isScalableImageFormat(d->url) && d->url.scheme() != QLatin1String("image"))) {
updatedDevicePixelRatio = d->updateDevicePixelRatio(targetDevicePixelRatio);
+ }
if (!updatedDevicePixelRatio) {
// (possible) local file: loadUrl and d->devicePixelRatio will be modified if
@@ -343,7 +346,8 @@ void QQuickImageBase::loadPixmap(const QUrl &url, LoadPixmapOptions loadOptions)
(loadOptions & HandleDPR) ? d->sourcesize * d->devicePixelRatio : QSize(),
options,
(loadOptions & UseProviderOptions) ? d->providerOptions : QQuickImageProviderOptions(),
- d->currentFrame, d->frameCount);
+ d->currentFrame, d->frameCount,
+ d->devicePixelRatio);
if (d->pix.isLoading()) {
if (d->progress != 0.0) {
diff --git a/src/quick/items/qquickimplicitsizeitem_p.h b/src/quick/items/qquickimplicitsizeitem_p.h
index 8ae8f9f447..41f682fe57 100644
--- a/src/quick/items/qquickimplicitsizeitem_p.h
+++ b/src/quick/items/qquickimplicitsizeitem_p.h
@@ -62,6 +62,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickImplicitSizeItem : public QQuickItem
Q_OBJECT
Q_PROPERTY(qreal implicitWidth READ implicitWidth NOTIFY implicitWidthChanged)
Q_PROPERTY(qreal implicitHeight READ implicitHeight NOTIFY implicitHeightChanged)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(6, 2)
protected:
QQuickImplicitSizeItem(QQuickImplicitSizeItemPrivate &dd, QQuickItem *parent);
diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp
index cdaf4773f1..dfa88c0a04 100644
--- a/src/quick/items/qquickitem.cpp
+++ b/src/quick/items/qquickitem.cpp
@@ -53,6 +53,7 @@
#include <QtGui/qpen.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qpointingdevice_p.h>
#include <QtGui/qinputmethod.h>
@@ -60,6 +61,7 @@
#include <QtCore/private/qnumeric_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtCore/qloggingcategory.h>
+#include <QtCore/private/qduplicatetracker_p.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmlengine_p.h>
@@ -403,42 +405,42 @@ void QQuickItemKeyFilter::componentComplete()
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::left
+ \qmlattachedproperty Item QtQuick::KeyNavigation::left
This property holds the item to assign focus to
when the left cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::right
+ \qmlattachedproperty Item QtQuick::KeyNavigation::right
This property holds the item to assign focus to
when the right cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::up
+ \qmlattachedproperty Item QtQuick::KeyNavigation::up
This property holds the item to assign focus to
when the up cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::down
+ \qmlattachedproperty Item QtQuick::KeyNavigation::down
This property holds the item to assign focus to
when the down cursor key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::tab
+ \qmlattachedproperty Item QtQuick::KeyNavigation::tab
This property holds the item to assign focus to
when the Tab key is pressed.
*/
/*!
- \qmlproperty Item QtQuick::KeyNavigation::backtab
+ \qmlattachedproperty Item QtQuick::KeyNavigation::backtab
This property holds the item to assign focus to
when the Shift+Tab key combination (Backtab) is pressed.
@@ -590,7 +592,7 @@ void QQuickKeyNavigationAttached::setBacktab(QQuickItem *i)
}
/*!
- \qmlproperty enumeration QtQuick::KeyNavigation::priority
+ \qmlattachedproperty enumeration QtQuick::KeyNavigation::priority
This property determines whether the keys are processed before
or after the attached item's own key handling.
@@ -908,7 +910,7 @@ bool QQuickKeysAttached::isConnected(const char *signalName) const
*/
/*!
- \qmlproperty list<Object> QtQuick::Keys::forwardTo
+ \qmlproperty list<Item> QtQuick::Keys::forwardTo
This property provides a way to forward key presses, key releases, and keyboard input
coming from input methods to other items. This can be useful when you want
@@ -2351,31 +2353,22 @@ QQuickItem::~QQuickItem()
while (!d->childItems.isEmpty())
d->childItems.constFirst()->setParentItem(nullptr);
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor)
- anchor->clearItem(this);
- }
-
- /*
+ d->notifyChangeListeners(QQuickItemPrivate::AllChanges, [this](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->clearItem(this);
+ });
+ /*
update item anchors that depended on us unless they are our child (and will also be destroyed),
or our sibling, and our parent is also being destroyed.
*/
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
- anchor->update();
- }
-
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Destroyed)
- change.listener->itemDestroyed(this);
- }
-
- d->changeListeners.clear();
- }
+ d->notifyChangeListeners(QQuickItemPrivate::AllChanges, [this](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor && anchor->item && anchor->item->parentItem() && anchor->item->parentItem() != this)
+ anchor->update();
+ });
+ d->notifyChangeListeners(QQuickItemPrivate::Destroyed, &QQuickItemChangeListener::itemDestroyed, this);
+ d->changeListeners.clear();
/*
Remove any references our transforms have to us, in case they try to
@@ -2539,6 +2532,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
QQuickItem *current = item;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem;
+ QDuplicateTracker<QQuickItem *> cycleDetector;
do {
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current;
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from;
@@ -2605,7 +2599,10 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo
// traversed all of the chain (by compare the [current] item with [startItem])
// Since the [startItem] might be promoted to its parent if it is invisible,
// we still have to check [current] item with original start item
- if ((current == startItem || current == originalStartItem) && from == firstFromItem) {
+ // We might also run into a cycle before we reach firstFromItem again
+ // but note that we have to ignore current if we are meant to skip it
+ if (((current == startItem || current == originalStartItem) && from == firstFromItem) ||
+ (!skip && cycleDetector.hasSeen(current))) {
// wrapped around, avoid endless loops
if (item == contentItem) {
qCDebug(lcFocus) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: looped, return contentItem";
@@ -3658,14 +3655,7 @@ QQuickAnchors *QQuickItemPrivate::anchors() const
void QQuickItemPrivate::siblingOrderChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::SiblingOrder) {
- change.listener->itemSiblingOrderChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::SiblingOrder, &QQuickItemChangeListener::itemSiblingOrderChanged, q);
}
QQmlListProperty<QObject> QQuickItemPrivate::data()
@@ -3733,6 +3723,9 @@ QList<QQuickItem *> QQuickItem::childItems() const
If clipping is enabled, an item will clip its own painting, as well
as the painting of its children, to its bounding rectangle.
+
+ \note Clipping can affect rendering performance. See \l {Clipping} for more
+ information.
*/
/*!
\property QQuickItem::clip
@@ -3783,15 +3776,10 @@ void QQuickItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
change.setWidthChange(newGeometry.width() != oldGeometry.width());
change.setHeightChange(newGeometry.height() != oldGeometry.height());
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &listener : listeners) {
- if (listener.types & QQuickItemPrivate::Geometry) {
- if (change.matches(listener.gTypes))
- listener.listener->itemGeometryChanged(this, change, oldGeometry);
- }
- }
- }
+ d->notifyChangeListeners(QQuickItemPrivate::Geometry, [&](const QQuickItemPrivate::ChangeListener &listener){
+ if (change.matches(listener.gTypes))
+ listener.listener->itemGeometryChanged(this, change, oldGeometry);
+ });
// The notify method takes care of emitting the signal, and also notifies any
// property observers.
@@ -4419,16 +4407,11 @@ void QQuickItem::setBaselineOffset(qreal offset)
d->baselineOffset = offset;
- if (!d->changeListeners.isEmpty()) {
- const auto listeners = d->changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Geometry) {
- QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
- if (anchor)
- anchor->updateVerticalAnchors();
- }
- }
- }
+ d->notifyChangeListeners(QQuickItemPrivate::Geometry, [](const QQuickItemPrivate::ChangeListener &change){
+ QQuickAnchorsPrivate *anchor = change.listener->anchorPrivate();
+ if (anchor)
+ anchor->updateVerticalAnchors();
+ });
if (d->_anchors && (d->_anchors->usedAnchors() & QQuickAnchors::BaselineAnchor))
QQuickAnchorsPrivate::get(d->_anchors)->updateVerticalAnchors();
@@ -4564,10 +4547,10 @@ static bool unwrapMapFromToFromItemArgs(QQmlV4Function *args, const QQuickItem *
}
/*!
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapFromItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapFromItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in \a
item's coordinate system, to this item's coordinate system, and returns a \l point or \l rect
@@ -4619,10 +4602,10 @@ QTransform QQuickItem::itemTransform(QQuickItem *other, bool *ok) const
}
/*!
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, point p)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
- \qmlmethod object QtQuick::Item::mapToItem(Item item, rect r)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, real x, real y)
+ \qmlmethod point QtQuick::Item::mapToItem(Item item, point p)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, real x, real y, real width, real height)
+ \qmlmethod rect QtQuick::Item::mapToItem(Item item, rect r)
Maps the point (\a x, \a y) or rect (\a x, \a y, \a width, \a height), which is in this
item's coordinate system, to \a item's coordinate system, and returns a \l point or \l rect
@@ -4704,7 +4687,7 @@ static bool unwrapMapFromToFromGlobalArgs(QQmlV4Function *args, const QQuickItem
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapFromGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapFromGlobal(real x, real y)
Maps the point (\a x, \a y), which is in the global coordinate system, to the
item's coordinate system, and returns a \l point matching the mapped coordinate.
@@ -4731,7 +4714,7 @@ void QQuickItem::mapFromGlobal(QQmlV4Function *args) const
/*!
\since 5.7
- \qmlmethod object QtQuick::Item::mapToGlobal(real x, real y)
+ \qmlmethod point QtQuick::Item::mapToGlobal(real x, real y)
Maps the point (\a x, \a y), which is in this item's coordinate system, to the
global coordinate system, and returns a \l point matching the mapped coordinate.
@@ -6424,26 +6407,12 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
switch (change) {
case QQuickItem::ItemChildAddedChange: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Children) {
- change.listener->itemChildAdded(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Children, &QQuickItemChangeListener::itemChildAdded, q, data.item);
break;
}
case QQuickItem::ItemChildRemovedChange: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Children) {
- change.listener->itemChildRemoved(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Children, &QQuickItemChangeListener::itemChildRemoved, q, data.item);
break;
}
case QQuickItem::ItemSceneChange:
@@ -6451,50 +6420,22 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemVisibleHasChanged: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Visibility) {
- change.listener->itemVisibilityChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Visibility, &QQuickItemChangeListener::itemVisibilityChanged, q);
break;
}
case QQuickItem::ItemEnabledHasChanged: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Enabled) {
- change.listener->itemEnabledChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Enabled, &QQuickItemChangeListener::itemEnabledChanged, q);
break;
}
case QQuickItem::ItemParentHasChanged: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Parent) {
- change.listener->itemParentChanged(q, data.item);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Parent, &QQuickItemChangeListener::itemParentChanged, q, data.item);
break;
}
case QQuickItem::ItemOpacityHasChanged: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Opacity) {
- change.listener->itemOpacityChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Opacity, &QQuickItemChangeListener::itemOpacityChanged, q);
break;
}
case QQuickItem::ItemActiveFocusHasChanged:
@@ -6502,14 +6443,7 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt
break;
case QQuickItem::ItemRotationHasChanged: {
q->itemChange(change, data);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::Rotation) {
- change.listener->itemRotationChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::Rotation, &QQuickItemChangeListener::itemRotationChanged, q);
break;
}
case QQuickItem::ItemAntialiasingHasChanged:
@@ -6787,16 +6721,17 @@ void QQuickItem::setX(qreal v)
d->x.removeBindingUnlessInWrapper();
if (qt_is_nan(v))
return;
- if (d->x == v)
+
+ const qreal oldx = d->x;
+ if (oldx == v)
return;
- qreal oldx = d->x;
d->x = v;
d->dirty(QQuickItemPrivate::Position);
- geometryChange(QRectF(v, d->y, d->width, d->height),
- QRectF(oldx, d->y, d->width, d->height));
+ const qreal y = d->y, w = d->width, h = d->height;
+ geometryChange(QRectF(v, y, w, h), QRectF(oldx, y, w, h));
}
void QQuickItem::setY(qreal v)
@@ -6805,18 +6740,19 @@ void QQuickItem::setY(qreal v)
d->y.removeBindingUnlessInWrapper();
if (qt_is_nan(v))
return;
- if (d->y == v)
+
+ const qreal oldy = d->y;
+ if (oldy == v)
return;
- qreal oldy = d->y;
d->y = v;
d->dirty(QQuickItemPrivate::Position);
// we use v instead of d->y, as that avoid a method call
// and we have v anyway in scope
- geometryChange(QRectF(d->x, v, d->width, d->height),
- QRectF(d->x, oldy, d->width, d->height));
+ const qreal x = d->x, w = d->width, h = d->height;
+ geometryChange(QRectF(x, v, w, h), QRectF(x, oldy, w, h));
}
/*!
@@ -6828,8 +6764,8 @@ void QQuickItem::setPosition(const QPointF &pos)
if (QPointF(d->x, d->y) == pos)
return;
- qreal oldx = d->x;
- qreal oldy = d->y;
+ const qreal oldx = d->x;
+ const qreal oldy = d->y;
/* This preserves the bindings, because that was what the code used to do
The effect of this is that you can have
@@ -6849,8 +6785,8 @@ void QQuickItem::setPosition(const QPointF &pos)
d->dirty(QQuickItemPrivate::Position);
- geometryChange(QRectF(d->x, d->y, d->width, d->height),
- QRectF(oldx, oldy, d->width, d->height));
+ const qreal w = d->width, h = d->height;
+ geometryChange(QRectF(pos.x(), pos.y(), w, h), QRectF(oldx, oldy, w, h));
}
/* The bindable methods return an object which supports inspection (hasBinding) and
@@ -6885,16 +6821,16 @@ void QQuickItem::setWidth(qreal w)
return;
d->widthValidFlag = true;
- if (d->width == w)
+ const qreal oldWidth = d->width;
+ if (oldWidth == w)
return;
- qreal oldWidth = d->width;
d->width = w;
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, w, d->height),
- QRectF(d->x, d->y, oldWidth, d->height));
+ const qreal x = d->x, y = d->y, h = d->height;
+ geometryChange(QRectF(x, y, w, h), QRectF(x, y, oldWidth, h));
}
void QQuickItem::resetWidth()
@@ -6908,14 +6844,7 @@ void QQuickItem::resetWidth()
void QQuickItemPrivate::implicitWidthChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::ImplicitWidth) {
- change.listener->itemImplicitWidthChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::ImplicitWidth, &QQuickItemChangeListener::itemImplicitWidthChanged, q);
emit q->implicitWidthChanged();
}
@@ -6941,7 +6870,14 @@ QBindable<qreal> QQuickItem::bindableWidth()
\qmlproperty real QtQuick::Item::implicitWidth
\qmlproperty real QtQuick::Item::implicitHeight
- Defines the natural width or height of the Item if no \l width or \l height is specified.
+ Defines the preferred width or height of the Item.
+
+ If \l width or \l height is not specified, an item's effective size will be
+ determined by its \l implicitWidth or \l implicitHeight.
+
+ However, if an item is the child of a \l {Qt Quick Layouts}{layout}, the
+ layout will determine the item's preferred size using its implicit size.
+ In such a scenario, the explicit \l width or \l height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent
implicit size which cannot be overridden, for example, \l [QML] Image and \l [QML] Text.
@@ -6975,7 +6911,14 @@ QBindable<qreal> QQuickItem::bindableWidth()
\property QQuickItem::implicitWidth
\property QQuickItem::implicitHeight
- Defines the natural width or height of the Item if no \l width or \l height is specified.
+ Defines the preferred width or height of the Item.
+
+ If \l width or \l height is not specified, an item's effective size will be
+ determined by its \l implicitWidth or \l implicitHeight.
+
+ However, if an item is the child of a \l {Qt Quick Layouts}{layout}, the
+ layout will determine the item's preferred size using its implicit size.
+ In such a scenario, the explicit \l width or \l height will be ignored.
The default implicit size for most items is 0x0, however some items have an inherent
implicit size which cannot be overridden, for example, \l [QML] Image and \l [QML] Text.
@@ -7019,19 +6962,18 @@ void QQuickItem::setImplicitWidth(qreal w)
changed = false;
}
- qreal oldWidth = d->width.valueBypassingBindings();
+ const qreal oldWidth = d->width.valueBypassingBindings();
Q_ASSERT(!d->width.hasBinding() || QQmlPropertyBinding::isUndefined(d->width.binding()));
// we need to keep the binding if its undefined (therefore we can't use operator=/setValue)
d->width.setValueBypassingBindings(w);
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
- qreal width = w;
- qreal height = d->height.valueBypassingBindings();
- geometryChange(QRectF(x, y, width, height),
- QRectF(x, y, oldWidth, height));
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
+ const qreal width = w;
+ const qreal height = d->height.valueBypassingBindings();
+ geometryChange(QRectF(x, y, width, height), QRectF(x, y, oldWidth, height));
if (changed)
d->implicitWidthChanged();
@@ -7085,16 +7027,16 @@ void QQuickItem::setHeight(qreal h)
return;
d->heightValidFlag = true;
- if (d->height == h)
+ const qreal oldHeight = d->height;
+ if (oldHeight == h)
return;
- qreal oldHeight = d->height;
d->height = h;
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, d->width, h),
- QRectF(d->x, d->y, d->width, oldHeight));
+ const qreal x = d->x, y = d->y, w = d->width;
+ geometryChange(QRectF(x, y, w, h), QRectF(x, y, w, oldHeight));
}
void QQuickItem::resetHeight()
@@ -7111,14 +7053,7 @@ void QQuickItem::resetHeight()
void QQuickItemPrivate::implicitHeightChanged()
{
Q_Q(QQuickItem);
- if (!changeListeners.isEmpty()) {
- const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
- for (const QQuickItemPrivate::ChangeListener &change : listeners) {
- if (change.types & QQuickItemPrivate::ImplicitHeight) {
- change.listener->itemImplicitHeightChanged(q);
- }
- }
- }
+ notifyChangeListeners(QQuickItemPrivate::ImplicitHeight, &QQuickItemChangeListener::itemImplicitHeightChanged, q);
emit q->implicitHeightChanged();
}
@@ -7151,17 +7086,17 @@ void QQuickItem::setImplicitHeight(qreal h)
changed = false;
}
- qreal oldHeight = d->height.valueBypassingBindings();
+ const qreal oldHeight = d->height.valueBypassingBindings();
Q_ASSERT(!d->height.hasBinding() || QQmlPropertyBinding::isUndefined(d->height.binding()));
// we need to keep the binding if its undefined (therefore we can't use operator=/setValue)
d->height.setValueBypassingBindings(h);
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
- qreal width = d->width.valueBypassingBindings();
- qreal height = d->height.valueBypassingBindings();
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
+ const qreal width = d->width.valueBypassingBindings();
+ const qreal height = d->height.valueBypassingBindings();
geometryChange(QRectF(x, y, width, height),
QRectF(x, y, width, oldHeight));
@@ -7200,8 +7135,8 @@ void QQuickItem::setImplicitSize(qreal w, qreal h)
if (wDone && hDone)
return;
- qreal oldWidth = width;
- qreal oldHeight = height;
+ const qreal oldWidth = width;
+ const qreal oldHeight = height;
if (!wDone) {
width = w;
d->width = w;
@@ -7213,8 +7148,8 @@ void QQuickItem::setImplicitSize(qreal w, qreal h)
d->dirty(QQuickItemPrivate::Size);
- qreal x = d->x.valueBypassingBindings();
- qreal y = d->y.valueBypassingBindings();
+ const qreal x = d->x.valueBypassingBindings();
+ const qreal y = d->y.valueBypassingBindings();
geometryChange(QRectF(x, y, width, height),
QRectF(x, y, oldWidth, oldHeight));
@@ -7267,15 +7202,15 @@ void QQuickItem::setSize(const QSizeF &size)
if (d->width == size.width() && d->height == size.height())
return;
- qreal oldHeight = d->height;
- qreal oldWidth = d->width;
+ const qreal oldHeight = d->height;
+ const qreal oldWidth = d->width;
d->height.setValueBypassingBindings(size.height());
d->width.setValueBypassingBindings(size.width());
d->dirty(QQuickItemPrivate::Size);
- geometryChange(QRectF(d->x, d->y, d->width, d->height),
- QRectF(d->x, d->y, oldWidth, oldHeight));
+ const qreal x = d->x, y = d->y;
+ geometryChange(QRectF(x, y, size.width(), size.height()), QRectF(x, y, oldWidth, oldHeight));
}
/*!
@@ -7456,20 +7391,19 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
if (d->focus == focus)
return;
+ bool notifyListeners = false;
if (d->window || d->parentItem) {
// Need to find our nearest focus scope
QQuickItem *scope = parentItem();
while (scope && !scope->isFocusScope() && scope->parentItem())
scope = scope->parentItem();
if (d->window) {
- if (reason != Qt::PopupFocusReason) {
- auto da = d->deliveryAgentPrivate();
- Q_ASSERT(da);
- if (focus)
- da->setFocusInScope(scope, this, reason);
- else
- da->clearFocusInScope(scope, this, reason);
- }
+ auto da = d->deliveryAgentPrivate();
+ Q_ASSERT(da);
+ if (focus)
+ da->setFocusInScope(scope, this, reason);
+ else
+ da->clearFocusInScope(scope, this, reason);
} else {
// do the focus changes from setFocusInScope/clearFocusInScope that are
// unrelated to a window
@@ -7487,9 +7421,10 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
d->focus = focus;
changed << this;
+ notifyListeners = true;
emit focusChanged(focus);
- QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
}
} else {
QVarLengthArray<QQuickItem *, 20> changed;
@@ -7502,10 +7437,13 @@ void QQuickItem::setFocus(bool focus, Qt::FocusReason reason)
d->focus = focus;
changed << this;
+ notifyListeners = true;
emit focusChanged(focus);
- QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
}
+ if (notifyListeners)
+ d->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, this, reason);
}
/*!
@@ -7635,7 +7573,7 @@ bool QQuickItem::isUnderMouse() const
return false;
QPointF cursorPos = QGuiApplicationPrivate::lastCursorPosition;
- return contains(mapFromScene(d->window->mapFromGlobal(cursorPos.toPoint())));
+ return contains(mapFromScene(d->window->mapFromGlobal(cursorPos)));
}
/*!
@@ -7802,7 +7740,7 @@ void QQuickItem::setCursor(const QCursor &cursor)
if (d->window) {
QWindow *renderWindow = QQuickRenderControl::renderWindowFor(d->window);
QWindow *window = renderWindow ? renderWindow : d->window;
- QPointF pos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ QPointF pos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition);
if (contains(mapFromScene(pos)))
updateCursorPos = pos;
}
@@ -7831,7 +7769,7 @@ void QQuickItem::unsetCursor()
if (d->window) {
QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(d->window);
if (windowPrivate->cursorItem == this) {
- QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ QPointF pos = d->window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition);
windowPrivate->updateCursor(pos);
}
}
@@ -8065,7 +8003,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
Returns \c true if this item contains \a point, which is in local coordinates;
returns \c false otherwise. This is the same check that is used for
hit-testing a QEventPoint during event delivery, and is affected by
- containmentMask() if it is set.
+ \l containmentMask if it is set.
*/
/*!
Returns \c true if this item contains \a point, which is in local coordinates;
@@ -8073,7 +8011,7 @@ void QQuickItem::setKeepTouchGrab(bool keep)
This function can be overridden in order to handle point collisions in items
with custom shapes. The default implementation checks whether the point is inside
- containmentMask() if it is set, or inside the bounding box otherwise.
+ \l containmentMask() if it is set, or inside the bounding box otherwise.
\note This method is used for hit-testing each QEventPoint during event
delivery, so the implementation should be kept as lightweight as possible.
@@ -8102,10 +8040,10 @@ bool QQuickItem::contains(const QPointF &point) const
\qmlproperty QObject* QtQuick::Item::containmentMask
\since 5.11
This property holds an optional mask for the Item to be used in the
- QtQuick::Item::contains() method. Its main use is currently to determine
+ \l contains() method. Its main use is currently to determine
whether a \l {QPointerEvent}{pointer event} has landed into the item or not.
- By default the \l contains method will return true for any point
+ By default the \c contains() method will return true for any point
within the Item's bounding box. \c containmentMask allows for
more fine-grained control. For example, if a custom C++
QQuickItem subclass with a specialized contains() method
@@ -8670,7 +8608,7 @@ QSGTextureProvider *QQuickItem::textureProvider() const
}
\endcode
- \sa Window::palette, Popup::palette, ColorGroup, Palette
+ \sa Window::palette, Popup::palette, ColorGroup, Palette, SystemPalette
*/
/*!
diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h
index 6a3a5db921..fcaedfb50d 100644
--- a/src/quick/items/qquickitem.h
+++ b/src/quick/items/qquickitem.h
@@ -472,6 +472,7 @@ private:
friend class QSGRenderer;
friend class QAccessibleQuickItem;
friend class QQuickAccessibleAttached;
+ friend class QQuickAnchorChanges;
Q_DISABLE_COPY(QQuickItem)
Q_DECLARE_PRIVATE(QQuickItem)
};
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index d8a7c1dfdc..4406e191cb 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -331,6 +331,8 @@ public:
ImplicitWidth = 0x100,
ImplicitHeight = 0x200,
Enabled = 0x400,
+ Focus = 0x800,
+ AllChanges = 0xFFFFFFFF
};
Q_DECLARE_FLAGS(ChangeTypes, ChangeType)
@@ -358,6 +360,32 @@ public:
QQuickGeometryChange gTypes; //NOTE: not used for ==
};
+ // call QQuickItemChangeListener PMF
+ template <typename Fn, typename ...Args>
+ void notifyChangeListeners(QQuickItemPrivate::ChangeTypes changeTypes, Fn &&function, Args &&...args)
+ {
+ if (changeListeners.isEmpty())
+ return;
+
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ if (change.types & changeTypes)
+ (change.listener->*function)(args...);
+ }
+ }
+ // call functor
+ template <typename Fn>
+ void notifyChangeListeners(QQuickItemPrivate::ChangeTypes changeTypes, Fn &&function) {
+ if (changeListeners.isEmpty())
+ return;
+
+ const auto listeners = changeListeners; // NOTE: intentional copy (QTBUG-54732)
+ for (const QQuickItemPrivate::ChangeListener &change : listeners) {
+ if (change.types & changeTypes)
+ function(change);
+ }
+ }
+
struct ExtraData {
ExtraData();
diff --git a/src/quick/items/qquickitemchangelistener_p.h b/src/quick/items/qquickitemchangelistener_p.h
index 31d06c9983..91e2d69cc0 100644
--- a/src/quick/items/qquickitemchangelistener_p.h
+++ b/src/quick/items/qquickitemchangelistener_p.h
@@ -134,6 +134,7 @@ public:
virtual void itemRotationChanged(QQuickItem *) {}
virtual void itemImplicitWidthChanged(QQuickItem *) {}
virtual void itemImplicitHeightChanged(QQuickItem *) {}
+ virtual void itemFocusChanged(QQuickItem *, Qt::FocusReason /* reason */) {}
virtual QQuickAnchorsPrivate *anchorPrivate() { return nullptr; }
};
diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h
index a055c0638b..e800c71377 100644
--- a/src/quick/items/qquickitemgrabresult.h
+++ b/src/quick/items/qquickitemgrabresult.h
@@ -75,7 +75,7 @@ public:
#endif
#endif
Q_INVOKABLE bool saveToFile(const QString &fileName) const;
- Q_INVOKABLE bool saveToFile(const QUrl &fileName) const;
+ Q_REVISION(6, 2) Q_INVOKABLE bool saveToFile(const QUrl &fileName) const;
protected:
bool event(QEvent *) override;
diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp
index 5201f6fd72..fbffde1c48 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -125,6 +125,8 @@ QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcTransient)
QT_END_NAMESPACE
+#include "moc_qquickitemsmodule_p.cpp"
+
static QQmlPrivate::AutoParentResult qquickitem_autoParent(QObject *obj, QObject *parent)
{
// When setting a parent (especially during dynamic object creation) in QML,
@@ -194,4 +196,138 @@ void QQuickItemsModule::defineModule()
qt_quickitems_defineModule();
}
+/*!
+ \qmltype PointerEvent
+ \instantiates QPointerEvent
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointerEvent.
+
+ PointerEvent is the QML name of the QPointerEvent class.
+*/
+
+/*!
+ \qmltype PointerDevice
+ \instantiates QPointingDevice
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDevice.
+
+ PointerDevice is the QML name of the QPointingDevice class.
+ It has the same properties and enums as \l QPointingDevice.
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::deviceType
+
+ This property tells the type of device that generated a PointerEvent.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Mouse A mouse.
+ \value PointerDevice.TouchScreen A touchscreen.
+ \value PointerDevice.TouchPad A touchpad or trackpad.
+ \value PointerDevice.Stylus A stylus on a graphics tablet.
+ \value PointerDevice.Airbrush An airbrush on a graphics tablet.
+ \value PointerDevice.Puck A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QInputDevice::DeviceType, PointerDeviceHandler::acceptedDevices
+*/
+
+/*!
+ \qmlproperty enumeration PointerDevice::pointerType
+
+ This property tells what is interacting with the PointerDevice.
+
+ There is some redundancy between this property and \l deviceType.
+ For example, if a touchscreen is used, then \c deviceType is
+ \c TouchScreen and \c pointerType is \c Finger. But on a graphics
+ tablet, it's often possible for both ends of the stylus to be used,
+ and programs need to distinguish them.
+ \l PointerDeviceHandler::acceptedDevices and
+ \l PointerDeviceHandler::acceptedPointerTypes can be used in combination
+ to filter the subset of events that a particular handler should react to.
+
+ Valid values are:
+
+ \value PointerDevice.Unknown The device cannot be identified.
+ \value PointerDevice.Generic A mouse or a device that emulates a mouse.
+ \value PointerDevice.Finger A finger on a touchscreen.
+ \value PointerDevice.Pen A stylus on a graphics tablet.
+ \value PointerDevice.Eraser An eraser on a graphics tablet.
+ \value PointerDevice.Cursor A digitizer with crosshairs, on a graphics tablet.
+
+ \sa QPointingDevice::PointerType, PointerDeviceHandler::acceptedPointerTypes
+*/
+
+/*!
+ \qmlproperty int PointerDevice::maximumPoints
+
+ This property tells the maximum number of simultaneous touch points
+ (fingers) that can be detected.
+*/
+
+/*!
+ \qmlproperty int PointerDevice::buttonCount
+
+ This property tells the maximum number of on-device buttons that can be
+ detected.
+*/
+
+/*!
+ \qmltype pointingDeviceUniqueId
+ \instantiates QPointingDeviceUniqueId
+ \inqmlmodule QtQuick
+ \brief QML equivalent for \l QPointingDeviceUniqueId.
+
+ pointingDeviceUniqueId is the QML name of the QPointingDeviceUniqueId class.
+*/
+
+/*!
+ \qmlproperty qint64 pointingDeviceUniqueId::numericId
+
+ This property gives the numeric ID of the \l PointerDevice, if available;
+ otherwise it is \c -1.
+*/
+
+/*!
+ \qmlproperty pointingDeviceUniqueId PointerDevice::uniqueId
+
+ This property may provide a unique ID for the device, if available. For
+ example, a graphics tablet stylus device may have a unique serial number.
+
+ \sa eventPoint, QEventPoint::uniqueId()
+*/
+
+/*!
+ \qmlsignal PointerDevice::grabChanged(QtObject grabber, enumeration transition, PointerEvent event, eventPoint point)
+
+ This signal is emitted when the \a grabber object gains or loses an
+ exclusive or passive grab of \a point during delivery of \a event.
+ The \a transition tells what happened, from the perspective of the
+ \c grabber object, which may be either an \l Item or an
+ \l {Qt Quick Input Handlers}{Input Handler}.
+
+ Valid values for \a transition are:
+
+ \value GrabExclusive
+ The \a grabber has taken primary responsibility for handling the \a point.
+ \value UngrabExclusive
+ The \a grabber has given up its previous exclusive grab.
+ \value CancelGrabExclusive
+ The exclusive grab of \a grabber has been taken over or cancelled.
+ \value GrabPassive
+ The \a grabber has acquired a passive grab, to monitor the \a point.
+ \value UngrabPassive
+ The \a grabber has given up its previous passive grab.
+ \value CancelGrabPassive
+ The previous passive grab has terminated abnormally.
+
+ \note A grab transition from one object to another results in two signals,
+ to notify that one object has lost its grab, and to notify that there is
+ another grabber. In other cases, when transitioning to or from a non-grabbing
+ state, only one signal is emitted.
+
+ \sa QPointerEvent::setExclusiveGrabber(), QPointerEvent::addPassiveGrabber(), QPointerEvent::removePassiveGrabber()
+*/
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp
index f1336a91f6..faa03fa9ae 100644
--- a/src/quick/items/qquickitemview.cpp
+++ b/src/quick/items/qquickitemview.cpp
@@ -57,8 +57,6 @@ FxViewItem::FxViewItem(QQuickItem *i, QQuickItemView *v, bool own, QQuickItemVie
, view(v)
, attached(attached)
{
- if (attached) // can be null for default components (see createComponentItem)
- attached->setView(view);
}
QQuickItemViewChangeSet::QQuickItemViewChangeSet()
@@ -290,8 +288,6 @@ void QQuickItemView::setDelegate(QQmlComponent *delegate)
if (QQmlDelegateModel *dataModel = qobject_cast<QQmlDelegateModel*>(d->model)) {
int oldCount = dataModel->count();
dataModel->setDelegate(delegate);
- if (isComponentComplete())
- d->applyDelegateChange();
if (oldCount != dataModel->count())
emit countChanged();
}
@@ -1785,7 +1781,7 @@ void QQuickItemViewPrivate::refill(qreal from, qreal to)
do {
bufferPause.stop();
- if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges()) {
+ if (currentChanges.hasPendingChanges() || bufferedChanges.hasPendingChanges() || currentChanges.active) {
currentChanges.reset();
bufferedChanges.reset();
releaseVisibleItems(reusableFlag);
@@ -1972,6 +1968,9 @@ void QQuickItemViewPrivate::layout()
transitioner->resetTargetLists();
}
+ if (!currentItem)
+ updateCurrent(currentIndex);
+
runDelayedRemoveTransition = false;
inLayout = false;
}
@@ -2504,12 +2503,29 @@ QQuickItem *QQuickItemViewPrivate::createComponentItem(QQmlComponent *component,
item->setZ(zValue);
QQml_setParent_noEvent(item, q->contentItem());
item->setParentItem(q->contentItem());
+
+ initializeComponentItem(item);
}
if (component)
component->completeCreate();
return item;
}
+/*!
+ \internal
+
+ Allows derived classes to do any initialization required for \a item
+ before completeCreate() is called on it. For example, any attached
+ properties required by the item can be set.
+
+ This is similar to initItem(), but as that has logic specific to
+ delegate items, we use a separate function for non-delegates.
+*/
+void QQuickItemViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ Q_UNUSED(item);
+}
+
void QQuickItemViewPrivate::updateTrackedItem()
{
Q_Q(QQuickItemView);
diff --git a/src/quick/items/qquickitemview_p_p.h b/src/quick/items/qquickitemview_p_p.h
index 0bc2a6b768..36c36f43e8 100644
--- a/src/quick/items/qquickitemview_p_p.h
+++ b/src/quick/items/qquickitemview_p_p.h
@@ -76,7 +76,7 @@ public:
};
-class QQuickItemViewChangeSet
+class Q_AUTOTEST_EXPORT QQuickItemViewChangeSet
{
public:
QQuickItemViewChangeSet();
@@ -100,7 +100,7 @@ public:
};
-class Q_AUTOTEST_EXPORT QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener
+class Q_QUICK_AUTOTEST_EXPORT QQuickItemViewPrivate : public QQuickFlickablePrivate, public QQuickItemViewTransitionChangeListener, public QAnimationJobChangeListener
{
Q_DECLARE_PUBLIC(QQuickItemView)
public:
@@ -178,6 +178,7 @@ public:
QQuickItem *createHighlightItem() const;
QQuickItem *createComponentItem(QQmlComponent *component, qreal zValue, bool createDefault = false) const;
+ virtual void initializeComponentItem(QQuickItem *) const;
void updateCurrent(int modelIndex);
void updateTrackedItem();
diff --git a/src/quick/items/qquickitemviewtransition.cpp b/src/quick/items/qquickitemviewtransition.cpp
index b7649c9952..6b03d6c16b 100644
--- a/src/quick/items/qquickitemviewtransition.cpp
+++ b/src/quick/items/qquickitemviewtransition.cpp
@@ -500,6 +500,37 @@ void QQuickItemViewTransitionableItem::startTransition(QQuickItemViewTransitione
clearCurrentScheduledTransition();
}
+void QQuickItemViewTransitionableItem::completeTransition(QQuickTransition *quickTransition)
+{
+ if (nextTransitionType == QQuickItemViewTransitioner::NoTransition)
+ return;
+
+ if (!prepared) {
+ qWarning("QQuickViewItem::prepareTransition() not called!");
+ return;
+ }
+
+ if (!item) {
+ qWarning("No target for transition!");
+ return;
+ }
+
+ if (!transition || transition->m_type != nextTransitionType || transition->m_isTarget != isTransitionTarget) {
+ if (transition)
+ RETURN_IF_DELETED(transition->cancel());
+ delete transition;
+ transition = new QQuickItemViewTransitionJob;
+ }
+
+ QQuickStateOperation::ActionList actions; // not used
+ QList<QQmlProperty> after; // not used
+ QScopedPointer<QQuickTransitionInstance> instance(
+ quickTransition->prepare(actions, after, transition, item));
+ RETURN_IF_DELETED(instance->complete());
+
+ clearCurrentScheduledTransition();
+}
+
void QQuickItemViewTransitionableItem::setNextTransition(QQuickItemViewTransitioner::TransitionType type, bool isTargetItem)
{
// Don't reset nextTransitionToSet - once it is set, it cannot be changed
@@ -549,13 +580,15 @@ void QQuickItemViewTransitionableItem::stopTransition()
{
if (transition)
RETURN_IF_DELETED(transition->cancel());
+ delete transition;
+ transition = nullptr;
clearCurrentScheduledTransition();
resetNextTransitionPos();
}
QQuickViewTransitionAttached::QQuickViewTransitionAttached(QObject *parent)
- : QObject(parent), m_item(nullptr), m_index(-1)
+ : QObject(parent), m_index(-1)
{
}
/*!
diff --git a/src/quick/items/qquickitemviewtransition_p.h b/src/quick/items/qquickitemviewtransition_p.h
index 43858db688..253f3c6c70 100644
--- a/src/quick/items/qquickitemviewtransition_p.h
+++ b/src/quick/items/qquickitemviewtransition_p.h
@@ -157,6 +157,7 @@ public:
bool prepareTransition(QQuickItemViewTransitioner *transitioner, int index, const QRectF &viewBounds);
void startTransition(QQuickItemViewTransitioner *transitioner, int index);
+ void completeTransition(QQuickTransition *quickTransition);
SelfDeletable m_selfDeletable;
QPointF nextTransitionTo;
@@ -225,7 +226,7 @@ private:
QList<int> m_targetIndexes;
QList<QObject *> m_targetItems;
- QQuickItem *m_item;
+ QPointer<QQuickItem> m_item;
int m_index;
};
diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp
index b954f1b107..58f031a9eb 100644
--- a/src/quick/items/qquicklistview.cpp
+++ b/src/quick/items/qquicklistview.cpp
@@ -130,6 +130,8 @@ public:
bool hasStickyHeader() const override;
bool hasStickyFooter() const override;
+ void initializeComponentItem(QQuickItem *item) const override;
+
void changedVisibleIndex(int newIndex) override;
void initializeCurrentItem() override;
@@ -1573,6 +1575,14 @@ bool QQuickListViewPrivate::hasStickyFooter() const
return footer && footerPositioning != QQuickListView::InlineFooter;
}
+void QQuickListViewPrivate::initializeComponentItem(QQuickItem *item) const
+{
+ QQuickListViewAttached *attached = static_cast<QQuickListViewAttached *>(
+ qmlAttachedPropertiesObject<QQuickListView>(item));
+ if (attached) // can be null for default components (see createComponentItem)
+ attached->setView(const_cast<QQuickListView*>(q_func()));
+}
+
void QQuickListViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change,
const QRectF &oldGeometry)
{
@@ -1642,6 +1652,10 @@ void QQuickListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal maxExte
return;
}
+ // update footer if all visible items have been removed
+ if (visibleItems.count() == 0)
+ updateFooter();
+
correctFlick = false;
fixupMode = moveReason == Mouse ? fixupMode : Immediate;
bool strictHighlightRange = haveHighlightRange && highlightRange == QQuickListView::StrictlyEnforceRange;
@@ -2727,7 +2741,8 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation)
\c section.delegate holds the delegate component for each section. The
default \l {QQuickItem::z}{stacking order} of section delegate instances
- is \c 2.
+ is \c 2. If you declare a \c required property named "section" in it,
+ that property will contain the section's title.
\c section.labelPositioning determines whether the current and/or
next section labels stick to the start/end of the view, and whether
@@ -3743,8 +3758,10 @@ bool QQuickListViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch
item = createItem(it.index, QQmlIncubator::Synchronous);
if (!item)
return false;
- if (it.removedAtIndex)
+ if (it.removedAtIndex) {
+ releaseItem(item, reusableFlag);
continue;
+ }
visibleItems.insert(index, item);
if (index == 0)
diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp
index 4cd93ca1f0..1f5c55cffe 100644
--- a/src/quick/items/qquickloader.cpp
+++ b/src/quick/items/qquickloader.cpp
@@ -736,6 +736,9 @@ void QQuickLoaderPrivate::_q_sourceLoaded()
return;
}
+ if (!active)
+ return;
+
QQmlContext *creationContext = component->creationContext();
if (!creationContext) creationContext = qmlContext(q);
itemContext = new QQmlContext(creationContext);
@@ -801,7 +804,7 @@ void QQuickLoader::componentComplete()
{
Q_D(QQuickLoader);
QQuickItem::componentComplete();
- if (active()) {
+ if (active() && (status() != Ready)) {
if (d->loadingFromSource)
d->createComponent();
d->load();
@@ -939,7 +942,7 @@ void QQuickLoaderPrivate::_q_updateSize(bool loaderGeometryChanged)
}
/*!
- \qmlproperty object QtQuick::Loader::item
+ \qmlproperty QtObject QtQuick::Loader::item
This property holds the top-level object that is currently loaded.
Since \c {QtQuick 2.0}, Loader can load any object type.
@@ -1038,9 +1041,15 @@ void QQuickLoaderPrivate::createComponent()
const QQmlComponent::CompilationMode mode = asynchronous
? QQmlComponent::Asynchronous
: QQmlComponent::PreferSynchronous;
- QQmlContext *context = qmlContext(q);
- component.setObject(new QQmlComponent(
- context->engine(), context->resolvedUrl(source), mode, q), q);
+ if (QQmlContext *context = qmlContext(q)) {
+ if (QQmlEngine *engine = context->engine()) {
+ component.setObject(new QQmlComponent(
+ engine, context->resolvedUrl(source), mode, q), q);
+ return;
+ }
+ }
+
+ qmlWarning(q) << "createComponent: Cannot find a QML engine.";
}
#include <moc_qquickloader_p.cpp>
diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp
index 281860fa6e..4977ddf44f 100644
--- a/src/quick/items/qquickmousearea.cpp
+++ b/src/quick/items/qquickmousearea.cpp
@@ -808,7 +808,8 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event)
QQuickWindow *w = window();
if (w && w->mouseGrabberItem() == this)
ungrabMouse();
- setKeepMouseGrab(false);
+ if (!d->preventStealing)
+ setKeepMouseGrab(false);
}
}
d->doubleClick = false;
@@ -827,7 +828,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
emit this->doubleClicked(&me);
if (!me.isAccepted())
d->propagate(&me, QQuickMouseAreaPrivate::DoubleClick);
- d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
+ if (d->pressed)
+ d->doubleClick = d->isDoubleClickConnected() || me.isAccepted();
}
QQuickItem::mouseDoubleClickEvent(event);
}
@@ -849,14 +851,8 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
me.setPosition(d->lastPos);
}
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
@@ -876,14 +872,8 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
emit positionChanged(&me);
}
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
@@ -894,14 +884,8 @@ void QQuickMouseArea::hoverLeaveEvent(QHoverEvent *event)
else
setHovered(false);
- if (auto parentMouseArea = qobject_cast<QQuickMouseArea *>(parentItem())) {
- if (parentMouseArea->acceptHoverEvents()) {
- // Special legacy case: if our parent is another MouseArea, and we're
- // hovered, the parent MouseArea should be hovered too. We achieve this
- // by simply ignoring the event to not block propagation.
- event->ignore();
- }
- }
+ // A MouseArea should not block hover events
+ event->ignore();
}
#if QT_CONFIG(wheelevent)
diff --git a/src/quick/items/qquickmultipointtoucharea.cpp b/src/quick/items/qquickmultipointtoucharea.cpp
index 642b5ca047..8687de8f43 100644
--- a/src/quick/items/qquickmultipointtoucharea.cpp
+++ b/src/quick/items/qquickmultipointtoucharea.cpp
@@ -40,11 +40,11 @@
#include "qquickmultipointtoucharea_p.h"
#include <QtQuick/qquickwindow.h>
#include <private/qsgadaptationlayer_p.h>
-#include <private/qevent_p.h>
#include <private/qquickitem_p.h>
#include <private/qquickwindow_p.h>
#include <private/qguiapplication_p.h>
#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qpointingdevice_p.h>
#include <QEvent>
#include <QMouseEvent>
@@ -570,7 +570,7 @@ void QQuickMultiPointTouchArea::grabGesture(QPointingDevice *dev)
setKeepTouchGrab(true);
}
-void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
+void QQuickMultiPointTouchArea::updateTouchData(QEvent *event, RemapEventPoints remap)
{
bool ended = false;
bool moved = false;
@@ -578,6 +578,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
clearTouchLists();
QList<QEventPoint> touchPoints;
+ bool touchPointsFromEvent = false;
QPointingDevice *dev = nullptr;
switch (event->type()) {
@@ -586,6 +587,7 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
case QEvent::TouchEnd: {
QTouchEvent* te = static_cast<QTouchEvent*>(event);
touchPoints = te->points();
+ touchPointsFromEvent = true;
dev = const_cast<QPointingDevice *>(te->pointingDevice());
break;
}
@@ -630,6 +632,8 @@ void QQuickMultiPointTouchArea::updateTouchData(QEvent *event)
}
if (numTouchPoints >= _minimumTouchPoints && numTouchPoints <= _maximumTouchPoints) {
for (QEventPoint &p : touchPoints) {
+ if (touchPointsFromEvent && remap == RemapEventPoints::ToLocal)
+ QMutableEventPoint::from(p).setPosition(mapFromScene(p.scenePosition()));
QEventPoint::State touchPointState = p.state();
int id = p.id();
if (touchPointState & QEventPoint::State::Released) {
@@ -971,12 +975,12 @@ bool QQuickMultiPointTouchArea::childMouseEventFilter(QQuickItem *receiver, QEve
}
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
return _stealMouse;
case QEvent::TouchEnd: {
if (!shouldFilter(event))
return false;
- updateTouchData(event);
+ updateTouchData(event, RemapEventPoints::ToLocal);
ungrab(true);
}
break;
diff --git a/src/quick/items/qquickmultipointtoucharea_p.h b/src/quick/items/qquickmultipointtoucharea_p.h
index 66626e8610..e1f2c559ce 100644
--- a/src/quick/items/qquickmultipointtoucharea_p.h
+++ b/src/quick/items/qquickmultipointtoucharea_p.h
@@ -278,7 +278,8 @@ protected:
void updateTouchPoint(QQuickTouchPoint*, const QEventPoint*);
void updateTouchPoint(QQuickTouchPoint *dtp, const QMouseEvent *e);
- void updateTouchData(QEvent*);
+ enum class RemapEventPoints { No, ToLocal };
+ void updateTouchData(QEvent*, RemapEventPoints remap = RemapEventPoints::No);
bool sendMouseEvent(QMouseEvent *event);
bool shouldFilter(QEvent *event);
diff --git a/src/quick/items/qquickpainteditem.cpp b/src/quick/items/qquickpainteditem.cpp
index 2cf26142c8..c24a6cbfdd 100644
--- a/src/quick/items/qquickpainteditem.cpp
+++ b/src/quick/items/qquickpainteditem.cpp
@@ -83,6 +83,8 @@ public:
\note It important to understand the performance implications such items
can incur. See QQuickPaintedItem::RenderTarget and
QQuickPaintedItem::renderTarget.
+
+ \sa {Scene Graph - Painted Item}, {Writing QML Extensions with C++}
*/
/*!
diff --git a/src/quick/items/qquickpalette.cpp b/src/quick/items/qquickpalette.cpp
index a64b309426..5e95a92238 100644
--- a/src/quick/items/qquickpalette.cpp
+++ b/src/quick/items/qquickpalette.cpp
@@ -334,3 +334,5 @@ bool QQuickPalette::isValidColorGroup(QPalette::ColorGroup groupTag,
}
QT_END_NAMESPACE
+
+#include "moc_qquickpalette_p.cpp"
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp
index d862eba25b..f714b98309 100644
--- a/src/quick/items/qquickpathview.cpp
+++ b/src/quick/items/qquickpathview.cpp
@@ -49,7 +49,8 @@
#include <private/qqmlchangeset_p.h>
#include <QtQml/qqmlinfo.h>
-#include <QtGui/qevent.h>
+
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/qevent.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qstylehints.h>
@@ -145,7 +146,8 @@ QQuickItem *QQuickPathViewPrivate::getItem(int modelIndex, qreal z, bool async)
item->setParentItem(q);
requestedIndex = -1;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->addItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->addItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
}
inRequest = false;
return item;
@@ -198,11 +200,14 @@ void QQuickPathView::initItem(int index, QObject *object)
void QQuickPathViewPrivate::releaseItem(QQuickItem *item)
{
- if (!item || !model)
+ if (!item)
return;
qCDebug(lcItemViewDelegateLifecycle) << "release" << item;
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
- itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ itemPrivate->removeItemChangeListener(
+ this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed);
+ if (!model)
+ return;
QQmlInstanceModel::ReleaseFlags flags = model->release(item);
if (!flags) {
// item was not destroyed, and we no longer reference it.
diff --git a/src/quick/items/qquickpathview_p_p.h b/src/quick/items/qquickpathview_p_p.h
index 274086ea7c..b83cd95b95 100644
--- a/src/quick/items/qquickpathview_p_p.h
+++ b/src/quick/items/qquickpathview_p_p.h
@@ -88,6 +88,12 @@ public:
}
}
+ void itemDestroyed(QQuickItem *item) override
+ {
+ if (!items.removeOne(item))
+ itemCache.removeOne(item);
+ }
+
void scheduleLayout() {
Q_Q(QQuickPathView);
if (!layoutScheduled) {
diff --git a/src/quick/items/qquickpincharea.cpp b/src/quick/items/qquickpincharea.cpp
index ed8506b440..37458542d3 100644
--- a/src/quick/items/qquickpincharea.cpp
+++ b/src/quick/items/qquickpincharea.cpp
@@ -360,7 +360,7 @@ void QQuickPinchArea::touchEvent(QTouchEvent *event)
void QQuickPinchArea::clearPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
- qCDebug(lcPA, "clear: %lld touchpoints", d->touchPoints.count());
+ qCDebug(lcPA, "clear: %" PRIdQSIZETYPE " touchpoints", d->touchPoints.count());
d->touchPoints.clear();
if (d->inPinch) {
d->inPinch = false;
@@ -390,12 +390,13 @@ void QQuickPinchArea::clearPinch(QTouchEvent *event)
}
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::cancelPinch(QTouchEvent *event)
{
Q_D(QQuickPinchArea);
- qCDebug(lcPA, "cancel: %lld touchpoints", d->touchPoints.count());
+ qCDebug(lcPA, "cancel: %" PRIdQSIZETYPE " touchpoints", d->touchPoints.count());
d->touchPoints.clear();
if (d->inPinch) {
d->inPinch = false;
@@ -431,6 +432,7 @@ void QQuickPinchArea::cancelPinch(QTouchEvent *event)
event->setExclusiveGrabber(point, nullptr);
}
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
}
void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
@@ -440,6 +442,7 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
if (d->touchPoints.count() < 2) {
// A pinch gesture is not occurring, so stealing the grab is permitted.
setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
// During filtering, there's no need to hold a grab for one point,
// because filtering happens for every event anyway.
// But if we receive the event via direct delivery, and give up the grab,
@@ -463,6 +466,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
pe.setStartPoint2(mapFromScene(d->sceneStartPoint2));
pe.setPoint1(mapFromScene(d->lastPoint1));
pe.setPoint2(mapFromScene(d->lastPoint2));
+ setKeepTouchGrab(false);
+ setKeepMouseGrab(false);
emit pinchFinished(&pe);
d->pinchStartDist = 0;
d->pinchActivated = false;
@@ -499,6 +504,8 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
d->initPinch = true;
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
+ setKeepTouchGrab(true);
+ setKeepMouseGrab(true);
}
if (d->pinchActivated && !d->pinchRejected) {
const int dragThreshold = QGuiApplication::styleHints()->startDragDistance();
@@ -561,6 +568,9 @@ void QQuickPinchArea::updatePinch(QTouchEvent *event, bool filtering)
event->setExclusiveGrabber(touchPoint1, this);
event->setExclusiveGrabber(touchPoint2, this);
setKeepTouchGrab(true);
+ // So that PinchArea works in PathView, grab mouse events too.
+ // We should be able to remove these setKeepMouseGrab calls when QTBUG-105567 is fixed.
+ setKeepMouseGrab(true);
d->inPinch = true;
if (d->pinch && d->pinch->target()) {
auto targetParent = pinch()->target()->parentItem();
@@ -727,6 +737,8 @@ bool QQuickPinchArea::event(QEvent *event)
clearPinch(nullptr);
break;
case Qt::ZoomNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal scale = d->pinchLastScale * (1.0 + gesture->value());
QQuickPinchEvent pe(d->pinchStartCenter, scale, d->pinchLastAngle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -744,7 +756,10 @@ bool QQuickPinchArea::event(QEvent *event)
else
emit pinchStarted(&pe);
d->inPinch = true;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
case Qt::SmartZoomNativeGesture: {
if (gesture->value() > 0.0 && d->pinch && d->pinch->target()) {
@@ -768,6 +783,8 @@ bool QQuickPinchArea::event(QEvent *event)
emit smartZoom(&pe);
} break;
case Qt::RotateNativeGesture: {
+ if (d->pinchRejected)
+ break;
qreal angle = d->pinchLastAngle + gesture->value();
QQuickPinchEvent pe(d->pinchStartCenter, d->pinchLastScale, angle, 0.0);
pe.setStartCenter(d->pinchStartCenter);
@@ -786,7 +803,10 @@ bool QQuickPinchArea::event(QEvent *event)
emit pinchStarted(&pe);
d->inPinch = true;
d->pinchRotation = angle;
- updatePinchTarget();
+ if (pe.accepted())
+ updatePinchTarget();
+ else
+ d->pinchRejected = true;
} break;
default:
return QQuickItem::event(event);
diff --git a/src/quick/items/qquickpositioners.cpp b/src/quick/items/qquickpositioners.cpp
index a8d050527b..313143e881 100644
--- a/src/quick/items/qquickpositioners.cpp
+++ b/src/quick/items/qquickpositioners.cpp
@@ -1697,7 +1697,7 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
QQuickBasePositionerPrivate *d = static_cast<QQuickBasePositionerPrivate*>(QQuickBasePositionerPrivate::get(this));
int c = m_columns;
int r = m_rows;
- int numVisible = positionedItems.count();
+ const int numVisible = positionedItems.count();
if (m_columns <= 0 && m_rows <= 0) {
c = 4;
@@ -1714,6 +1714,10 @@ void QQuickGrid::doPositioning(QSizeF *contentSize)
return; //Nothing else to do
}
+ if (numVisible > r * c) {
+ qmlWarning(this) << "Grid contains more visible items (" << numVisible << ") than rows*columns (" << r * c << ")";
+ }
+
QList<qreal> maxColWidth;
QList<qreal> maxRowHeight;
int childIndex =0;
diff --git a/src/quick/items/qquickrectangle.cpp b/src/quick/items/qquickrectangle.cpp
index ce570a743c..52c830c14a 100644
--- a/src/quick/items/qquickrectangle.cpp
+++ b/src/quick/items/qquickrectangle.cpp
@@ -578,8 +578,13 @@ QSGNode *QQuickRectangle::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData
if (d->pen && d->pen->isValid()) {
rectangle->setPenColor(d->pen->color());
- rectangle->setPenWidth(d->pen->width());
- rectangle->setAligned(d->pen->pixelAligned());
+ qreal penWidth = d->pen->width();
+ if (d->pen->pixelAligned()) {
+ qreal dpr = window() ? window()->effectiveDevicePixelRatio() : 1.0;
+ penWidth = qRound(penWidth * dpr) / dpr; // Ensures integer width after dpr scaling
+ }
+ rectangle->setPenWidth(penWidth);
+ rectangle->setAligned(false); // width rounding already done, so the Node should not do it
} else {
rectangle->setPenWidth(0);
}
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index a660bd0ca3..2d48a39be8 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -181,6 +181,14 @@ QQuickRenderControl::QQuickRenderControl(QObject *parent)
}
/*!
+ \internal
+*/
+QQuickRenderControl::QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject * parent)
+ : QObject(dd, parent)
+{
+}
+
+/*!
Destroys the instance. Releases all scenegraph resources.
\sa invalidate()
@@ -214,7 +222,7 @@ void QQuickRenderControlPrivate::windowDestroyed()
QQuickWindowPrivate::get(window)->animationController.reset();
#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache(window);
#endif
window = nullptr;
}
@@ -322,6 +330,7 @@ bool QQuickRenderControl::initialize()
params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
params.maybeSurface = d->window;
renderContext->initialize(&params);
+ d->initialized = true;
} else {
qWarning("QRhi is only compatible with default adaptation");
return false;
@@ -528,7 +537,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
Reimplemented in subclasses to return the real window this render control
is rendering into.
- If \a offset in non-null, it is set to the offset of the control
+ If \a offset is non-null, it is set to the offset of the control
inside the window.
\note While not mandatory, reimplementing this function becomes essential for
@@ -540,7 +549,7 @@ void QQuickRenderControlPrivate::maybeUpdate()
/*!
Returns the real window that \a win is being rendered to, if any.
- If \a offset in non-null, it is set to the offset of the rendering
+ If \a offset is non-null, it is set to the offset of the rendering
inside its window.
*/
@@ -554,6 +563,14 @@ QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
return nullptr;
}
+bool QQuickRenderControlPrivate::isRenderWindowFor(QQuickWindow *quickWin, const QWindow *renderWin)
+{
+ QQuickRenderControl *rc = QQuickWindowPrivate::get(quickWin)->renderControl;
+ if (rc)
+ return QQuickRenderControlPrivate::get(rc)->isRenderWindow(renderWin);
+ return false;
+}
+
/*!
\return the QQuickWindow this QQuickRenderControl is associated with.
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
index 160aad73ab..3b1646c3f6 100644
--- a/src/quick/items/qquickrendercontrol.h
+++ b/src/quick/items/qquickrendercontrol.h
@@ -80,6 +80,9 @@ public:
QQuickWindow *window() const;
+protected:
+ QQuickRenderControl(QQuickRenderControlPrivate &dd, QObject * parent);
+
Q_SIGNALS:
void renderRequested();
void sceneChanged();
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index 00d9c909d0..8349153df0 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -71,6 +71,9 @@ public:
return renderControl->d_func();
}
+ static bool isRenderWindowFor(QQuickWindow *quickWin, const QWindow *renderWin);
+ virtual bool isRenderWindow(const QWindow *w) { Q_UNUSED(w); return false; }
+
static void cleanup();
void windowDestroyed();
diff --git a/src/quick/items/qquickscalegrid.cpp b/src/quick/items/qquickscalegrid.cpp
index c2288cf220..13b249d50f 100644
--- a/src/quick/items/qquickscalegrid.cpp
+++ b/src/quick/items/qquickscalegrid.cpp
@@ -217,3 +217,5 @@ QString QQuickGridScaledImage::pixmapUrl() const
}
QT_END_NAMESPACE
+
+#include "moc_qquickscalegrid_p_p.cpp"
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index caabd541b6..5c2f113fdc 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -1165,6 +1165,8 @@ QSGNode *QQuickShaderEffectImpl::handleUpdatePaintNode(QSGNode *oldNode, QQuickI
sd.fragment.shader = &m_shaders[Fragment];
sd.fragment.dirtyConstants = &m_dirtyConstants[Fragment];
sd.fragment.dirtyTextures = &m_dirtyTextures[Fragment];
+ sd.materialTypeCacheKey = m_item->window();
+
node->syncMaterial(&sd);
if (m_dirty & QSGShaderEffectNode::DirtyShaderMesh) {
@@ -1243,6 +1245,7 @@ bool QQuickShaderEffectImpl::updateUniformValue(const QByteArray &name, const QV
sd.fragment.shader = &m_shaders[Fragment];
sd.fragment.dirtyConstants = &dirtyConstants[Fragment];
sd.fragment.dirtyTextures = {};
+ sd.materialTypeCacheKey = m_item->window();
node->syncMaterial(&sd);
@@ -1384,7 +1387,7 @@ bool QQuickShaderEffectImpl::updateShader(Shader shaderType, const QUrl &fileUrl
// provided and monitored like with an application-provided shader.
QSGGuiThreadShaderEffectManager::ShaderInfo::Variable v;
v.name = QByteArrayLiteral("source");
- v.bindPoint = 0; // fake
+ v.bindPoint = 1; // fake, must match the default source bindPoint in qquickshadereffectnode.cpp
v.type = texturesSeparate ? QSGGuiThreadShaderEffectManager::ShaderInfo::Texture
: QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler;
m_shaders[shaderType].shaderInfo.variables.append(v);
@@ -1438,10 +1441,8 @@ void QQuickShaderEffectImpl::updateShaderVars(Shader shaderType)
const int varCount = m_shaders[shaderType].shaderInfo.variables.count();
m_shaders[shaderType].varData.resize(varCount);
- // Reuse signal mappers as much as possible since the mapping is based on
- // the index and shader type which are both constant.
- if (m_mappers[shaderType].count() < varCount)
- m_mappers[shaderType].resize(varCount);
+ // Recreate signal mappers when the shader has changed.
+ clearMappers(shaderType);
auto *engine = qmlEngine(m_item);
QQmlPropertyCache *propCache = engine ? QQmlData::ensurePropertyCache(engine, m_item) : nullptr;
@@ -1497,13 +1498,11 @@ void QQuickShaderEffectImpl::updateShaderVars(Shader shaderType)
if (pd->notifyIndex() == -1) {
qWarning("QQuickShaderEffect: property '%s' does not have notification method!", v.name.constData());
} else {
- auto *&mapper = m_mappers[shaderType][i];
- if (!mapper) {
- const int mappedId = indexToMappedId(shaderType, i);
- mapper = new QtPrivate::EffectSlotMapper([this, mappedId](){
- this->propertyChanged(mappedId);
- });
- }
+ const int mappedId = indexToMappedId(shaderType, i);
+ auto mapper = new QtPrivate::EffectSlotMapper([this, mappedId](){
+ this->propertyChanged(mappedId);
+ });
+ m_mappers[shaderType].append(mapper);
mapper->setSignalIndex(m_itemMetaObject->property(propIdx).notifySignal().methodIndex());
Q_ASSERT(m_item->metaObject() == m_itemMetaObject);
bool ok = QObjectPrivate::connectImpl(m_item, pd->notifyIndex(), m_item, nullptr, mapper,
diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp
index 4f61d61309..b298ed74da 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -344,7 +344,6 @@ void QQuickShaderEffectSource::setSourceItem(QQuickItem *item)
d->refFromEffectItem(m_hideSource);
d->addItemChangeListener(this, QQuickItemPrivate::Geometry);
connect(m_sourceItem, SIGNAL(destroyed(QObject*)), this, SLOT(sourceItemDestroyed(QObject*)));
- connect(m_sourceItem, SIGNAL(parentChanged(QQuickItem*)), this, SLOT(sourceItemParentChanged(QQuickItem*)));
} else {
qWarning("ShaderEffectSource: sourceItem and ShaderEffectSource must both be children of the same window.");
m_sourceItem = nullptr;
@@ -364,13 +363,6 @@ void QQuickShaderEffectSource::sourceItemDestroyed(QObject *item)
}
-void QQuickShaderEffectSource::sourceItemParentChanged(QQuickItem *parent)
-{
- if (!parent && m_texture)
- m_texture->setItem(0);
-}
-
-
/*!
\qmlproperty rect QtQuick::ShaderEffectSource::sourceRect
diff --git a/src/quick/items/qquickshadereffectsource_p.h b/src/quick/items/qquickshadereffectsource_p.h
index 921038e49a..fe419e5959 100644
--- a/src/quick/items/qquickshadereffectsource_p.h
+++ b/src/quick/items/qquickshadereffectsource_p.h
@@ -174,7 +174,6 @@ Q_SIGNALS:
private Q_SLOTS:
void sourceItemDestroyed(QObject *item);
void invalidateSceneGraph();
- void sourceItemParentChanged(QQuickItem *parent);
protected:
void releaseResources() override;
diff --git a/src/quick/items/qquickspriteengine.cpp b/src/quick/items/qquickspriteengine.cpp
index e35c766ab6..ddc43c10ed 100644
--- a/src/quick/items/qquickspriteengine.cpp
+++ b/src/quick/items/qquickspriteengine.cpp
@@ -352,6 +352,7 @@ void QQuickSpriteEngine::startAssemblingImage()
return;
m_loaded = false;
m_errorsPrinted = false;
+ m_sprites.clear();
//This could also trigger the start of the image loading in Sprites, however that currently happens in Sprite::setSource
diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp
index bfec619f80..d16f0d0883 100644
--- a/src/quick/items/qquickstateoperations.cpp
+++ b/src/quick/items/qquickstateoperations.cpp
@@ -359,8 +359,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << xa;
} else {
QQmlProperty property(d->target, QLatin1String("x"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->xString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->xString.value, d->target, qmlContext(this));
QQuickStateAction xa;
xa.property = property;
xa.toBinding = newBinding;
@@ -378,8 +377,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ya;
} else {
QQmlProperty property(d->target, QLatin1String("y"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->yString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->yString.value, d->target, qmlContext(this));
QQuickStateAction ya;
ya.property = property;
ya.toBinding = newBinding;
@@ -397,8 +395,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << sa;
} else {
QQmlProperty property(d->target, QLatin1String("scale"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->scaleString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->scaleString.value, d->target, qmlContext(this));
QQuickStateAction sa;
sa.property = property;
sa.toBinding = newBinding;
@@ -416,8 +413,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ra;
} else {
QQmlProperty property(d->target, QLatin1String("rotation"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->rotationString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->rotationString.value, d->target, qmlContext(this));
QQuickStateAction ra;
ra.property = property;
ra.toBinding = newBinding;
@@ -435,8 +431,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << wa;
} else {
QQmlProperty property(d->target, QLatin1String("width"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->widthString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->widthString, d->target, qmlContext(this));
QQuickStateAction wa;
wa.property = property;
wa.toBinding = newBinding;
@@ -454,8 +449,7 @@ QQuickStateOperation::ActionList QQuickParentChange::actions()
actions << ha;
} else {
QQmlProperty property(d->target, QLatin1String("height"));
- QQmlBinding *newBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, d->heightString.value, d->target, qmlContext(this));
- newBinding->setTarget(property);
+ auto newBinding = QQmlAnyBinding::createFromScriptString(property, d->heightString, d->target, qmlContext(this));
QQuickStateAction ha;
ha.property = property;
ha.toBinding = newBinding;
@@ -492,11 +486,13 @@ void QQuickParentChangePrivate::reverseRewindHelper(const std::unique_ptr<QQuick
{
if (!target || !snapshot)
return;
- target->setX(snapshot->x);
- target->setY(snapshot->y);
+
+ // leave existing bindings alive; new bindings are applied in applyBindings
+ // setPosition and setSize update the geometry without invalidating bindings
+ target->setPosition(QPointF(snapshot->x, snapshot->y));
+ target->setSize(QSizeF(snapshot->width, snapshot->height));
+
target->setScale(snapshot->scale);
- target->setWidth(snapshot->width);
- target->setHeight(snapshot->height);
target->setRotation(snapshot->rotation);
target->setParentItem(snapshot->parent);
if (snapshot->stackBefore)
@@ -573,7 +569,7 @@ void QQuickParentChange::rewind()
The AnchorChanges type is used to modify the anchors of an item in a \l State.
AnchorChanges cannot be used to modify the margins on an item. For this, use
- PropertyChanges intead.
+ PropertyChanges instead.
In the following example we change the top and bottom anchors of an item
using AnchorChanges, and the top and bottom anchor margins using
@@ -1106,6 +1102,7 @@ void QQuickAnchorChanges::reverse()
QQuickAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QQuickAnchors::Horizontal_Mask;
QQuickAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QQuickAnchors::Horizontal_Mask;
+ const QRectF oldGeometry(d->target->position(), d->target->size());
bool stateSetWidth = (stateHAnchors &&
stateHAnchors != QQuickAnchors::LeftAnchor &&
stateHAnchors != QQuickAnchors::RightAnchor &&
@@ -1114,8 +1111,11 @@ void QQuickAnchorChanges::reverse()
origHAnchors != QQuickAnchors::LeftAnchor &&
origHAnchors != QQuickAnchors::RightAnchor &&
origHAnchors != QQuickAnchors::HCenterAnchor);
- if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
- d->target->setWidth(d->origWidth.value);
+ if (d->origWidth.isValid() && stateSetWidth && !origSetWidth && !qt_is_nan(d->origWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (targetPrivate->width != d->origWidth)
+ targetPrivate->width.setValueBypassingBindings(d->origWidth);
+ }
bool stateSetHeight = (stateVAnchors &&
stateVAnchors != QQuickAnchors::TopAnchor &&
@@ -1127,14 +1127,23 @@ void QQuickAnchorChanges::reverse()
origVAnchors != QQuickAnchors::BottomAnchor &&
origVAnchors != QQuickAnchors::VCenterAnchor &&
origVAnchors != QQuickAnchors::BaselineAnchor);
- if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
- d->target->setHeight(d->origHeight.value);
+ if (d->origHeight.isValid() && stateSetHeight && !origSetHeight && !!qt_is_nan(d->origHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (targetPrivate->height != d->origHeight)
+ targetPrivate->height.setValueBypassingBindings(d->origHeight);
+ }
+
+ if (stateHAnchors && !origHAnchors && !qt_is_nan(d->origX) && d->origX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->origX);
- if (stateHAnchors && !origHAnchors)
- d->target->setX(d->origX);
+ if (stateVAnchors && !origVAnchors && !qt_is_nan(d->origY) && d->origY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->origY);
- if (stateVAnchors && !origVAnchors)
- d->target->setY(d->origY);
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
+ }
}
QQuickStateActionEvent::EventType QQuickAnchorChanges::type() const
@@ -1328,15 +1337,31 @@ void QQuickAnchorChanges::rewind()
return;
QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(d->target);
+ const QRectF oldGeometry(d->target->position(), d->target->size());
+
+ // Restore previous values (but not previous bindings, i.e. anchors).
+ // Also, don't drop any new bindings.
+ if (!qt_is_nan(d->rewindX) && d->rewindX != targetPrivate->x)
+ targetPrivate->x.setValueBypassingBindings(d->rewindX);
+ if (!qt_is_nan(d->rewindY) && d->rewindY != targetPrivate->y)
+ targetPrivate->y.setValueBypassingBindings(d->rewindY);
+
+ if (targetPrivate->widthValid() && !qt_is_nan(d->rewindWidth)) {
+ targetPrivate->widthValidFlag = true;
+ if (d->rewindWidth != targetPrivate->width)
+ targetPrivate->width.setValueBypassingBindings(d->rewindWidth);
+ }
- //restore previous values (but not previous bindings, i.e. anchors)
- d->target->setX(d->rewindX);
- d->target->setY(d->rewindY);
- if (targetPrivate->widthValid()) {
- d->target->setWidth(d->rewindWidth);
+ if (targetPrivate->heightValid() && !qt_is_nan(d->rewindHeight)) {
+ targetPrivate->heightValidFlag = true;
+ if (d->rewindHeight != targetPrivate->height)
+ targetPrivate->height.setValueBypassingBindings(d->rewindHeight);
}
- if (targetPrivate->heightValid()) {
- d->target->setHeight(d->rewindHeight);
+
+ const QRectF newGeometry(d->target->position(), d->target->size());
+ if (newGeometry != oldGeometry) {
+ targetPrivate->dirty(QQuickItemPrivate::Position);
+ d->target->geometryChange(newGeometry, oldGeometry);
}
}
@@ -1373,7 +1398,6 @@ void QQuickAnchorChanges::saveTargetValues()
d->toHeight = d->target->height();
}
-#include <moc_qquickstateoperations_p.cpp>
-
QT_END_NAMESPACE
+#include <moc_qquickstateoperations_p.cpp>
diff --git a/src/quick/items/qquicktableview.cpp b/src/quick/items/qquicktableview.cpp
index 540f2edfde..9f259166df 100644
--- a/src/quick/items/qquicktableview.cpp
+++ b/src/quick/items/qquicktableview.cpp
@@ -429,6 +429,7 @@
/*!
\qmlproperty ItemSelectionModel QtQuick::TableView::selectionModel
+ \since 6.2
This property can be set to control which delegate items should be shown as
selected. If the delegate has a \c {required property bool selected}
@@ -583,8 +584,8 @@
there is no setter function. This getter function is mostly
useful if the TableView doesn't have a columnWidthProvider set, since
otherwise you can call that function instead (which will work, even
- for columns that are not currently visible.
- If no columnWidthProvider is set, the height of a row will be
+ for columns that are not currently visible).
+ If no columnWidthProvider is set, the width of a column will be
equal to its \l implicitColumnWidth().
\sa columnWidthProvider, implicitColumnWidth(), isColumnLoaded(), {Row heights and column widths}
@@ -602,7 +603,7 @@
there is no setter function. This getter function is mostly
useful if the TableView doesn't have a rowHeightProvider set, since
otherwise you can call that function instead (which will work, even
- for rows that are not currently visible.
+ for rows that are not currently visible).
If no rowHeightProvider is set, the height of a row will be
equal to its \l implicitRowHeight().
@@ -687,8 +688,6 @@ Q_LOGGING_CATEGORY(lcTableViewDelegateLifecycle, "qt.quick.tableview.lifecycle")
#define Q_TABLEVIEW_ASSERT(cond, output) Q_ASSERT((cond) || [&](){ dumpTable(); qWarning() << "output:" << output; return false;}())
static const Qt::Edge allTableEdges[] = { Qt::LeftEdge, Qt::RightEdge, Qt::TopEdge, Qt::BottomEdge };
-static const int kEdgeIndexNotSet = -2;
-static const int kEdgeIndexAtEnd = -3;
static const char* kRequiredProperty = "_qt_isrequiredpropery_selected";
@@ -790,8 +789,12 @@ void QQuickTableViewPrivate::setSelectionStartPos(const QPointF &pos)
{
if (loadedItems.isEmpty())
return;
- if (!selectionModel)
+ if (!selectionModel) {
+ if (warnNoSelectionModel)
+ qmlWarning(q_func()) << "Cannot set selection: no SelectionModel assigned!";
+ warnNoSelectionModel = false;
return;
+ }
const QAbstractItemModel *qaim = selectionModel->model();
if (!qaim)
return;
@@ -816,8 +819,12 @@ void QQuickTableViewPrivate::setSelectionEndPos(const QPointF &pos)
{
if (loadedItems.isEmpty())
return;
- if (!selectionModel)
+ if (!selectionModel) {
+ if (warnNoSelectionModel)
+ qmlWarning(q_func()) << "Cannot set selection: no SelectionModel assigned!";
+ warnNoSelectionModel = false;
return;
+ }
const QAbstractItemModel *qaim = selectionModel->model();
if (!qaim)
return;
@@ -2331,16 +2338,31 @@ void QQuickTableViewPrivate::processRebuildTable()
if (rebuildState == RebuildState::LayoutTable) {
layoutAfterLoadingInitialTable();
+ loadAndUnloadVisibleEdges();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
+ if (rebuildState == RebuildState::CancelOvershootBottomRight) {
+ cancelOvershootBottomRight();
+ loadAndUnloadVisibleEdges();
if (!moveToNextRebuildState())
return;
}
- if (rebuildState == RebuildState::LoadAndUnloadAfterLayout) {
+ if (rebuildState == RebuildState::CancelOvershootTopLeft) {
+ cancelOvershootTopLeft();
loadAndUnloadVisibleEdges();
if (!moveToNextRebuildState())
return;
}
+ if (rebuildState == RebuildState::UpdateContentSize) {
+ updateContentSize();
+ if (!moveToNextRebuildState())
+ return;
+ }
+
const bool preload = (rebuildOptions & RebuildOption::All
&& reusableFlag == QQmlTableInstanceModel::Reusable);
@@ -2584,23 +2606,31 @@ void QQuickTableViewPrivate::loadInitialTable()
loadAndUnloadVisibleEdges();
}
-void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+void QQuickTableViewPrivate::updateContentSize()
{
- clearEdgeSizeCache();
- relayoutTableItems();
- syncLoadedTableRectFromLoadedTable();
-
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded()) {
+ const bool allColumnsLoaded = atTableEnd(Qt::LeftEdge) && atTableEnd(Qt::RightEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentWidth) || allColumnsLoaded) {
updateAverageColumnWidth();
updateContentWidth();
}
- if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded()) {
+ const bool allRowsLoaded = atTableEnd(Qt::TopEdge) && atTableEnd(Qt::BottomEdge);
+ if (rebuildOptions.testFlag(RebuildOption::CalculateNewContentHeight) || allRowsLoaded) {
updateAverageRowHeight();
updateContentHeight();
}
updateExtents();
+}
+
+void QQuickTableViewPrivate::layoutAfterLoadingInitialTable()
+{
+ clearEdgeSizeCache();
+ relayoutTableItems();
+ syncLoadedTableRectFromLoadedTable();
+
+ updateContentSize();
+
adjustViewportXAccordingToAlignment();
adjustViewportYAccordingToAlignment();
}
@@ -2675,6 +2705,58 @@ void QQuickTableViewPrivate::adjustViewportYAccordingToAlignment()
syncViewportRect();
}
+void QQuickTableViewPrivate::cancelOvershootBottomRight()
+{
+ // After doing a layout with positioning specified, the table might end up in an
+ // overshooting state (meaning that the table is dragged beyond the bounds
+ // of the viewport, with the result that it will bounce back in once you touch it).
+ // This happens because the layouting might try to e.g position the last row in the
+ // model in the center of the viewport, which will leave a big blank space from the
+ // last row towards the bottom.
+ // This space will be detected by updateExtents(), which will adjust the extents so
+ // that the superfluous blank area ends up as an overshoot. But we shouldn't leave the
+ // table in an overshooting state after a rebuild, so we clamp it here so thatit's
+ // either aligned to the top/left or to the bottom/right of the viewport.
+ // An exception is if we're not rebuilding because of positionViewAtCell(), since
+ // the app is allowed to set contentX and contentY at start-up. A second exception is
+ // if this view is a sync child, since then we can end up with extra space at the end
+ // if our model has fewer rows/columns than the syncView.
+ const qreal blankSpaceRight = viewportRect.right() - loadedTableOuterRect.right();
+ const qreal blankSpaceBottom = viewportRect.bottom() - loadedTableOuterRect.bottom();
+ const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
+ const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
+
+ if (positionVertically && !syncVertically && viewportRect.top() > 0 && blankSpaceBottom > 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at bottom:" << blankSpaceBottom;
+ setLocalViewportY(viewportRect.y() - blankSpaceBottom);
+ syncViewportRect();
+ }
+
+ if (positionHorizontally && !syncHorizontally && viewportRect.left() > 0 && blankSpaceRight > 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at right:" << blankSpaceRight;
+ setLocalViewportX(viewportRect.x() - blankSpaceRight);
+ syncViewportRect();
+ }
+}
+
+void QQuickTableViewPrivate::cancelOvershootTopLeft()
+{
+ const bool positionVertically = rebuildOptions.testFlag(RebuildOption::PositionViewAtRow);
+ const bool positionHorizontally = rebuildOptions.testFlag(RebuildOption::PositionViewAtColumn);
+
+ if (positionVertically && !syncVertically && viewportRect.top() < 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at top:" << viewportRect.top();
+ setLocalViewportY(0);
+ syncViewportRect();
+ }
+
+ if (positionHorizontally && !syncHorizontally && viewportRect.left() < 0) {
+ qCDebug(lcTableViewDelegateLifecycle()) << "cancelling overshoot at left:" << viewportRect.left();
+ setLocalViewportX(0);
+ syncViewportRect();
+ }
+}
+
void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
{
Q_Q(QQuickTableView);
@@ -2725,7 +2807,7 @@ void QQuickTableViewPrivate::unloadEdge(Qt::Edge edge)
void QQuickTableViewPrivate::loadEdge(Qt::Edge edge, QQmlIncubator::IncubationMode incubationMode)
{
const int edgeIndex = nextVisibleEdgeIndexAroundLoadedTable(edge);
- qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex;
+ qCDebug(lcTableViewDelegateLifecycle) << edge << edgeIndex << q_func();
const auto visibleCells = edge & (Qt::LeftEdge | Qt::RightEdge)
? loadedRows.keys() : loadedColumns.keys();
@@ -3226,11 +3308,25 @@ void QQuickTableViewPrivate::syncSyncView()
if (syncHorizontally) {
q->setColumnSpacing(syncView->columnSpacing());
updateContentWidth();
+
+ if (syncView->leftColumn() != q->leftColumn()) {
+ // The left column is no longer the same as the left
+ // column in syncView. This requires a rebuild.
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftColumn;
+ scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ }
}
if (syncVertically) {
q->setRowSpacing(syncView->rowSpacing());
updateContentHeight();
+
+ if (syncView->topRow() != q->topRow()) {
+ // The top row is no longer the same as the top
+ // row in syncView. This requires a rebuild.
+ scheduledRebuildOptions |= QQuickTableViewPrivate::RebuildOption::CalculateNewTopLeftRow;
+ scheduledRebuildOptions.setFlag(RebuildOption::ViewportOnly);
+ }
}
if (syncView && loadedItems.isEmpty() && !tableSize.isEmpty()) {
@@ -3456,10 +3552,26 @@ void QQuickTableViewPrivate::setLocalViewportY(qreal contentY)
void QQuickTableViewPrivate::syncViewportRect()
{
- // Sync viewportRect so that it contains the actual geometry of the viewport
+ // Sync viewportRect so that it contains the actual geometry of the viewport.
+ // Since the column (and row) size of a sync child is decided by the column size
+ // of its sync view, the viewport width of a sync view needs to be the maximum of
+ // the sync views width, and its sync childrens width. This to ensure that no sync
+ // child loads a column which is not yet loaded by the sync view, since then the
+ // implicit column size cannot be resolved.
Q_Q(QQuickTableView);
- viewportRect = QRectF(q->contentX(), q->contentY(), q->width(), q->height());
- qCDebug(lcTableViewDelegateLifecycle) << viewportRect;
+
+ qreal w = q->width();
+ qreal h = q->height();
+
+ for (auto syncChild : std::as_const(syncChildren)) {
+ auto syncChild_d = syncChild->d_func();
+ if (syncChild_d->syncHorizontally)
+ w = qMax(w, syncChild->width());
+ if (syncChild_d->syncHorizontally)
+ h = qMax(h, syncChild->height());
+ }
+
+ viewportRect = QRectF(q->contentX(), q->contentY(), w, h);
}
void QQuickTableViewPrivate::syncViewportPosRecursive()
@@ -4154,3 +4266,5 @@ QQuickTableSectionSizeProviderPrivate::~QQuickTableSectionSizeProviderPrivate()
#include "moc_qquicktableview_p.cpp"
QT_END_NAMESPACE
+
+#include "moc_qquicktableview_p_p.cpp"
diff --git a/src/quick/items/qquicktableview_p_p.h b/src/quick/items/qquicktableview_p_p.h
index 76d5c152da..9893cd97e7 100644
--- a/src/quick/items/qquicktableview_p_p.h
+++ b/src/quick/items/qquicktableview_p_p.h
@@ -71,6 +71,8 @@ Q_DECLARE_LOGGING_CATEGORY(lcTableViewDelegateLifecycle)
static const qreal kDefaultRowHeight = 50;
static const qreal kDefaultColumnWidth = 50;
+static const int kEdgeIndexNotSet = -2;
+static const int kEdgeIndexAtEnd = -3;
class FxTableItem;
class QQuickTableSectionSizeProviderPrivate;
@@ -201,7 +203,9 @@ public:
LoadInitalTable,
VerifyTable,
LayoutTable,
- LoadAndUnloadAfterLayout,
+ CancelOvershootBottomRight,
+ CancelOvershootTopLeft,
+ UpdateContentSize,
PreloadColumns,
PreloadRows,
MovePreloadedItemsToPool,
@@ -288,6 +292,8 @@ public:
// Consider making it public.
bool isTransposed = false;
+ bool warnNoSelectionModel = true;
+
QJSValue rowHeightProvider;
QJSValue columnWidthProvider;
QQuickTableSectionSizeProvider rowHeights;
@@ -396,6 +402,9 @@ public:
int nextVisibleEdgeIndex(Qt::Edge edge, int startIndex);
int nextVisibleEdgeIndexAroundLoadedTable(Qt::Edge edge);
+ inline bool atTableEnd(Qt::Edge edge) {
+ return nextVisibleEdgeIndexAroundLoadedTable(edge) == kEdgeIndexAtEnd;
+ }
bool allColumnsLoaded();
bool allRowsLoaded();
inline int edgeToArrayIndex(Qt::Edge edge);
@@ -432,8 +441,13 @@ public:
void adjustViewportXAccordingToAlignment();
void adjustViewportYAccordingToAlignment();
+ void cancelOvershootBottomRight();
+ void cancelOvershootTopLeft();
+
void scheduleRebuildTable(QQuickTableViewPrivate::RebuildOptions options);
+ void updateContentSize();
+
QTypeRevision resolveImportVersion();
void createWrapperModel();
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 0f17af1975..ec1416768e 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -764,11 +764,15 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const bool pixelSize = font.pixelSize() != -1;
QString layoutText = layout.text();
- int largeFont = pixelSize ? font.pixelSize() : font.pointSize();
- int smallFont = fontSizeMode() != QQuickText::FixedSize
- ? qMin(pixelSize ? minimumPixelSize() : minimumPointSize(), largeFont)
- : largeFont;
- int scaledFontSize = largeFont;
+ const qreal minimumSize = pixelSize
+ ? static_cast<qreal>(minimumPixelSize())
+ : minimumPointSize();
+ qreal largeFont = pixelSize ? font.pixelSize() : font.pointSizeF();
+ qreal smallFont = fontSizeMode() != QQuickText::FixedSize
+ ? qMin<qreal>(minimumSize, largeFont)
+ : largeFont;
+ qreal scaledFontSize = largeFont;
+ const qreal sizeFittingThreshold(0.01);
bool widthChanged = false;
widthExceeded = availableWidth() <= 0 && (singlelineElide || canWrap || horizontalFit);
@@ -797,7 +801,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (pixelSize)
scaledFont.setPixelSize(scaledFontSize);
else
- scaledFont.setPointSize(scaledFontSize);
+ scaledFont.setPointSizeF(scaledFontSize);
if (layout.font() != scaledFont)
layout.setFont(scaledFont);
}
@@ -967,7 +971,7 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
const qreal availWidth = availableWidth();
const qreal availHeight = availableHeight();
- lineWidth = q->widthValid() && availWidth > 0 ? availWidth : naturalWidth;
+ lineWidth = q->widthValid() && q->width() > 0 ? availWidth : naturalWidth;
maxHeight = q->heightValid() ? availHeight : FLT_MAX;
// If the width of the item has changed and it's possible the result of wrapping,
@@ -1061,40 +1065,45 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
if (!horizontalFit && !verticalFit)
break;
+ // Can't find a better fit
+ if (qFuzzyCompare(smallFont, largeFont))
+ break;
+
// Try and find a font size that better fits the dimensions of the element.
if (horizontalFit) {
if (unelidedRect.width() > lineWidth || (!verticalFit && wrapped)) {
widthExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
- if (pixelSize)
- scaledFont.setPixelSize(scaledFontSize);
- else
- scaledFont.setPointSize(scaledFontSize);
+
continue;
} else if (!verticalFit) {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
if (verticalFit) {
if (truncateHeight || unelidedRect.height() > maxHeight) {
heightExceeded = true;
- largeFont = scaledFontSize - 1;
- if (smallFont > largeFont)
- break;
+ largeFont = scaledFontSize;
+
scaledFontSize = (smallFont + largeFont) / 2;
} else {
smallFont = scaledFontSize;
- if (smallFont == largeFont)
+
+ // Check to see if the current scaledFontSize is acceptable
+ if ((largeFont - smallFont) < sizeFittingThreshold)
break;
- scaledFontSize = (smallFont + largeFont + 1) / 2;
+
+ scaledFontSize = (smallFont + largeFont) / 2;
}
}
}
@@ -1153,12 +1162,6 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
elideLayout->setFont(layout.font());
elideLayout->setTextOption(layout.textOption());
-#if QT_CONFIG(translation) && QT_CONFIG(qml_debug)
- if (QQmlDebugTranslationService *service
- = QQmlDebugConnector::service<QQmlDebugTranslationService>()) {
- elideText = service->foundElidedText(q, layoutText, elideText);
- }
-#endif //QT_CONFIG(translation)
elideLayout->setText(elideText);
elideLayout->beginLayout();
@@ -2416,21 +2419,23 @@ void QQuickText::geometryChange(const QRectF &newGeometry, const QRectF &oldGeom
goto geomChangeDone;
if (!(widthChanged || widthMaximum) && !d->isLineLaidOutConnected()) { // only height has changed
- if (newGeometry.height() > oldGeometry.height()) {
- if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
- // Height is adequate and growing, and it wasn't 0 previously.
- goto geomChangeDone;
- }
- if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
- goto geomChangeDone;
- } else if (newGeometry.height() < oldGeometry.height()) {
- if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
- goto geomChangeDone;
-
- if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
- && d->elideMode != QQuickText::ElideRight
- && !(d->maximumLineCountValid && d->widthExceeded)) {
- goto geomChangeDone;
+ if (!verticalPositionChanged) {
+ if (newGeometry.height() > oldGeometry.height()) {
+ if (!d->heightExceeded && !qFuzzyIsNull(oldGeometry.height())) {
+ // Height is adequate and growing, and it wasn't 0 previously.
+ goto geomChangeDone;
+ }
+ if (d->lineCount == d->maximumLineCount()) // Reached maximum line and height is growing.
+ goto geomChangeDone;
+ } else if (newGeometry.height() < oldGeometry.height()) {
+ if (d->lineCount < 2 && !verticalScale && newGeometry.height() > 0) // A single line won't be truncated until the text is 0 height.
+ goto geomChangeDone;
+
+ if (!verticalScale // no scaling, no eliding, and either unwrapped, or no maximum line count.
+ && d->elideMode != QQuickText::ElideRight
+ && !(d->maximumLineCountValid && d->widthExceeded)) {
+ goto geomChangeDone;
+ }
}
}
} else if (!heightChanged && widthMaximum) {
@@ -2958,7 +2963,7 @@ void QQuickTextPrivate::processHoverEvent(QHoverEvent *event)
emit q->linkHovered(extra->hoveredLink);
}
}
- event->setAccepted(!link.isEmpty());
+ event->ignore();
}
void QQuickText::hoverEnterEvent(QHoverEvent *event)
@@ -2981,6 +2986,7 @@ void QQuickText::hoverLeaveEvent(QHoverEvent *event)
/*!
\qmlproperty int QtQuick::Text::renderTypeQuality
+ \since 6.0
Override the default rendering type quality for this component. This is a low-level
customization which can be ignored in most cases. It currently only has an effect
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index 304b82b914..13d8579017 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -339,6 +339,8 @@ private:
Q_DECLARE_PRIVATE(QQuickText)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickText::HAlignment, QQuickText::VAlignment)
+
class QTextLine;
class QQuickTextLine : public QObject
{
diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp
index 32a27661ea..1412b68ceb 100644
--- a/src/quick/items/qquicktextedit.cpp
+++ b/src/quick/items/qquicktextedit.cpp
@@ -1203,7 +1203,15 @@ void QQuickTextEdit::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextEdit::cursorPosition
- The position of the cursor in the TextEdit.
+ The position of the cursor in the TextEdit. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
*/
int QQuickTextEdit::cursorPosition() const
{
@@ -2959,6 +2967,7 @@ void QQuickTextEdit::hoverEnterEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
@@ -2966,6 +2975,7 @@ void QQuickTextEdit::hoverMoveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
@@ -2973,6 +2983,7 @@ void QQuickTextEdit::hoverLeaveEvent(QHoverEvent *event)
Q_D(QQuickTextEdit);
if (d->isLinkHoveredConnected())
d->control->processEvent(event, QPointF(-d->xoff, -d->yoff));
+ event->ignore();
}
/*!
diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h
index 41245f904e..7b43a847c1 100644
--- a/src/quick/items/qquicktextedit_p.h
+++ b/src/quick/items/qquicktextedit_p.h
@@ -422,6 +422,8 @@ private:
Q_DECLARE_PRIVATE(QQuickTextEdit)
};
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QQuickTextEdit::HAlignment, QQuickTextEdit::VAlignment)
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickTextEdit)
diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp
index e5922df623..c08f357df8 100644
--- a/src/quick/items/qquicktextinput.cpp
+++ b/src/quick/items/qquicktextinput.cpp
@@ -517,8 +517,16 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
}
/*!
- \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::effectiveHorizontalAlignment
+ \readonly
+
+ When using the attached property LayoutMirroring::enabled to mirror application
+ layouts, the horizontal alignment of text will also be mirrored. However, the property
+ \l horizontalAlignment will remain unchanged. To query the effective horizontal alignment
+ of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+*/
+/*!
+ \qmlproperty enumeration QtQuick::TextInput::horizontalAlignment
\qmlproperty enumeration QtQuick::TextInput::verticalAlignment
Sets the horizontal alignment of the text within the TextInput item's
@@ -541,7 +549,7 @@ void QQuickTextInput::setSelectedTextColor(const QColor &color)
When using the attached property LayoutMirroring::enabled to mirror application
layouts, the horizontal alignment of text will also be mirrored. However, the property
\c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
- of TextInput, use the read-only property \c effectiveHorizontalAlignment.
+ of TextInput, use the read-only property \l effectiveHorizontalAlignment.
*/
QQuickTextInput::HAlignment QQuickTextInput::hAlign() const
{
@@ -830,7 +838,20 @@ void QQuickTextInput::setCursorVisible(bool on)
/*!
\qmlproperty int QtQuick::TextInput::cursorPosition
- The position of the cursor in the TextInput.
+ The position of the cursor in the TextInput. The cursor is positioned between
+ characters.
+
+ \note The \e characters in this case refer to the string of \l QChar objects,
+ therefore 16-bit Unicode characters, and the position is considered an index
+ into this string. This does not necessarily correspond to individual graphemes
+ in the writing system, as a single grapheme may be represented by multiple
+ Unicode characters, such as in the case of surrogate pairs, linguistic
+ ligatures or diacritics.
+
+ \l displayText is different if echoMode is set to \l TextInput.Password: then
+ each passwordMaskCharacter is a "narrow" character
+ (the cursorPosition always moves by 1), even if the text in the TextInput is not.
+
*/
int QQuickTextInput::cursorPosition() const
{
@@ -848,6 +869,7 @@ void QQuickTextInput::setCursorPosition(int cp)
/*!
\qmlproperty rectangle QtQuick::TextInput::cursorRectangle
+ \readonly
The rectangle where the standard text cursor is rendered within the text input. Read only.
@@ -889,6 +911,7 @@ QRectF QQuickTextInput::cursorRectangle() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionEnd, cursorPosition, selectedText
*/
int QQuickTextInput::selectionStart() const
@@ -904,6 +927,7 @@ int QQuickTextInput::selectionStart() const
This property is read-only. To change the selection, use select(start,end),
selectAll(), or selectWord().
+ \readonly
\sa selectionStart, cursorPosition, selectedText
*/
int QQuickTextInput::selectionEnd() const
@@ -934,6 +958,7 @@ void QQuickTextInput::select(int start, int end)
/*!
\qmlproperty string QtQuick::TextInput::selectedText
+ \readonly
This read-only property provides the text currently selected in the
text input.
@@ -1151,6 +1176,7 @@ void QQuickTextInput::setInputMask(const QString &im)
/*!
\qmlproperty bool QtQuick::TextInput::acceptableInput
+ \readonly
This property is always true unless a validator or input mask has been set.
If a validator or input mask has been set, this property will only be true
@@ -2001,6 +2027,8 @@ QVariant QQuickTextInput::inputMethodQuery(Qt::InputMethodQuery property, const
if (argument.isValid())
return QVariant(QStringView{d->m_text}.left(d->m_cursor).right(argument.toInt()).toString());
return QVariant(d->m_text.left(d->m_cursor));
+ case Qt::ImReadOnly:
+ return QVariant(d->m_readOnly);
default:
return QQuickItem::inputMethodQuery(property);
}
@@ -2104,7 +2132,7 @@ void QQuickTextInput::undo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalUndo();
d->finishChange(-1, true);
}
@@ -2120,7 +2148,7 @@ void QQuickTextInput::redo()
{
Q_D(QQuickTextInput);
if (!d->m_readOnly) {
- d->resetInputMethod();
+ d->cancelInput();
d->internalRedo();
d->finishChange();
}
@@ -2458,6 +2486,7 @@ void QQuickTextInput::setPersistentSelection(bool on)
/*!
\qmlproperty bool QtQuick::TextInput::canPaste
+ \readonly
Returns true if the TextInput is writable and the content of the clipboard is
suitable for pasting into the TextInput.
@@ -2479,6 +2508,7 @@ bool QQuickTextInput::canPaste() const
/*!
\qmlproperty bool QtQuick::TextInput::canUndo
+ \readonly
Returns true if the TextInput is writable and there are previous operations
that can be undone.
@@ -2492,6 +2522,7 @@ bool QQuickTextInput::canUndo() const
/*!
\qmlproperty bool QtQuick::TextInput::canRedo
+ \readonly
Returns true if the TextInput is writable and there are \l {undo}{undone}
operations that can be redone.
@@ -2505,6 +2536,7 @@ bool QQuickTextInput::canRedo() const
/*!
\qmlproperty real QtQuick::TextInput::contentWidth
+ \readonly
Returns the width of the text, including the width past the width
which is covered due to insufficient wrapping if \l wrapMode is set.
@@ -2518,6 +2550,7 @@ qreal QQuickTextInput::contentWidth() const
/*!
\qmlproperty real QtQuick::TextInput::contentHeight
+ \readonly
Returns the height of the text, including the height past the height
that is covered if the text does not fit within the set height.
@@ -2681,7 +2714,7 @@ void QQuickTextInput::focusOutEvent(QFocusEvent *event)
/*!
\qmlproperty bool QtQuick::TextInput::inputMethodComposing
-
+ \readonly
This property holds whether the TextInput has partial text input from an
input method.
@@ -2747,11 +2780,13 @@ void QQuickTextInputPrivate::init()
m_inputControl = new QInputControl(QInputControl::LineEdit, q);
}
-void QQuickTextInputPrivate::resetInputMethod()
+void QQuickTextInputPrivate::cancelInput()
{
+#if QT_CONFIG(im)
Q_Q(QQuickTextInput);
if (!m_readOnly && q->hasActiveFocus() && qGuiApp)
- QGuiApplication::inputMethod()->reset();
+ cancelPreedit();
+#endif // im
}
void QQuickTextInput::updateCursorRectangle(bool scroll)
@@ -3459,7 +3494,12 @@ void QQuickTextInputPrivate::processInputMethodEvent(QInputMethodEvent *event)
for (int i = 0; i < event->attributes().size(); ++i) {
const QInputMethodEvent::Attribute &a = event->attributes().at(i);
if (a.type == QInputMethodEvent::Selection) {
- m_cursor = qBound(0, a.start + a.length, m_text.length());
+ // If we already called internalInsert(), the cursor position will
+ // already be adjusted correctly. The attribute.start does
+ // not seem to take the mask into account, so it will reset cursor
+ // to an invalid position in such case.
+ if (!cursorPositionChanged)
+ m_cursor = qBound(0, a.start + a.length, m_text.length());
if (a.length) {
m_selstart = qMax(0, qMin(a.start, m_text.length()));
m_selend = m_cursor;
@@ -4696,7 +4736,7 @@ void QQuickTextInput::ensureVisible(int position)
void QQuickTextInput::clear()
{
Q_D(QQuickTextInput);
- d->resetInputMethod();
+ d->cancelInput();
d->clear();
}
diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h
index b4561556aa..1fecd7f9df 100644
--- a/src/quick/items/qquicktextinput_p_p.h
+++ b/src/quick/items/qquicktextinput_p_p.h
@@ -173,7 +173,7 @@ public:
}
void init();
- void resetInputMethod();
+ void cancelInput();
void startCreatingCursor();
void ensureVisible(int position, int preeditCursor = 0, int preeditLength = 0);
void updateHorizontalScroll();
diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp
index b3401200c8..763607f730 100644
--- a/src/quick/items/qquicktextnodeengine.cpp
+++ b/src/quick/items/qquicktextnodeengine.cpp
@@ -209,10 +209,7 @@ void QQuickTextNodeEngine::addTextDecorations(const QVarLengthArray<TextDecorati
{
QRectF &rect = textDecoration.rect;
- rect.setY(qRound(rect.y()
- + m_currentLine.ascent()
- + (m_currentLine.leadingIncluded() ? m_currentLine.leading() : qreal(0.0f))
- + offset));
+ rect.setY(qRound(rect.y() + m_currentLine.ascent() + offset));
rect.setHeight(thickness);
}
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 314223a838..19b508cecb 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -483,18 +483,14 @@ void forceUpdate(QQuickItem *item)
forceUpdate(items.at(i));
}
-void QQuickWindowRenderTarget::reset(QRhi *rhi, QSGRenderer *renderer)
+void QQuickWindowRenderTarget::reset(QRhi *rhi)
{
- if (rhi) {
- if (renderer)
- renderer->invalidatePipelineCacheDependency(rpDesc);
- if (owns) {
- delete renderTarget;
- delete rpDesc;
- delete texture;
- delete renderBuffer;
- delete depthStencil;
- }
+ if (rhi && owns) {
+ delete renderTarget;
+ delete rpDesc;
+ delete texture;
+ delete renderBuffer;
+ delete depthStencil;
}
renderTarget = nullptr;
@@ -514,7 +510,7 @@ void QQuickWindowPrivate::ensureCustomRenderTarget()
redirect.renderTargetDirty = false;
- redirect.rt.reset(rhi, renderer);
+ redirect.rt.reset(rhi);
// a default constructed QQuickRenderTarget means no redirection
if (customRenderTarget.isNull())
@@ -723,7 +719,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
QQuickWindowPrivate::~QQuickWindowPrivate()
{
inDestructor = true;
- redirect.rt.reset(rhi, renderer);
+ redirect.rt.reset(rhi);
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->removeWindow(q_func());
deliveryAgent = nullptr;
@@ -884,14 +880,6 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
The Window object creates a new top-level window for a Qt Quick scene. It automatically sets up the
window for use with \c {QtQuick} graphical types.
- To use this type, you will need to import the module with the following line:
- \code
- import QtQuick
- \endcode
-
- Omitting this import will allow you to have a QML environment without
- access to window system features.
-
A Window can be declared inside an Item or inside another Window; in that
case the inner Window will automatically become "transient for" the outer
Window: that is, most platforms will show it centered upon the outer window
@@ -907,9 +895,23 @@ void QQuickWindowPrivate::cleanup(QSGNode *n)
When the user attempts to close a window, the \l closing signal will be
emitted. You can force the window to stay open (for example to prompt the
- user to save changes) by writing an \c onClosing handler and setting
- \c {close.accepted = false}.
+ user to save changes) by writing an \c onClosing handler that sets
+ \c {close.accepted = false} unless it's safe to close the window (for example,
+ because there are no more unsaved changes).
+
+ \code
+ onClosing: (close) => {
+ if (document.changed) {
+ close.accepted = false
+ confirmExitPopup.open()
+ }
+ }
+
+ // The confirmExitPopup allows user to save or discard the document,
+ // or to cancel the closing.
+ \endcode
*/
+
/*!
\class QQuickWindow
\since 5.0
@@ -1094,7 +1096,11 @@ QQuickWindow::QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent)
}
/*!
- \internal
+ Constructs a window for displaying a QML scene, whose rendering will
+ be controlled by the \a control object.
+ Please refer to QQuickRenderControl's documentation for more information.
+
+ \since 5.4
*/
QQuickWindow::QQuickWindow(QQuickRenderControl *control)
: QWindow(*(new QQuickWindowPrivate), nullptr)
@@ -1318,6 +1324,8 @@ QQuickItem *QQuickWindow::contentItem() const
\brief The item which currently has active focus or \c null if there is
no item with active focus.
+
+ \sa QQuickItem::forceActiveFocus(), {Keyboard Focus in Qt Quick}
*/
QQuickItem *QQuickWindow::activeFocusItem() const
{
@@ -1350,6 +1358,38 @@ bool QQuickWindow::event(QEvent *e)
QQuickDeliveryAgent *da = d->deliveryAgent;
if (e->isPointerEvent()) {
/*
+ We can't bypass the virtual functions like mousePressEvent() tabletEvent() etc.,
+ for the sake of code that subclasses QQuickWindow and overrides them, even though
+ we no longer need them as entry points for Qt Quick event delivery.
+ So dispatch to them now, ahead of normal delivery, and stop them from calling
+ back into this function if they were called from here (avoid recursion).
+ It could also be that user code expects them to work as entry points, too;
+ in that case, windowEventDispatch _won't_ be set, so the event comes here and
+ we'll dispatch it further below.
+ */
+ if (d->windowEventDispatch)
+ return false;
+ {
+ const bool wasAccepted = e->isAccepted();
+ QBoolBlocker windowEventDispatchGuard(d->windowEventDispatch, true);
+ qCDebug(lcPtr) << "dispatching to window functions in case of override" << e;
+ QWindow::event(e);
+ if (e->isAccepted() && !wasAccepted)
+ return true;
+ }
+ /*
+ QQuickWindow does not override touchEvent(). If the application has a subclass
+ of QQuickWindow which allows the event to remain accepted, it means they want
+ to stop propagation here, so return early (below). But otherwise we will call
+ QWindow::touchEvent(), which will ignore(); in that case, we need to continue
+ with the usual delivery below, so we need to undo the ignore().
+ */
+ auto pe = static_cast<QPointerEvent *>(e);
+ if (QQuickDeliveryAgentPrivate::isTouchEvent(pe))
+ e->accept();
+ // end of dispatch to user-overridden virtual window functions
+
+ /*
When delivering update and release events to existing grabbers,
use the subscene delivery agent, if any. A possible scenario:
1) Two touchpoints pressed on the main window: QQuickWindowPrivate::deliveryAgent delivers to QQuick3DViewport,
@@ -1362,7 +1402,6 @@ bool QQuickWindow::event(QEvent *e)
With single-point events (mouse, or only one finger) it's simplified: there can only be one subscene of interest;
for (pt : pe->points()) would only iterate once, so we might as well skip that logic.
*/
- auto pe = static_cast<QPointerEvent *>(e);
if (pe->pointCount()) {
if (QQuickDeliveryAgentPrivate::subsceneAgentsExist) {
bool ret = false;
@@ -1533,13 +1572,18 @@ bool QQuickWindow::event(QEvent *e)
else if (e->type() == QEvent::Type(QQuickWindowPrivate::TriggerContextCreationFailure))
d->windowManager->handleContextCreationFailure(this);
- return QWindow::event(e);
+ if (e->isPointerEvent())
+ return true;
+ else
+ return QWindow::event(e);
}
/*! \reimp */
void QQuickWindow::keyPressEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1549,6 +1593,8 @@ void QQuickWindow::keyPressEvent(QKeyEvent *e)
void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverKeyEvent(e);
@@ -1559,6 +1605,8 @@ void QQuickWindow::keyReleaseEvent(QKeyEvent *e)
void QQuickWindow::wheelEvent(QWheelEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverSinglePointEventUntilAccepted(event);
@@ -1570,6 +1618,8 @@ void QQuickWindow::wheelEvent(QWheelEvent *event)
void QQuickWindow::tabletEvent(QTabletEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->deliverPointerEvent(event);
@@ -1580,6 +1630,8 @@ void QQuickWindow::tabletEvent(QTabletEvent *event)
void QQuickWindow::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1588,6 +1640,8 @@ void QQuickWindow::mousePressEvent(QMouseEvent *event)
void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1596,6 +1650,8 @@ void QQuickWindow::mouseMoveEvent(QMouseEvent *event)
void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1604,6 +1660,8 @@ void QQuickWindow::mouseDoubleClickEvent(QMouseEvent *event)
void QQuickWindow::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickWindow);
+ if (d->windowEventDispatch)
+ return;
auto da = d->deliveryAgentPrivate();
Q_ASSERT(da);
da->handleMouseEvent(event);
@@ -1672,6 +1730,12 @@ QPair<QQuickItem*, QQuickPointerHandler*> QQuickWindowPrivate::findCursorItemAnd
}
#endif
+void QQuickWindowPrivate::clearFocusObject()
+{
+ if (auto da = deliveryAgentPrivate())
+ da->clearFocusObject();
+}
+
/*!
\qmlproperty list<Object> Window::data
\qmldefault
@@ -1787,7 +1851,7 @@ void QQuickWindowPrivate::cleanupNodesOnShutdown(QQuickItem *item)
p->dirty(QQuickItemPrivate::Window);
}
- // Qt 6: Make invalidateSceneGraph a virtual member of QQuickItem
+ // Qt 7: Make invalidateSceneGraph a virtual member of QQuickItem
if (p->flags & QQuickItem::ItemHasContents) {
const QMetaObject *mo = item->metaObject();
int index = mo->indexOfSlot("invalidateSceneGraph()");
@@ -2000,9 +2064,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
// desired list is shorter.
QSGNode *groupNode = itemPriv->childContainerNode();
QSGNode *currentNode = groupNode->firstChild();
- int added = 0;
- int removed = 0;
- int replaced = 0;
QSGNode *desiredNode = nullptr;
while (currentNode && (desiredNode = fetchNextNode(itemPriv, ii, fetchedPaintNode))) {
@@ -2015,7 +2076,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
desiredNode->parent()->removeChildNode(desiredNode);
groupNode->insertChildNodeAfter(desiredNode, currentNode);
groupNode->removeChildNode(currentNode);
- replaced++;
// since we just replaced currentNode, we also need to reset
// the pointer.
@@ -2034,7 +2094,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
if (desiredNode->parent())
desiredNode->parent()->removeChildNode(desiredNode);
groupNode->appendChildNode(desiredNode);
- added++;
}
} else if (currentNode) {
// on the other hand, if we processed less than our current node
@@ -2044,7 +2103,6 @@ void QQuickWindowPrivate::updateDirtyNode(QQuickItem *item)
QSGNode *node = currentNode->nextSibling();
groupNode->removeChildNode(currentNode);
currentNode = node;
- removed++;
}
}
}
@@ -2490,7 +2548,7 @@ QImage QQuickWindow::grabWindow()
{
Q_D(QQuickWindow);
- if (!isVisible() && !d->renderControl) {
+ if (!d->isRenderable() && !d->renderControl) {
// backends like software can grab regardless of the window state
if (d->windowManager && (d->windowManager->flags() & QSGRenderLoop::SupportsGrabWithoutExpose))
return d->windowManager->grab(this);
@@ -3780,7 +3838,7 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
graphics API based on the platform and other conditions, set \a api to
QSGRendererInterface::Unknown.
- \since 5.8
+ \since 6.0
*/
void QQuickWindow::setGraphicsApi(QSGRendererInterface::GraphicsApi api)
{
@@ -4082,7 +4140,7 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
/*!
\since 6.0
- \qmlproperty QQuickPalette Window::palette
+ \qmlproperty Palette Window::palette
This property holds the palette currently set for the window.
@@ -4094,7 +4152,7 @@ void QQuickWindow::setTextRenderType(QQuickWindow::TextRenderType renderType)
property on the window's palette, that property propagates to all child controls in the window,
overriding any system defaults for that property.
- \sa Item::palette, Popup::palette, QQuickColorGroup
+ \sa Item::palette, Popup::palette, ColorGroup, SystemPalette
//! internal \sa QQuickAbstractPaletteProvider, QQuickPalette
*/
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index 7342424251..3b442499bb 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -110,7 +110,7 @@ public Q_SLOTS:
class QQuickWindowRenderTarget
{
public:
- void reset(QRhi *rhi, QSGRenderer *renderer);
+ void reset(QRhi *rhi);
QRhiRenderTarget *renderTarget = nullptr;
QRhiRenderPassDescriptor *rpDesc = nullptr;
QRhiTexture *texture = nullptr;
@@ -161,6 +161,8 @@ public:
QPair<QQuickItem*, QQuickPointerHandler*> findCursorItemAndHandler(QQuickItem *item, const QPointF &scenePos) const;
#endif
+ void clearFocusObject() override;
+
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);
@@ -249,9 +251,18 @@ public:
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason)
{ deliveryAgentPrivate()->clearFocusInScope(scope, item, reason); }
void handleTouchEvent(QTouchEvent *e)
- { deliveryAgentPrivate()->handleTouchEvent(e); }
+ {
+ // setup currentEventDeliveryAgent like in QQuickDeliveryAgent::event
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveryAgentPrivate()->q_func();
+ deliveryAgentPrivate()->handleTouchEvent(e);
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
+ }
void handleMouseEvent(QMouseEvent *e)
- { deliveryAgentPrivate()->handleMouseEvent(e); }
+ {
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = deliveryAgentPrivate()->q_func();
+ deliveryAgentPrivate()->handleMouseEvent(e);
+ QQuickDeliveryAgentPrivate::currentEventDeliveryAgent = nullptr;
+ }
// ^^^ currently in use in Controls 2; TODO remove
// data property
@@ -287,6 +298,7 @@ public:
uint hasActiveSwapchain : 1;
uint hasRenderableSwapchain : 1;
uint swapchainJustBecameRenderable : 1;
+ bool windowEventDispatch = false;
private:
static void cleanupNodesOnShutdown(QQuickItem *);
diff --git a/src/quick/items/qquickwindowmodule_p.h b/src/quick/items/qquickwindowmodule_p.h
index 7177469b55..c1cd48f964 100644
--- a/src/quick/items/qquickwindowmodule_p.h
+++ b/src/quick/items/qquickwindowmodule_p.h
@@ -74,7 +74,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowQmlImpl : public QQuickWindow, public Q
Q_INTERFACES(QQmlParserStatus)
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
- Q_PROPERTY(Visibility visibility READ visibility WRITE setVisibility NOTIFY visibilityChanged)
+ Q_PROPERTY(QWindow::Visibility visibility READ visibility WRITE setVisibility NOTIFY
+ visibilityChanged)
Q_PROPERTY(QObject *screen READ screen WRITE setScreen NOTIFY screenChanged REVISION(2, 3))
QML_ATTACHED(QQuickWindowAttached)
QML_NAMED_ELEMENT(Window)
@@ -84,7 +85,7 @@ public:
QQuickWindowQmlImpl(QWindow *parent = nullptr);
void setVisible(bool visible);
- void setVisibility(Visibility visibility);
+ void setVisibility(QWindow::Visibility visibility);
QObject *screen() const;
void setScreen(QObject *screen);
diff --git a/src/quick/qtquickglobal_p.h b/src/quick/qtquickglobal_p.h
index 797d9f169a..0ef394e739 100644
--- a/src/quick/qtquickglobal_p.h
+++ b/src/quick/qtquickglobal_p.h
@@ -72,6 +72,36 @@ Q_DECLARE_LOGGING_CATEGORY(lcMouse)
Q_DECLARE_LOGGING_CATEGORY(lcFocus)
Q_DECLARE_LOGGING_CATEGORY(lcDirty)
+/*
+ This is needed for QuickTestUtils. Q_AUTOTEST_EXPORT checks QT_BUILDING_QT
+ (amongst others) to see if it should export symbols. Until QuickTestUtils
+ was introduced, this was enough, as there weren't any intermediate test
+ helper libraries that used a Qt library and were in turn used by tests.
+
+ Taking QQuickItemViewPrivate as an example: previously it was using
+ Q_AUTOTEST_EXPORT. Since QuickTestUtils is a Qt library (albeit a private
+ one), QT_BUILDING_QT was true and so Q_AUTOTEST_EXPORT evaluated to an
+ export. However, QQuickItemViewPrivate was already exported by the Quick
+ library, so we would get errors like this:
+
+ Qt6Quickd.lib(Qt6Quickd.dll) : error LNK2005: "public: static class
+ QQuickItemViewPrivate * __cdecl QQuickItemViewPrivate::get(class QQuickItemView *)"
+ (?get@QQuickItemViewPrivate@@SAPEAV1@PEAVQQuickItemView@@@Z) already defined
+ in Qt6QuickTestUtilsd.lib(viewtestutils.cpp.obj)
+
+ So, to account for the special case of QuickTestUtils, we need to be more
+ specific about which part of Qt we're building; instead of checking if we're
+ building any Qt library at all, check if we're building the Quick library,
+ and only then export.
+*/
+#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILD_QUICK_LIB) && defined(QT_SHARED)
+# define Q_QUICK_AUTOTEST_EXPORT Q_DECL_EXPORT
+#elif defined(QT_BUILD_INTERNAL) && defined(QT_SHARED)
+# define Q_QUICK_AUTOTEST_EXPORT Q_DECL_IMPORT
+#else
+# define Q_QUICK_AUTOTEST_EXPORT
+#endif
+
QT_END_NAMESPACE
#endif // QTQUICKGLOBAL_P_H
diff --git a/src/quick/qtquickplugin.cpp b/src/quick/qtquickplugin.cpp
index e4ceee15a9..eeca8eac5e 100644
--- a/src/quick/qtquickplugin.cpp
+++ b/src/quick/qtquickplugin.cpp
@@ -42,6 +42,9 @@
QT_BEGIN_NAMESPACE
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick);
+Q_GHS_KEEP_REFERENCE(QQuick_initializeModule);
+
class QtQuick2Plugin : public QQmlEngineExtensionPlugin
{
Q_OBJECT
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
index e76baaa632..30b4d7aa47 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedatlastexture.cpp
@@ -173,3 +173,5 @@ QSGTexture *Texture::removedFromAtlas(QRhiResourceUpdateBatch *) const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedatlastexture_p.cpp"
diff --git a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
index 46dc6c5507..d5d22f3677 100644
--- a/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
+++ b/src/quick/scenegraph/compressedtexture/qsgcompressedtexture.cpp
@@ -377,19 +377,20 @@ void QSGCompressedTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdate
return;
}
- QRhiTexture::Flags texFlags;
- if (fmt.isSRGB)
- texFlags |= QRhiTexture::sRGB;
+ if (!m_texture) {
+ QRhiTexture::Flags texFlags;
+ if (fmt.isSRGB)
+ texFlags |= QRhiTexture::sRGB;
- if (!rhi->isTextureFormatSupported(fmt.rhiFormat, texFlags)) {
- qWarning("Unsupported compressed format 0x%x", m_textureData.glInternalFormat());
- return;
- }
+ if (!rhi->isTextureFormatSupported(fmt.rhiFormat, texFlags)) {
+ qCDebug(QSG_LOG_TEXTUREIO, "Compressed texture format possibly unsupported: 0x%x",
+ m_textureData.glInternalFormat());
+ }
- if (!m_texture) {
m_texture = rhi->newTexture(fmt.rhiFormat, m_size, 1, texFlags);
if (!m_texture->create()) {
- qWarning("Failed to create QRhiTexture for compressed data");
+ qWarning("Failed to create QRhiTexture for compressed data with format 0x%x",
+ m_textureData.glInternalFormat());
delete m_texture;
m_texture = nullptr;
return;
@@ -466,3 +467,5 @@ QSize QSGCompressedTextureFactory::textureSize() const
}
QT_END_NAMESPACE
+
+#include "moc_qsgcompressedtexture_p.cpp"
diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
index 6f14d5abff..05a952bc9f 100644
--- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.cpp
@@ -377,3 +377,5 @@ void QSGAbstractRenderer::renderSceneInline()
}
QT_END_NAMESPACE
+
+#include "moc_qsgabstractrenderer_p.cpp"
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index 6d6b2aca23..c6877369c0 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -299,23 +299,23 @@ void ShaderManager::invalidated()
qDeleteAll(rewrittenShaders);
rewrittenShaders.clear();
- qDeleteAll(srbCache);
- srbCache.clear();
-
qDeleteAll(pipelineCache);
pipelineCache.clear();
+
+ qDeleteAll(srbPool);
+ srbPool.clear();
}
void ShaderManager::clearCachedRendererData()
{
- for (ShaderManager::Shader *sms : stockShaders) {
+ for (ShaderManager::Shader *sms : qAsConst(stockShaders)) {
QSGMaterialShader *s = sms->programRhi.program;
if (s) {
QSGMaterialShaderPrivate *sd = QSGMaterialShaderPrivate::get(s);
sd->clearCachedRendererData();
}
}
- for (ShaderManager::Shader *sms : rewrittenShaders) {
+ for (ShaderManager::Shader *sms : qAsConst(rewrittenShaders)) {
QSGMaterialShader *s = sms->programRhi.program;
if (s) {
QSGMaterialShaderPrivate *sd = QSGMaterialShaderPrivate::get(s);
@@ -324,24 +324,6 @@ void ShaderManager::clearCachedRendererData()
}
}
-QRhiShaderResourceBindings *ShaderManager::srb(const ShaderResourceBindingList &bindings)
-{
- auto it = srbCache.constFind(bindings);
- if (it != srbCache.constEnd())
- return *it;
-
- QRhiShaderResourceBindings *srb = context->rhi()->newShaderResourceBindings();
- srb->setBindings(bindings.cbegin(), bindings.cend());
- if (srb->create()) {
- srbCache.insert(bindings, srb);
- } else {
- qWarning("Failed to build srb");
- delete srb;
- srb = nullptr;
- }
- return srb;
-}
-
void qsg_dumpShadowRoots(BatchRootInfo *i, int indent)
{
static int extraIndent = 0;
@@ -918,7 +900,7 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx, QSGRendererInterface::RenderMod
// The shader manager is shared between renderers (think for example Item
// layers that create a new Renderer each) with the same rendercontext (and
// so same QRhi).
- m_shaderManager = ctx->findChild<ShaderManager *>(QStringLiteral("__qt_ShaderManager"), Qt::FindDirectChildrenOnly);
+ m_shaderManager = ctx->findChild<ShaderManager *>(QString(), Qt::FindDirectChildrenOnly);
if (!m_shaderManager) {
m_shaderManager = new ShaderManager(ctx);
m_shaderManager->setObjectName(QStringLiteral("__qt_ShaderManager"));
@@ -928,17 +910,17 @@ Renderer::Renderer(QSGDefaultRenderContext *ctx, QSGRendererInterface::RenderMod
m_batchNodeThreshold = qt_sg_envInt("QSG_RENDERER_BATCH_NODE_THRESHOLD", 64);
m_batchVertexThreshold = qt_sg_envInt("QSG_RENDERER_BATCH_VERTEX_THRESHOLD", 1024);
+ m_srbPoolThreshold = qt_sg_envInt("QSG_RENDERER_SRB_POOL_THRESHOLD", 1024);
if (Q_UNLIKELY(debug_build() || debug_render())) {
- qDebug("Batch thresholds: nodes: %d vertices: %d",
- m_batchNodeThreshold, m_batchVertexThreshold);
+ qDebug("Batch thresholds: nodes: %d vertices: %d Srb pool threshold: %d",
+ m_batchNodeThreshold, m_batchVertexThreshold, m_srbPoolThreshold);
}
}
static void qsg_wipeBuffer(Buffer *buffer)
{
- if (buffer->buf)
- delete buffer->buf;
+ delete buffer->buf;
// The free here is ok because we're in one of two situations.
// 1. We're using the upload pool in which case unmap will have set the
@@ -961,11 +943,6 @@ static void qsg_wipeBatch(Batch *batch, bool separateIndexBuffer)
Renderer::~Renderer()
{
if (m_rhi) {
- // If setExternalRenderPassDescriptor() was called, we have to
- // aggressively invalidate to prevent an object, the lifetime of which
- // we have no control over, staying in the (per-window) caches.
- invalidatePipelineCacheDependency(m_external_rp_desc);
-
// Clean up batches and buffers
const bool separateIndexBuffer = m_context->separateIndexBuffer();
for (int i = 0; i < m_opaqueBatches.size(); ++i)
@@ -976,17 +953,18 @@ Renderer::~Renderer()
qsg_wipeBatch(m_batchPool.at(i), separateIndexBuffer);
}
- for (Node *n : qAsConst(m_nodes))
+ for (Node *n : qAsConst(m_nodes)) {
+ if (n->type() == QSGNode::GeometryNodeType) {
+ Element *e = n->element();
+ if (!e->removed)
+ m_elementsToDelete.add(e);
+ }
m_nodeAllocator.release(n);
+ }
// Remaining elements...
- for (int i=0; i<m_elementsToDelete.size(); ++i) {
- Element *e = m_elementsToDelete.at(i);
- if (e->isRenderNode)
- delete static_cast<RenderNodeElement *>(e);
- else
- m_elementAllocator.release(e);
- }
+ for (int i=0; i<m_elementsToDelete.size(); ++i)
+ releaseElement(m_elementsToDelete.at(i), true);
destroyGraphicsResources();
@@ -1017,6 +995,9 @@ void Renderer::releaseCachedResources()
m_dummyTexture = nullptr;
m_rhi->releaseCachedResources();
+
+ m_vertexUploadPool.resize(0);
+ m_indexUploadPool.resize(0);
}
void Renderer::invalidateAndRecycleBatch(Batch *b)
@@ -1055,8 +1036,11 @@ void Renderer::unmap(Buffer *buffer, bool isIndexBuf)
buffer->buf = m_rhi->newBuffer(QRhiBuffer::Immutable,
isIndexBuf ? QRhiBuffer::IndexBuffer : QRhiBuffer::VertexBuffer,
buffer->size);
- if (!buffer->buf->create())
+ if (!buffer->buf->create()) {
qWarning("Failed to build vertex/index buffer of size %d", buffer->size);
+ delete buffer->buf;
+ buffer->buf = nullptr;
+ }
} else {
bool needsRebuild = false;
if (buffer->buf->size() < buffer->size) {
@@ -1070,16 +1054,23 @@ void Renderer::unmap(Buffer *buffer, bool isIndexBuf)
buffer->nonDynamicChangeCount = 0;
needsRebuild = true;
}
- if (needsRebuild)
- buffer->buf->create();
+ if (needsRebuild) {
+ if (!buffer->buf->create()) {
+ qWarning("Failed to (re)build vertex/index buffer of size %d", buffer->size);
+ delete buffer->buf;
+ buffer->buf = nullptr;
+ }
+ }
}
- if (buffer->buf->type() != QRhiBuffer::Dynamic) {
- m_resourceUpdates->uploadStaticBuffer(buffer->buf,
- 0, buffer->size, buffer->data);
- buffer->nonDynamicChangeCount += 1;
- } else {
- m_resourceUpdates->updateDynamicBuffer(buffer->buf, 0, buffer->size,
- buffer->data);
+ if (buffer->buf) {
+ if (buffer->buf->type() != QRhiBuffer::Dynamic) {
+ m_resourceUpdates->uploadStaticBuffer(buffer->buf,
+ 0, buffer->size, buffer->data);
+ buffer->nonDynamicChangeCount += 1;
+ } else {
+ m_resourceUpdates->updateDynamicBuffer(buffer->buf, 0, buffer->size,
+ buffer->data);
+ }
}
if (m_visualizer->mode() == Visualizer::VisualizeNothing)
buffer->data = nullptr;
@@ -2629,10 +2620,29 @@ static inline bool needsBlendConstant(QRhiGraphicsPipeline::BlendFactor f)
bool Renderer::ensurePipelineState(Element *e, const ShaderManager::Shader *sms, bool depthPostPass)
{
- // In unmerged batches the srbs in the elements are all compatible
- // layout-wise. Note the key's == and qHash implementations: the rp desc and
- // srb are tested for (layout) compatibility, not pointer equality.
- const GraphicsPipelineStateKey k { m_gstate, sms, renderPassDescriptor(), e->srb };
+ // Note the key's == and qHash implementations: the renderpass descriptor
+ // and srb are tested for compatibility, not pointer equality.
+ //
+ // We do not store the srb pointer itself because the ownership stays with
+ // the Element and that can go away more often that we would like it
+ // to. (think scrolling a list view, constantly dropping and creating new
+ // nodes) Rather, use an opaque blob of a few uints and store and compare
+ // that. This works because once the pipeline is built, we will always call
+ // setShaderResources with an explicitly specified srb which is fine even if
+ // e->srb we used here to bake the pipeline is already gone by that point.
+ //
+ // A typical QSGMaterial's serialized srb layout is 8 uints. (uniform buffer
+ // + texture, 4 fields each) Regardless, using an implicitly shared
+ // container is essential here. (won't detach so no more allocs and copies
+ // are done, unless the Element decides to rebake the srb with a different
+ // layout - but then the detach is exactly what we need)
+ //
+ // Same story for the renderpass descriptor: the object can go away but
+ // that's fine because that has no effect on an already built pipeline, and
+ // for comparison we only rely on the serialized blob in order decide if the
+ // render target is compatible with the pipeline.
+
+ const GraphicsPipelineStateKey k = GraphicsPipelineStateKey::create(m_gstate, sms, renderPassDescriptor(), e->srb);
// Note: dynamic state (viewport rect, scissor rect, stencil ref, blend
// constant) is never a part of GraphicsState/QRhiGraphicsPipeline.
@@ -2826,8 +2836,8 @@ static void materialToRendererGraphicsState(GraphicsState *dst,
void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
QSGMaterialShader::RenderState &renderState,
QSGMaterial *material,
- ShaderManager::ShaderResourceBindingList *bindings,
const Batch *batch,
+ Element *e,
int ubufOffset,
int ubufRegionSize)
{
@@ -2835,6 +2845,8 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
QSGMaterialShader *shader = sms->programRhi.program;
QSGMaterialShaderPrivate *pd = QSGMaterialShaderPrivate::get(shader);
+ QVarLengthArray<QRhiShaderResourceBinding, 8> bindings;
+
if (pd->ubufBinding >= 0) {
m_current_uniform_data = &pd->masterUniformData;
const bool changed = shader->updateUniformData(renderState, material, m_currentMaterial);
@@ -2843,11 +2855,11 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
if (changed || !batch->ubufDataValid)
m_resourceUpdates->updateDynamicBuffer(batch->ubuf, ubufOffset, ubufRegionSize, pd->masterUniformData.constData());
- bindings->append(QRhiShaderResourceBinding::uniformBuffer(pd->ubufBinding,
- pd->ubufStages,
- batch->ubuf,
- ubufOffset,
- ubufRegionSize));
+ bindings.append(QRhiShaderResourceBinding::uniformBuffer(pd->ubufBinding,
+ pd->ubufStages,
+ batch->ubuf,
+ ubufOffset,
+ ubufRegionSize));
}
for (int binding = 0; binding < QSGMaterialShaderPrivate::MAX_SHADER_RESOURCE_BINDINGS; ++binding) {
@@ -2901,17 +2913,92 @@ void Renderer::updateMaterialDynamicData(ShaderManager::Shader *sms,
if (!texture)
texture = dummyTexture();
QRhiSampler *sampler = pd->samplerBindingTable[binding];
- bindings->append(QRhiShaderResourceBinding::sampledTexture(binding,
- stages,
- texture,
- sampler));
+ bindings.append(QRhiShaderResourceBinding::sampledTexture(binding,
+ stages,
+ texture,
+ sampler));
}
}
#ifndef QT_NO_DEBUG
- if (bindings->isEmpty())
+ if (bindings.isEmpty())
qWarning("No shader resources for material %p, this is odd.", material);
#endif
+
+ enum class SrbAction {
+ Unknown,
+ DoNothing,
+ UpdateResources,
+ Rebake
+ } srbAction = SrbAction::Unknown;
+
+ // First, if the Element has no srb created at all, then try to find an existing,
+ // currently unused srb that is layout-compatible with our binding list.
+ if (!e->srb) {
+ // reuse a QVector as our work area, thus possibly reusing the underlying allocation too
+ QVector<quint32> &layoutDesc(m_shaderManager->srbLayoutDescSerializeWorkspace);
+ layoutDesc.clear();
+ QRhiShaderResourceBinding::serializeLayoutDescription(bindings.cbegin(), bindings.cend(), std::back_inserter(layoutDesc));
+ e->srb = m_shaderManager->srbPool.take(layoutDesc);
+ if (e->srb) {
+ // Here we know layout compatibility is satisfied, but do not spend time on full
+ // comparison. The chance of getting an srb that refers to the same resources
+ // (buffer, textures) is low in practice. So reuse, but write new resources.
+ srbAction = SrbAction::UpdateResources;
+ }
+ }
+
+ // If the Element had an existing srb, investigate:
+ // - It may be used as-is (when nothing changed in the scene regarding this node compared to the previous frame).
+ // - Otherwise it may be able to go with a lightweight update (replace resources, binding list layout is the same).
+ // - If all else fails rebake the full thing, meaning we reuse the memory allocation but will recreate everything underneath.
+ if (srbAction == SrbAction::Unknown && e->srb) {
+ if (std::equal(e->srb->cbeginBindings(), e->srb->cendBindings(), bindings.cbegin(), bindings.cend())) {
+ srbAction = SrbAction::DoNothing;
+ } else if (std::equal(e->srb->cbeginBindings(), e->srb->cendBindings(), bindings.cbegin(), bindings.cend(),
+ [](const auto &a, const auto &b) { return a.isLayoutCompatible(b); }))
+ {
+ srbAction = SrbAction::UpdateResources;
+ } else {
+ srbAction = SrbAction::Rebake;
+ }
+ }
+
+ // If the Element had no srb associated at all and could not find a layout-compatible
+ // one from the pool, then create a whole new object.
+ if (!e->srb) {
+ e->srb = m_rhi->newShaderResourceBindings();
+ srbAction = SrbAction::Rebake;
+ }
+
+ Q_ASSERT(srbAction != SrbAction::Unknown && e->srb);
+
+ switch (srbAction) {
+ case SrbAction::DoNothing:
+ break;
+ case SrbAction::UpdateResources:
+ {
+ e->srb->setBindings(bindings.cbegin(), bindings.cend());
+ QRhiShaderResourceBindings::UpdateFlags flags;
+ // Due to the way the binding list is built up above, if we have a uniform buffer
+ // at binding point 0 (or none at all) then the sampledTexture bindings are added
+ // with increasing binding points afterwards, so the list is already sorted based
+ // on the binding points, thus we can save some time by telling the QRhi backend
+ // not to sort again.
+ if (pd->ubufBinding <= 0 || bindings.count() <= 1)
+ flags |= QRhiShaderResourceBindings::BindingsAreSorted;
+
+ e->srb->updateResources(flags);
+ }
+ break;
+ case SrbAction::Rebake:
+ e->srb->setBindings(bindings.cbegin(), bindings.cend());
+ if (!e->srb->create())
+ qWarning("Failed to build srb");
+ break;
+ default:
+ Q_ASSERT_X(false, "updateMaterialDynamicData", "No srb action set, this cannot happen");
+ }
}
void Renderer::updateMaterialStaticData(ShaderManager::Shader *sms,
@@ -3029,8 +3116,7 @@ bool Renderer::prepareRenderMergedBatch(Batch *batch, PreparedRenderBatch *rende
bool pendingGStatePop = false;
updateMaterialStaticData(sms, renderState, material, batch, &pendingGStatePop);
- ShaderManager::ShaderResourceBindingList bindings;
- updateMaterialDynamicData(sms, renderState, material, &bindings, batch, 0, ubufSize);
+ updateMaterialDynamicData(sms, renderState, material, batch, e, 0, ubufSize);
#ifndef QT_NO_DEBUG
if (qsg_test_and_clear_material_failure()) {
@@ -3045,8 +3131,6 @@ bool Renderer::prepareRenderMergedBatch(Batch *batch, PreparedRenderBatch *rende
}
#endif
- e->srb = m_shaderManager->srb(bindings);
-
m_gstate.drawMode = QSGGeometry::DrawingMode(g->drawingMode());
m_gstate.lineWidth = g->lineWidth();
@@ -3103,6 +3187,9 @@ void Renderer::checkLineWidth(QSGGeometry *g)
void Renderer::renderMergedBatch(PreparedRenderBatch *renderBatch, bool depthPostPass)
{
const Batch *batch = renderBatch->batch;
+ if (!batch->vbo.buf || !batch->ibo.buf)
+ return;
+
Element *e = batch->first;
QSGGeometryNode *gn = e->node;
QSGGeometry *g = gn->geometry();
@@ -3232,9 +3319,7 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren
}
QSGMaterialShader::RenderState renderState = state(QSGMaterialShader::RenderState::DirtyStates(int(dirty)));
- ShaderManager::ShaderResourceBindingList bindings;
- updateMaterialDynamicData(sms, renderState,
- material, &bindings, batch, ubufOffset, ubufSize);
+ updateMaterialDynamicData(sms, renderState, material, batch, e, ubufOffset, ubufSize);
#ifndef QT_NO_DEBUG
if (qsg_test_and_clear_material_failure()) {
@@ -3246,8 +3331,6 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren
}
#endif
- e->srb = m_shaderManager->srb(bindings);
-
ubufOffset += aligned(ubufSize, m_ubufAlignment);
const QSGGeometry::DrawingMode prevDrawMode = m_gstate.drawMode;
@@ -3302,8 +3385,10 @@ bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *ren
void Renderer::renderUnmergedBatch(PreparedRenderBatch *renderBatch, bool depthPostPass)
{
const Batch *batch = renderBatch->batch;
+ if (!batch->vbo.buf)
+ return;
+
Element *e = batch->first;
- QSGGeometryNode *gn = e->node;
if (batch->clipState.type & ClipState::StencilClip)
enqueueStencilDraw(batch);
@@ -3313,8 +3398,7 @@ void Renderer::renderUnmergedBatch(PreparedRenderBatch *renderBatch, bool depthP
QRhiCommandBuffer *cb = commandBuffer();
while (e) {
- gn = e->node;
- QSGGeometry *g = gn->geometry();
+ QSGGeometry *g = e->node->geometry();
checkLineWidth(g);
const int effectiveIndexSize = m_uint32IndexForRhi ? sizeof(quint32) : g->sizeOfIndex();
@@ -3322,11 +3406,13 @@ void Renderer::renderUnmergedBatch(PreparedRenderBatch *renderBatch, bool depthP
const QRhiCommandBuffer::VertexInput vbufBinding(batch->vbo.buf, vOffset);
if (g->indexCount()) {
- cb->setVertexInput(VERTEX_BUFFER_BINDING, 1, &vbufBinding,
- batch->ibo.buf, iOffset,
- effectiveIndexSize == sizeof(quint32) ? QRhiCommandBuffer::IndexUInt32
- : QRhiCommandBuffer::IndexUInt16);
- cb->drawIndexed(g->indexCount());
+ if (batch->ibo.buf) {
+ cb->setVertexInput(VERTEX_BUFFER_BINDING, 1, &vbufBinding,
+ batch->ibo.buf, iOffset,
+ effectiveIndexSize == sizeof(quint32) ? QRhiCommandBuffer::IndexUInt32
+ : QRhiCommandBuffer::IndexUInt16);
+ cb->drawIndexed(g->indexCount());
+ }
} else {
cb->setVertexInput(VERTEX_BUFFER_BINDING, 1, &vbufBinding);
cb->draw(g->vertexCount());
@@ -3372,6 +3458,26 @@ void Renderer::setGraphicsPipeline(QRhiCommandBuffer *cb, const Batch *batch, El
cb->setShaderResources(e->srb);
}
+void Renderer::releaseElement(Element *e, bool inDestructor)
+{
+ if (e->isRenderNode) {
+ delete static_cast<RenderNodeElement *>(e);
+ } else {
+ if (e->srb) {
+ if (!inDestructor) {
+ if (m_shaderManager->srbPool.count() < m_srbPoolThreshold)
+ m_shaderManager->srbPool.insert(e->srb->serializedLayoutDescription(), e->srb);
+ else
+ delete e->srb;
+ } else {
+ delete e->srb;
+ }
+ e->srb = nullptr;
+ }
+ m_elementAllocator.release(e);
+ }
+}
+
void Renderer::deleteRemovedElements()
{
if (!m_elementsToDelete.size())
@@ -3388,13 +3494,9 @@ void Renderer::deleteRemovedElements()
*e = nullptr;
}
- for (int i=0; i<m_elementsToDelete.size(); ++i) {
- Element *e = m_elementsToDelete.at(i);
- if (e->isRenderNode)
- delete static_cast<RenderNodeElement *>(e);
- else
- m_elementAllocator.release(e);
- }
+ for (int i=0; i<m_elementsToDelete.size(); ++i)
+ releaseElement(m_elementsToDelete.at(i));
+
m_elementsToDelete.reset();
}
@@ -3903,22 +4005,6 @@ bool Renderer::hasVisualizationModeWithContinuousUpdate() const
return m_visualizer->mode() == Visualizer::VisualizeOverdraw;
}
-void Renderer::invalidatePipelineCacheDependency(QRhiRenderPassDescriptor *rpDesc)
-{
- if (!rpDesc)
- return;
-
- for (auto it = m_shaderManager->pipelineCache.begin(); it != m_shaderManager->pipelineCache.end(); ) {
- if (it.key().compatibleRenderPassDescriptor == rpDesc) {
- QRhiGraphicsPipeline *ps = it.value();
- it = m_shaderManager->pipelineCache.erase(it);
- ps->deleteLater(); // QRhi takes care of it in endFrame()
- } else {
- ++it;
- }
- }
-}
-
bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept
{
return a.depthTest == b.depthTest
@@ -3960,8 +4046,8 @@ bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKe
{
return a.state == b.state
&& a.sms->programRhi.program == b.sms->programRhi.program
- && a.compatibleRenderPassDescriptor->isCompatible(b.compatibleRenderPassDescriptor)
- && a.layoutCompatibleSrb->isLayoutCompatible(b.layoutCompatibleSrb);
+ && a.renderTargetDescription == b.renderTargetDescription
+ && a.srbLayoutDescription == b.srbLayoutDescription;
}
bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept
@@ -3971,8 +4057,10 @@ bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKe
size_t qHash(const GraphicsPipelineStateKey &k, size_t seed) noexcept
{
- // no srb and rp included due to their special comparison semantics and lack of hash keys
- return qHash(k.state, seed) + qHash(k.sms->programRhi.program, seed);
+ return qHash(k.state, seed)
+ ^ qHash(k.sms->programRhi.program)
+ ^ k.extra.renderTargetDescriptionHash
+ ^ k.extra.srbLayoutDescriptionHash;
}
Visualizer::Visualizer(Renderer *renderer)
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index a42c41304f..241f5748b6 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -652,8 +652,21 @@ struct GraphicsPipelineStateKey
{
GraphicsState state;
const ShaderManagerShader *sms;
- const QRhiRenderPassDescriptor *compatibleRenderPassDescriptor;
- const QRhiShaderResourceBindings *layoutCompatibleSrb;
+ QVector<quint32> renderTargetDescription;
+ QVector<quint32> srbLayoutDescription;
+ struct {
+ size_t renderTargetDescriptionHash;
+ size_t srbLayoutDescriptionHash;
+ } extra;
+ static GraphicsPipelineStateKey create(const GraphicsState &state,
+ const ShaderManagerShader *sms,
+ const QRhiRenderPassDescriptor *rpDesc,
+ const QRhiShaderResourceBindings *srb)
+ {
+ const QVector<quint32> rtDesc = rpDesc->serializedFormat();
+ const QVector<quint32> srbDesc = srb->serializedLayoutDescription();
+ return { state, sms, rtDesc, srbDesc, { qHash(rtDesc), qHash(srbDesc) } };
+ }
};
bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept;
@@ -687,11 +700,11 @@ public:
void clearCachedRendererData();
- using ShaderResourceBindingList = QVarLengthArray<QRhiShaderResourceBinding, 8>;
- QRhiShaderResourceBindings *srb(const ShaderResourceBindingList &bindings);
-
QHash<GraphicsPipelineStateKey, QRhiGraphicsPipeline *> pipelineCache;
+ QMultiHash<QVector<quint32>, QRhiShaderResourceBindings *> srbPool;
+ QVector<quint32> srbLayoutDescSerializeWorkspace;
+
public Q_SLOTS:
void invalidated();
@@ -705,8 +718,6 @@ private:
QHash<ShaderKey, Shader *> stockShaders;
QSGDefaultRenderContext *context;
-
- QHash<ShaderResourceBindingList, QRhiShaderResourceBindings *> srbCache;
};
struct RenderPassState
@@ -822,8 +833,7 @@ private:
bool ensurePipelineState(Element *e, const ShaderManager::Shader *sms, bool depthPostPass = false);
QRhiTexture *dummyTexture();
void updateMaterialDynamicData(ShaderManager::Shader *sms, QSGMaterialShader::RenderState &renderState,
- QSGMaterial *material, ShaderManager::ShaderResourceBindingList *bindings,
- const Batch *batch, int ubufOffset, int ubufRegionSize);
+ QSGMaterial *material, const Batch *batch, Element *e, int ubufOffset, int ubufRegionSize);
void updateMaterialStaticData(ShaderManager::Shader *sms, QSGMaterialShader::RenderState &renderState,
QSGMaterial *material, Batch *batch, bool *gstateChanged);
void checkLineWidth(QSGGeometry *g);
@@ -858,12 +868,11 @@ private:
inline Batch *newBatch();
void invalidateAndRecycleBatch(Batch *b);
+ void releaseElement(Element *e, bool inDestructor = false);
void setVisualizationMode(const QByteArray &mode) override;
bool hasVisualizationModeWithContinuousUpdate() const override;
- void invalidatePipelineCacheDependency(QRhiRenderPassDescriptor *rpDesc) override;
-
QSGDefaultRenderContext *m_context;
QSGRendererInterface::RenderMode m_renderMode;
QSet<Node *> m_taggedRoots;
@@ -893,6 +902,7 @@ private:
int m_batchNodeThreshold;
int m_batchVertexThreshold;
+ int m_srbPoolThreshold;
Visualizer *m_visualizer;
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp
index c8ecf49767..cf369f55a6 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.cpp
+++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp
@@ -406,8 +406,10 @@ const QSGGeometry::AttributeSet &QSGGeometry::defaultAttributes_ColoredPoint2D()
Geometry objects are constructed by default with DrawTriangleStrip as
the drawing mode.
- The attribute structure is assumed to be POD and the geometry object
- assumes this will not go away. There is no memory management involved.
+ \note \a attributes and the \l Attribute objects referenced by it must
+ stay valid for the entire lifetime of the QSGGeometry.
+ QSGGeometry stores a reference to \a attributes and does not delete
+ the \l Attribute objects.
*/
QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes,
diff --git a/src/quick/scenegraph/coreapi/qsggeometry.h b/src/quick/scenegraph/coreapi/qsggeometry.h
index 060d896b3c..82b930edf2 100644
--- a/src/quick/scenegraph/coreapi/qsggeometry.h
+++ b/src/quick/scenegraph/coreapi/qsggeometry.h
@@ -201,6 +201,7 @@ public:
void setLineWidth(float w);
private:
+ Q_DISABLE_COPY_MOVE(QSGGeometry)
friend class QSGGeometryData;
int m_drawing_mode;
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index e22ffa10d2..46637b326e 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -78,8 +78,8 @@ static void qt_print_node_count()
insertChildNodeAfter(). The order of nodes is important as geometry nodes
are rendered according to their ordering in the scene graph.
- The scene graph nodes contains a mechanism to describe which
- parts of the scene has changed. This includes the combined matrices,
+ The scene graph nodes contain a mechanism that describes which
+ parts of the scene have changed. This includes the combined matrices,
accumulated opacity, changes to the node hierarchy, and so on. This
information can be used for optimizations inside the scene graph renderer.
For the renderer to properly render the nodes, it is important that users
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 4b3cd9f2c1..277e5b8482 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -55,7 +55,7 @@ int qt_sg_envInt(const char *name, int defaultValue)
if (Q_LIKELY(!qEnvironmentVariableIsSet(name)))
return defaultValue;
bool ok = false;
- int value = qgetenv(name).toInt(&ok);
+ int value = qEnvironmentVariableIntValue(name, &ok);
return ok ? value : defaultValue;
}
@@ -98,7 +98,6 @@ QSGRenderer::QSGRenderer(QSGRenderContext *context)
, m_rt(nullptr)
, m_cb(nullptr)
, m_rp_desc(nullptr)
- , m_external_rp_desc(nullptr)
, m_node_updater(nullptr)
, m_changed_emitted(false)
, m_is_rendering(false)
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index 31f00dc738..9f1ab6a99b 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -97,7 +97,6 @@ public:
virtual void setVisualizationMode(const QByteArray &) { }
virtual bool hasVisualizationModeWithContinuousUpdate() const { return false; }
virtual void releaseCachedResources() { }
- virtual void invalidatePipelineCacheDependency(QRhiRenderPassDescriptor *) { }
void clearChangedFlag() { m_changed_emitted = false; }
@@ -116,15 +115,8 @@ public:
QRhiRenderPassDescriptor *renderPassDescriptor() const { return m_rp_desc; }
void setExternalRenderPassDescriptor(QRhiRenderPassDescriptor *rpDesc) {
- if (m_external_rp_desc) {
- // Changes will be rare in practice - one has to construct a
- // dynamic Quick 3D scene with reparenting involved for that. Play
- // nice nonetheless and invalidate as soon as possible.
- if (m_external_rp_desc != rpDesc)
- invalidatePipelineCacheDependency(m_external_rp_desc);
- }
- m_rp_desc = rpDesc;
- m_external_rp_desc = rpDesc;
+ // no differentiation needed anymore
+ setRenderPassDescriptor(rpDesc);
}
void setRenderPassRecordingCallbacks(QSGRenderContext::RenderPassCallback start,
@@ -162,7 +154,6 @@ protected:
QRhiRenderTarget *m_rt;
QRhiCommandBuffer *m_cb;
QRhiRenderPassDescriptor *m_rp_desc;
- QRhiRenderPassDescriptor *m_external_rp_desc;
struct {
QSGRenderContext::RenderPassCallback start = nullptr;
QSGRenderContext::RenderPassCallback end = nullptr;
diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
index ec8e3dda57..403206abc5 100644
--- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp
@@ -239,13 +239,14 @@ void QSGRenderNode::prepare()
Assume nothing about the pipelines and dynamic states bound on the command
list/buffer when this function is called.
- With some graphics APIs it can be necessary to also connect to the
- QQuickWindow::beforeRendering() signal, because that is emitted before
- recording the beginning of a renderpass on the command buffer
- (vkCmdBeginRenderPass with Vulkan, or starting to encode via
- MTLRenderCommandEncoder in case of Metal). Recording copy operations cannot
- be done inside render() with such APIs. Rather, do it in the slot connected
- (with DirectConnection) to the beforeRendering signal.
+ With some graphics APIs it can be necessary to reimplement prepare() in
+ addition, or alternatively connect to the QQuickWindow::beforeRendering()
+ signal. These are called/emitted before recording the beginning of a
+ renderpass on the command buffer (vkCmdBeginRenderPass with Vulkan, or
+ starting to encode via MTLRenderCommandEncoder in case of Metal. Recording
+ copy operations cannot be done inside render() with such APIs. Rather, do
+ such operations either in prepare() or the slot connected to
+ beforeRendering (with DirectConnection).
\sa QSGRendererInterface, QQuickWindow::rendererInterface()
*/
diff --git a/src/quick/scenegraph/coreapi/qsgtexture.cpp b/src/quick/scenegraph/coreapi/qsgtexture.cpp
index d70a9664ba..b79999c3ea 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture.cpp
+++ b/src/quick/scenegraph/coreapi/qsgtexture.cpp
@@ -43,6 +43,7 @@
#include <private/qsgmaterialshader_p.h>
#include <private/qquickitem_p.h> // qquickwindow_p.h cannot be included on its own due to template nonsense
#include <private/qquickwindow_p.h>
+#include <QtCore/private/qnativeinterface_p.h>
#include <QtGui/private/qrhi_p.h>
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) && defined(__GLIBC__)
@@ -715,6 +716,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting OpenGL texture objects.
\since 6.0
*/
@@ -815,6 +817,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Direct3D 11 texture objects.
\since 6.0
*/
@@ -875,6 +878,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Metal texture objects.
\since 6.0
*/
@@ -922,6 +926,7 @@ namespace QNativeInterface {
\inmodule QtQuick
\ingroup native-interfaces
\ingroup native-interfaces-qsgtexture
+ \inheaderfile QSGTexture
\brief Provides access to and enables adopting Vulkan image objects.
\since 6.0
*/
diff --git a/src/quick/scenegraph/coreapi/qsgtexture_mac.mm b/src/quick/scenegraph/coreapi/qsgtexture_mac.mm
index 9d009eb5cb..7ead16f14f 100644
--- a/src/quick/scenegraph/coreapi/qsgtexture_mac.mm
+++ b/src/quick/scenegraph/coreapi/qsgtexture_mac.mm
@@ -41,6 +41,7 @@
#include "qsgtexture_platform.h"
#include <private/qquickitem_p.h>
#include <private/qquickwindow_p.h>
+#include <QtCore/private/qnativeinterface_p.h>
#include <QtGui/private/qrhi_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index ee0dc95945..c3d286ee9d 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -353,6 +353,7 @@ public:
};
ShaderSyncData vertex;
ShaderSyncData fragment;
+ void *materialTypeCacheKey;
};
// Each ShaderEffect item has one node (render thread) and one manager (gui thread).
@@ -463,9 +464,9 @@ public:
{
return pixelSize / baseFontSize();
}
- int distanceFieldRadius() const
+ qreal distanceFieldRadius() const
{
- return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution);
+ return QT_DISTANCEFIELD_RADIUS(m_doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_doubleGlyphResolution));
}
int glyphCount() const { return m_glyphCount; }
bool doubleGlyphResolution() const { return m_doubleGlyphResolution; }
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 578b5ab2f2..df0592cad1 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -111,6 +111,18 @@ QSGTextMaskRhiShader::QSGTextMaskRhiShader(QFontEngine::GlyphFormat glyphFormat)
QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/textmask.frag.qsb"));
}
+enum UbufOffset {
+ ModelViewMatrixOffset = 0,
+ ProjectionMatrixOffset = ModelViewMatrixOffset + 64,
+ ColorOffset = ProjectionMatrixOffset + 64,
+ TextureScaleOffset = ColorOffset + 16,
+ DprOffset = TextureScaleOffset + 8,
+
+ // + 1 float padding (vec4 must be aligned to 16)
+ StyleColorOffset = DprOffset + 4 + 4,
+ ShiftOffset = StyleColorOffset + 16
+};
+
bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
@@ -126,11 +138,14 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
bool changed = false;
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= DprOffset + 4);
if (state.isMatrixDirty()) {
- const QMatrix4x4 m = state.combinedMatrix();
- memcpy(buf->data(), m.constData(), 64);
+ const QMatrix4x4 mv = state.modelViewMatrix();
+ memcpy(buf->data() + ModelViewMatrixOffset, mv.constData(), 64);
+ const QMatrix4x4 p = state.projectionMatrix();
+ memcpy(buf->data() + ProjectionMatrixOffset, p.constData(), 64);
+
changed = true;
}
@@ -139,13 +154,13 @@ bool QSGTextMaskRhiShader::updateUniformData(RenderState &state,
if (updated || !oldMat || oldRtex != newRtex) {
const QVector2D textureScale = QVector2D(1.0f / mat->rhiGlyphCache()->width(),
1.0f / mat->rhiGlyphCache()->height());
- memcpy(buf->data() + 64 + 16, &textureScale, 8);
+ memcpy(buf->data() + TextureScaleOffset, &textureScale, 8);
changed = true;
}
if (!oldMat) {
float dpr = state.devicePixelRatio();
- memcpy(buf->data() + 64 + 16 + 8, &dpr, 4);
+ memcpy(buf->data() + DprOffset, &dpr, 4);
}
// move texture uploads/copies onto the renderer's soon-to-be-committed list
@@ -193,11 +208,11 @@ bool QSG8BitTextMaskRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 80);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -236,12 +251,12 @@ bool QSG24BitTextMaskRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
// shader takes vec4 but uses alpha only; coloring happens via the blend constant
const QVector4D color = qsg_premultiply(mat->color(), state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -259,7 +274,8 @@ bool QSG24BitTextMaskRhiShader::updateGraphicsPipelineState(RenderState &state,
ps->srcColor = GraphicsPipelineState::ConstantColor;
ps->dstColor = GraphicsPipelineState::OneMinusSrcColor;
- QVector4D color = qsg_premultiply(mat->color(), state.opacity());
+ QVector4D color = mat->color();
+
// if (useSRGB())
// color = qt_sRGB_to_linear_RGB(color);
@@ -291,12 +307,12 @@ bool QSG32BitColorTextRhiShader::updateUniformData(RenderState &state,
QSGTextMaskMaterial *oldMat = static_cast<QSGTextMaskMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 92);
+ Q_ASSERT(buf->size() >= ColorOffset + 16);
if (oldMat == nullptr || mat->color() != oldMat->color() || state.isOpacityDirty()) {
// shader takes vec4 but uses alpha only
const QVector4D color(0, 0, 0, mat->color().w() * state.opacity());
- memcpy(buf->data() + 64, &color, 16);
+ memcpy(buf->data() + ColorOffset, &color, 16);
changed = true;
}
@@ -332,20 +348,17 @@ bool QSGStyledTextRhiShader::updateUniformData(RenderState &state,
QSGStyledTextMaterial *oldMat = static_cast<QSGStyledTextMaterial *>(oldMaterial);
QByteArray *buf = state.uniformData();
- Q_ASSERT(buf->size() >= 120);
-
- // matrix..dpr + 1 float padding (vec4 must be aligned to 16)
- const int startOffset = 64 + 16 + 8 + 4 + 4;
+ Q_ASSERT(buf->size() >= ShiftOffset + 8);
if (oldMat == nullptr || mat->styleColor() != oldMat->styleColor() || state.isOpacityDirty()) {
const QVector4D styleColor = qsg_premultiply(mat->styleColor(), state.opacity());
- memcpy(buf->data() + startOffset, &styleColor, 16);
+ memcpy(buf->data() + StyleColorOffset, &styleColor, 16);
changed = true;
}
if (oldMat == nullptr || oldMat->styleShift() != mat->styleShift()) {
const QVector2D v = mat->styleShift();
- memcpy(buf->data() + startOffset + 16, &v, 8);
+ memcpy(buf->data() + ShiftOffset, &v, 8);
changed = true;
}
@@ -444,7 +457,7 @@ void QSGTextMaskMaterial::updateCache(QFontEngine::GlyphFormat glyphFormat)
QColor color = glyphFormat == QFontEngine::Format_ARGB ? QColor::fromRgbF(m_color.x(), m_color.y(), m_color.z(), m_color.w()) : QColor();
m_glyphCache = fontEngine->glyphCache(cacheKey, glyphFormat, glyphCacheTransform, color);
if (!m_glyphCache || int(m_glyphCache->glyphFormat()) != glyphFormat) {
- m_glyphCache = new QSGRhiTextureGlyphCache(m_rhi, glyphFormat, glyphCacheTransform, color);
+ m_glyphCache = new QSGRhiTextureGlyphCache(m_rc, glyphFormat, glyphCacheTransform, color);
fontEngine->setGlyphCache(cacheKey, m_glyphCache.data());
m_rc->registerFontengineForCleanup(fontEngine);
}
@@ -470,8 +483,12 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
QTextureGlyphCache *cache = glyphCache();
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
- cache->populate(fontD->fontEngine, glyphIndexes.size(), glyphIndexes.constData(),
- fixedPointPositions.data());
+ cache->populate(fontD->fontEngine,
+ glyphIndexes.size(),
+ glyphIndexes.constData(),
+ fixedPointPositions.data(),
+ QPainter::RenderHints(),
+ true);
cache->fillInPendingGlyphs();
int margin = fontD->fontEngine->glyphMargin(cache->glyphFormat());
@@ -491,9 +508,11 @@ void QSGTextMaskMaterial::populate(const QPointF &p,
bool supportsSubPixelPositions = fontD->fontEngine->supportsHorizontalSubPixelPositions();
for (int i=0; i<glyphIndexes.size(); ++i) {
QPointF glyphPosition = glyphPositions.at(i) + position;
+ QFixedPoint fixedPointPosition = fixedPointPositions.at(i);
+
QFixed subPixelPosition;
if (supportsSubPixelPositions)
- subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(glyphPosition.x()));
+ subPixelPosition = fontD->fontEngine->subPixelPositionForX(QFixed::fromReal(fixedPointPosition.x.toReal() * glyphCacheScaleX));
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphIndexes.at(i),
QFixedPoint(subPixelPosition, 0));
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
index 1b2dbab84f..8579cb5e2a 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp
+++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp
@@ -64,6 +64,7 @@ QSGDefaultRenderContext::QSGDefaultRenderContext(QSGContext *context)
, m_currentFrameRenderPass(nullptr)
, m_separateIndexBuffer(false)
, m_useDepthBufferFor2D(true)
+ , m_glyphCacheResourceUpdates(nullptr)
{
}
@@ -89,6 +90,8 @@ void QSGDefaultRenderContext::initialize(const QSGRenderContext::InitParams *par
// unlike OpenGL (and like WebGL), QRhi does not guarantee buffer usage types can be mixed
m_separateIndexBuffer = true;
+ m_glyphCacheResourceUpdates = nullptr;
+
m_sg->renderContextInitialized(this);
emit initialized();
@@ -140,10 +143,11 @@ void QSGDefaultRenderContext::invalidate()
}
m_fontEnginesToClean.clear();
-
qDeleteAll(m_glyphCaches);
m_glyphCaches.clear();
+ releaseGlyphCacheResourceUpdates();
+
m_rhi = nullptr;
if (m_sg)
@@ -296,13 +300,34 @@ QSGDistanceFieldGlyphCache *QSGDefaultRenderContext::distanceFieldGlyphCache(con
QString key = fontKey(font, renderTypeQuality);
QSGDistanceFieldGlyphCache *cache = m_glyphCaches.value(key, 0);
if (!cache) {
- cache = new QSGRhiDistanceFieldGlyphCache(m_rhi, font, renderTypeQuality);
+ cache = new QSGRhiDistanceFieldGlyphCache(this, font, renderTypeQuality);
m_glyphCaches.insert(key, cache);
}
return cache;
}
+QRhiResourceUpdateBatch *QSGDefaultRenderContext::maybeGlyphCacheResourceUpdates()
+{
+ return m_glyphCacheResourceUpdates;
+}
+
+QRhiResourceUpdateBatch *QSGDefaultRenderContext::glyphCacheResourceUpdates()
+{
+ if (!m_glyphCacheResourceUpdates)
+ m_glyphCacheResourceUpdates = m_rhi->nextResourceUpdateBatch();
+
+ return m_glyphCacheResourceUpdates;
+}
+
+void QSGDefaultRenderContext::releaseGlyphCacheResourceUpdates()
+{
+ if (m_glyphCacheResourceUpdates) {
+ m_glyphCacheResourceUpdates->release();
+ m_glyphCacheResourceUpdates = nullptr;
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qsgdefaultrendercontext_p.cpp"
diff --git a/src/quick/scenegraph/qsgdefaultrendercontext_p.h b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
index 002513c0e4..e96bf045b5 100644
--- a/src/quick/scenegraph/qsgdefaultrendercontext_p.h
+++ b/src/quick/scenegraph/qsgdefaultrendercontext_p.h
@@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
class QRhi;
class QRhiCommandBuffer;
class QRhiRenderPassDescriptor;
+class QRhiResourceUpdateBatch;
class QSGMaterialShader;
class QSurface;
@@ -143,6 +144,10 @@ public:
return m_currentDevicePixelRatio;
}
+ QRhiResourceUpdateBatch *maybeGlyphCacheResourceUpdates();
+ QRhiResourceUpdateBatch *glyphCacheResourceUpdates();
+ void releaseGlyphCacheResourceUpdates();
+
protected:
static QString fontKey(const QRawFont &font, int renderTypeQuality);
@@ -156,6 +161,7 @@ protected:
qreal m_currentDevicePixelRatio;
bool m_separateIndexBuffer;
bool m_useDepthBufferFor2D;
+ QRhiResourceUpdateBatch *m_glyphCacheResourceUpdates;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index 8ac112b106..4c6589d1f9 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -43,6 +43,10 @@
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(lcSgText, "qt.scenegraph.text")
+
+qint64 QSGDistanceFieldGlyphNode::m_totalAllocation = 0;
+
QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGRenderContext *context)
: m_glyphNodeType(RootGlyphNode)
, m_context(context)
@@ -135,6 +139,9 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR
const QVector<quint32> glyphIndexes = m_glyphs.glyphIndexes();
for (int i = 0; i < glyphIndexes.count(); ++i)
m_allGlyphIndexesLookup.insert(glyphIndexes.at(i));
+ qCDebug(lcSgText, "inserting %" PRIdQSIZETYPE " glyphs, %" PRIdQSIZETYPE " unique",
+ glyphIndexes.count(),
+ m_allGlyphIndexesLookup.count());
}
void QSGDistanceFieldGlyphNode::setStyle(QQuickText::TextStyle style)
@@ -198,8 +205,7 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
QSGGeometry *g = geometry();
Q_ASSERT(g->indexType() == QSGGeometry::UnsignedShortType);
-
- QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo> glyphsInOtherTextures;
+ m_glyphsInOtherTextures.clear();
const QVector<quint32> indexes = m_glyphs.glyphIndexes();
const QVector<QPointF> positions = m_glyphs.positions();
@@ -208,9 +214,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
// The template parameters here are assuming that most strings are short, 64
// characters or less.
QVarLengthArray<QSGGeometry::TexturedPoint2D, 256> vp;
- vp.reserve(indexes.size() * 4);
QVarLengthArray<ushort, 384> ip;
- ip.reserve(indexes.size() * 6);
+ const qsizetype maxIndexCount = (std::numeric_limits<quint16>::max() - 1) / 4; // 16383 (see below: 0xFFFF is not allowed)
+ const qsizetype maxVertexCount = maxIndexCount * 4; // 65532
+ const auto likelyGlyphCount = qMin(indexes.size(), maxIndexCount);
+ vp.reserve(likelyGlyphCount * 4);
+ ip.reserve(likelyGlyphCount * 6);
qreal maxTexMargin = m_glyph_cache->distanceFieldRadius();
qreal fontScale = m_glyph_cache->fontScale(fontPixelSize);
@@ -236,15 +245,20 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
// As we use UNSIGNED_SHORT indexing in the geometry, we overload the
// "glyphsInOtherTextures" concept as overflow for if there are more
- // than 65535 vertices to render which would otherwise exceed the
+ // than 65532 vertices to render, which would otherwise exceed the
// maximum index size. (leave 0xFFFF unused in order not to clash with
- // primitive restart) This will cause sub-nodes to be recursively
- // created to handle any number of glyphs.
- if (m_texture != texture || vp.size() >= 65535) {
- if (texture->texture) {
- GlyphInfo &glyphInfo = glyphsInOtherTextures[texture];
+ // primitive restart) This will cause sub-nodes to be
+ // created to handle any number of glyphs. But only the RootGlyphNode
+ // needs to do this classification; from the perspective of a SubGlyphNode,
+ // it's already done, and m_glyphs contains only pointers to ranges of
+ // indices and positions that the RootGlyphNode is storing.
+ if (m_texture != texture || vp.size() >= maxVertexCount) {
+ if (m_glyphNodeType == RootGlyphNode && texture->texture) {
+ GlyphInfo &glyphInfo = m_glyphsInOtherTextures[texture];
glyphInfo.indexes.append(glyphIndex);
glyphInfo.positions.append(position);
+ } else if (vp.size() >= maxVertexCount && m_glyphNodeType == SubGlyphNode) {
+ break; // out of this loop over indices, because we won't add any more vertices
}
continue;
}
@@ -303,26 +317,38 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
ip.append(o + 0);
}
- QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo>::const_iterator ite = glyphsInOtherTextures.constBegin();
- while (ite != glyphsInOtherTextures.constEnd()) {
- QGlyphRun subNodeGlyphRun(m_glyphs);
- subNodeGlyphRun.setGlyphIndexes(ite->indexes);
- subNodeGlyphRun.setPositions(ite->positions);
-
- QSGDistanceFieldGlyphNode *subNode = new QSGDistanceFieldGlyphNode(m_context);
- subNode->setGlyphNodeType(SubGlyphNode);
- subNode->setColor(m_color);
- subNode->setStyle(m_style);
- subNode->setStyleColor(m_styleColor);
- subNode->setPreferredAntialiasingMode(m_antialiasingMode);
- subNode->setGlyphs(m_originalPosition, subNodeGlyphRun);
- subNode->update();
- subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
- appendChildNode(subNode);
-
- ++ite;
+ if (m_glyphNodeType == SubGlyphNode) {
+ Q_ASSERT(m_glyphsInOtherTextures.isEmpty());
+ } else {
+ if (!m_glyphsInOtherTextures.isEmpty())
+ qCDebug(lcSgText, "%" PRIdQSIZETYPE " 'other' textures", m_glyphsInOtherTextures.count());
+ QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo>::const_iterator ite = m_glyphsInOtherTextures.constBegin();
+ while (ite != m_glyphsInOtherTextures.constEnd()) {
+ QGlyphRun subNodeGlyphRun(m_glyphs);
+ for (int i = 0; i < ite->indexes.count(); i += maxIndexCount) {
+ int len = qMin(maxIndexCount, ite->indexes.count() - i);
+ subNodeGlyphRun.setRawData(ite->indexes.constData() + i, ite->positions.constData() + i, len);
+ qCDebug(lcSgText) << "subNodeGlyphRun has" << len << "positions:"
+ << *(ite->positions.constData() + i) << "->" << *(ite->positions.constData() + i + len - 1);
+
+ QSGDistanceFieldGlyphNode *subNode = new QSGDistanceFieldGlyphNode(m_context);
+ subNode->setGlyphNodeType(SubGlyphNode);
+ subNode->setColor(m_color);
+ subNode->setStyle(m_style);
+ subNode->setStyleColor(m_styleColor);
+ subNode->setPreferredAntialiasingMode(m_antialiasingMode);
+ subNode->setGlyphs(m_originalPosition, subNodeGlyphRun);
+ subNode->update();
+ subNode->updateGeometry(); // we have to explicitly call this now as preprocess won't be called before it's rendered
+ appendChildNode(subNode);
+ }
+ ++ite;
+ }
}
+ m_totalAllocation += vp.size() * sizeof(QSGGeometry::TexturedPoint2D) + ip.size() * sizeof(quint16);
+ qCDebug(lcSgText) << "allocating for" << vp.size() << "vtx (reserved" << likelyGlyphCount * 4 << "):" << vp.size() * sizeof(QSGGeometry::TexturedPoint2D)
+ << "bytes;" << ip.size() << "idx:" << ip.size() * sizeof(quint16) << "bytes; total bytes so far" << m_totalAllocation;
g->allocate(vp.size(), ip.size());
memcpy(g->vertexDataAsTexturedPoint2D(), vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
memcpy(g->indexDataAsUShort(), ip.constData(), ip.size() * sizeof(quint16));
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index 2b2975ccb3..e7655f502d 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -115,9 +115,13 @@ private:
QVector<QPointF> positions;
};
QSet<quint32> m_allGlyphIndexesLookup;
+ // m_glyphs holds pointers to the GlyphInfo.indexes and positions arrays, so we need to hold on to them
+ QHash<const QSGDistanceFieldGlyphCache::Texture *, GlyphInfo> m_glyphsInOtherTextures;
uint m_dirtyGeometry: 1;
uint m_dirtyMaterial: 1;
+
+ static qint64 m_totalAllocation; // all SG glyph vertices and indices; only for qCDebug metrics
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 077814b1f4..443afb00ac 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -357,10 +357,6 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
rhi->makeThreadLocalNativeContextCurrent();
}
-#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
-#endif
-
if (d->swapchain) {
if (window->handle()) {
// We get here when exiting via QCoreApplication::quit() instead of
@@ -373,6 +369,11 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
}
d->cleanupNodesOnShutdown();
+
+#if QT_CONFIG(quick_shadereffect)
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache(window);
+#endif
+
if (m_windows.size() == 0) {
rc->invalidate();
d->rhi = nullptr;
@@ -409,17 +410,6 @@ void QSGGuiThreadRenderLoop::handleDeviceLoss()
void QSGGuiThreadRenderLoop::releaseSwapchain(QQuickWindow *window)
{
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
-
- // Unlike the threaded render loop, this one reuses the same rendercontext
- // for all QQuickWindows for the entire lifetime of the render loop. (and
- // even if it wouldn't, special cases like destroy() - show() on the
- // QQuickWindow still needed this)
- // Therefore the renderer, if there is one, needs to be notified about the
- // destruction of certain resources because they may be referenced from
- // per-rendercontext data structures.
- if (wd->renderer)
- wd->renderer->invalidatePipelineCacheDependency(wd->rpDescForSwapchain);
-
delete wd->rpDescForSwapchain;
wd->rpDescForSwapchain = nullptr;
delete wd->swapchain;
@@ -452,7 +442,7 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data)
{
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
- bool current = false;
+ bool ok = rhi != nullptr;
if (!rhi) {
// This block below handles both the initial QRhi initialization and
@@ -473,7 +463,9 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data)
data.rhiDeviceLost = false;
- current = true;
+ ok = true;
+ // We need to guarantee that sceneGraphInitialized is
+ // emitted with a context current, if running with OpenGL.
rhi->makeThreadLocalNativeContextCurrent();
// The sample count cannot vary between windows as we use the same
@@ -493,16 +485,8 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data)
data.rhiDoomed = true;
handleContextCreationFailure(window);
}
- // otherwise no error, will retry on a subsequent rendering attempt
+ // otherwise no error, just return false so that we will retry on a subsequent rendering attempt
}
- } else {
- current = true;
- // With the rhi making the (OpenGL) context current serves only one
- // purpose: to enable external OpenGL rendering connected to one of
- // the QQuickWindow signals (beforeSynchronizing, beforeRendering,
- // etc.) to function like it did on the direct OpenGL path. For our
- // own rendering this call would not be necessary.
- rhi->makeThreadLocalNativeContextCurrent();
}
if (rhi && !cd->swapchain) {
@@ -551,7 +535,7 @@ bool QSGGuiThreadRenderLoop::ensureRhi(QQuickWindow *window, WindowData &data)
window->installEventFilter(this);
}
- return current;
+ return ok;
}
void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
@@ -665,6 +649,12 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
}
}
+ // Enable external OpenGL rendering connected to one of the
+ // QQuickWindow signals (beforeSynchronizing, beforeRendering,
+ // etc.) to function like it did on the direct OpenGL path,
+ // i.e. ensure there is a context current, just in case.
+ rhi->makeThreadLocalNativeContextCurrent();
+
cd->syncSceneGraph();
if (lastDirtyWindow)
rc->endSync();
@@ -775,6 +765,7 @@ QImage QSGGuiThreadRenderLoop::grab(QQuickWindow *window)
// renderWindow() so one cannot get to grab() without having done at least
// one on-screen frame.
cd->rhi->beginFrame(cd->swapchain);
+ rhi->makeThreadLocalNativeContextCurrent(); // for custom GL rendering before/during/after sync
cd->syncSceneGraph();
cd->renderSceneGraph(window->size());
QImage image = QSGRhiSupport::instance()->grabAndBlockInCurrentFrame(rhi, cd->swapchain->currentFrameCommandBuffer());
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
index a715092b19..b139c3428a 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache.cpp
@@ -39,6 +39,7 @@
#include "qsgrhidistancefieldglyphcache_p.h"
#include "qsgcontext_p.h"
+#include "qsgdefaultrendercontext_p.h"
#include <QtGui/private/qdistancefield_p.h>
#include <QtCore/qelapsedtimer.h>
#include <QtQml/private/qqmlglobal_p.h>
@@ -54,11 +55,12 @@ DEFINE_BOOL_CONFIG_OPTION(qsgPreferFullSizeGlyphCacheTextures, QSG_PREFER_FULLSI
# define QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING 2
#endif
-QSGRhiDistanceFieldGlyphCache::QSGRhiDistanceFieldGlyphCache(QRhi *rhi,
+QSGRhiDistanceFieldGlyphCache::QSGRhiDistanceFieldGlyphCache(QSGDefaultRenderContext *rc,
const QRawFont &font,
int renderTypeQuality)
: QSGDistanceFieldGlyphCache(font, renderTypeQuality)
- , m_rhi(rhi)
+ , m_rc(rc)
+ , m_rhi(rc->rhi())
{
// Load a pregenerated cache if the font contains one
loadPregeneratedCache(font);
@@ -66,13 +68,19 @@ QSGRhiDistanceFieldGlyphCache::QSGRhiDistanceFieldGlyphCache(QRhi *rhi,
QSGRhiDistanceFieldGlyphCache::~QSGRhiDistanceFieldGlyphCache()
{
- for (int i = 0; i < m_textures.count(); ++i)
- delete m_textures[i].texture;
+ // A plain delete should work, but just in case commitResourceUpdates was
+ // not called and something is enqueued on the update batch for a texture,
+ // defer until the end of the frame.
+ for (int i = 0; i < m_textures.count(); ++i) {
+ if (m_textures[i].texture)
+ m_textures[i].texture->deleteLater();
+ }
delete m_areaAllocator;
// should be empty, but just in case
- qDeleteAll(m_pendingDispose);
+ for (QRhiTexture *t : qAsConst(m_pendingDispose))
+ t->deleteLater();
}
void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
@@ -88,8 +96,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
int padding = QSG_RHI_DISTANCEFIELD_GLYPH_CACHE_PADDING;
QRectF boundingRect = glyphData(glyphIndex).boundingRect;
- int glyphWidth = qCeil(boundingRect.width()) + distanceFieldRadius() * 2;
- int glyphHeight = qCeil(boundingRect.height()) + distanceFieldRadius() * 2;
+ int glyphWidth = qCeil(boundingRect.width() + distanceFieldRadius() * 2);
+ int glyphHeight = qCeil(boundingRect.height() + distanceFieldRadius() * 2);
QSize glyphSize(glyphWidth + padding * 2, glyphHeight + padding * 2);
QRect alloc = m_areaAllocator->allocate(glyphSize);
@@ -100,8 +108,8 @@ void QSGRhiDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
QRectF unusedGlyphBoundingRect = glyphData(unusedGlyph).boundingRect;
- int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width()) + distanceFieldRadius() * 2;
- int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height()) + distanceFieldRadius() * 2;
+ int unusedGlyphWidth = qCeil(unusedGlyphBoundingRect.width() + distanceFieldRadius() * 2);
+ int unusedGlyphHeight = qCeil(unusedGlyphBoundingRect.height() + distanceFieldRadius() * 2);
m_areaAllocator->deallocate(QRect(unusedCoord.x - padding,
unusedCoord.y - padding,
padding * 2 + unusedGlyphWidth,
@@ -178,15 +186,13 @@ void QSGRhiDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField> &gly
texInfo->uploads.append(QRhiTextureUploadEntry(0, 0, subresDesc));
}
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
-
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
for (int i = 0; i < glyphs.size(); ++i) {
TextureInfo *texInfo = m_glyphsTexture.value(glyphs.at(i).glyph());
if (!texInfo->uploads.isEmpty()) {
QRhiTextureUploadDescription desc;
desc.setEntries(texInfo->uploads.cbegin(), texInfo->uploads.cend());
- m_resourceUpdates->uploadTexture(texInfo->texture, desc);
+ resourceUpdates->uploadTexture(texInfo->texture, desc);
texInfo->uploads.clear();
}
}
@@ -229,12 +235,10 @@ void QSGRhiDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo,
texInfo->texture = m_rhi->newTexture(QRhiTexture::RED_OR_ALPHA8, QSize(width, height), 1, QRhiTexture::UsedAsTransferSource);
if (texInfo->texture->create()) {
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
-
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
QRhiTextureSubresourceUploadDescription subresDesc(pixels, width * height);
subresDesc.setSourceSize(QSize(width, height));
- m_resourceUpdates->uploadTexture(texInfo->texture, QRhiTextureUploadEntry(0, 0, subresDesc));
+ resourceUpdates->uploadTexture(texInfo->texture, QRhiTextureUploadEntry(0, 0, subresDesc));
} else {
qWarning("Failed to create distance field glyph cache");
}
@@ -257,17 +261,15 @@ void QSGRhiDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int widt
updateRhiTexture(oldTexture, texInfo->texture, texInfo->size);
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
-
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
if (useTextureResizeWorkaround()) {
QRhiTextureSubresourceUploadDescription subresDesc(texInfo->image.constBits(),
oldWidth * oldHeight);
subresDesc.setSourceSize(QSize(oldWidth, oldHeight));
- m_resourceUpdates->uploadTexture(texInfo->texture, QRhiTextureUploadEntry(0, 0, subresDesc));
+ resourceUpdates->uploadTexture(texInfo->texture, QRhiTextureUploadEntry(0, 0, subresDesc));
texInfo->image = texInfo->image.copy(0, 0, width, height);
} else {
- m_resourceUpdates->copyTexture(texInfo->texture, oldTexture);
+ resourceUpdates->copyTexture(texInfo->texture, oldTexture);
}
m_pendingDispose.insert(oldTexture);
@@ -447,7 +449,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *textureRecord = allocatorData;
for (int i = 0; i < textureCount; ++i, textureRecord += Qtdf::TextureRecordSize) {
- if (textureRecord + Qtdf::TextureRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - textureRecord < Qtdf::TextureRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -463,7 +465,7 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
const char *glyphRecord = textureRecord;
for (quint32 i = 0; i < glyphCount; ++i, glyphRecord += Qtdf::GlyphRecordSize) {
- if (glyphRecord + Qtdf::GlyphRecordSize > qtdfTableEnd) {
+ if (qtdfTableEnd - glyphRecord < Qtdf:: GlyphRecordSize) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -513,8 +515,8 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
int width = texInfo->allocatedArea.width();
int height = texInfo->allocatedArea.height();
- qint64 size = width * height;
- if (reinterpret_cast<const char *>(textureData + size) > qtdfTableEnd) {
+ qint64 size = qint64(width) * height;
+ if (qtdfTableEnd - reinterpret_cast<const char *>(textureData) < size) {
qWarning("qtdf table too small in font '%s'.",
qPrintable(font.familyName()));
return false;
@@ -547,14 +549,13 @@ bool QSGRhiDistanceFieldGlyphCache::loadPregeneratedCache(const QRawFont &font)
void QSGRhiDistanceFieldGlyphCache::commitResourceUpdates(QRhiResourceUpdateBatch *mergeInto)
{
- if (m_resourceUpdates) {
- mergeInto->merge(m_resourceUpdates);
- m_resourceUpdates->release();
- m_resourceUpdates = nullptr;
+ if (QRhiResourceUpdateBatch *resourceUpdates = m_rc->maybeGlyphCacheResourceUpdates()) {
+ mergeInto->merge(resourceUpdates);
+ m_rc->releaseGlyphCacheResourceUpdates();
}
// now let's assume the resource updates will be committed in this frame
- for (QRhiTexture *t : m_pendingDispose)
+ for (QRhiTexture *t : qAsConst(m_pendingDispose))
t->deleteLater(); // will be deleted after the frame is submitted -> safe
m_pendingDispose.clear();
@@ -604,7 +605,8 @@ void QSGRhiDistanceFieldGlyphCache::saveTexture(QRhiTexture *texture, const QStr
};
QRhiReadbackDescription rb(texture);
- m_resourceUpdates->readBackTexture(rb, rbResult);
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
+ resourceUpdates->readBackTexture(rb, rbResult);
}
#endif
diff --git a/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
index 48d666e7e2..965b496e48 100644
--- a/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgrhidistancefieldglyphcache_p.h
@@ -57,10 +57,12 @@
QT_BEGIN_NAMESPACE
+class QSGDefaultRenderContext;
+
class Q_QUICK_PRIVATE_EXPORT QSGRhiDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache
{
public:
- QSGRhiDistanceFieldGlyphCache(QRhi *rhi, const QRawFont &font, int renderTypeQuality);
+ QSGRhiDistanceFieldGlyphCache(QSGDefaultRenderContext *rc, const QRawFont &font, int renderTypeQuality);
virtual ~QSGRhiDistanceFieldGlyphCache();
void requestGlyphs(const QSet<glyph_t> &glyphs) override;
@@ -114,11 +116,11 @@ private:
return &m_textures[index];
}
+ QSGDefaultRenderContext *m_rc;
QRhi *m_rhi;
mutable int m_maxTextureSize = 0;
int m_maxTextureCount = 3;
QSGAreaAllocator *m_areaAllocator = nullptr;
- QRhiResourceUpdateBatch *m_resourceUpdates = nullptr;
QList<TextureInfo> m_textures;
QHash<glyph_t, TextureInfo *> m_glyphsTexture;
QSet<glyph_t> m_unusedGlyphs;
diff --git a/src/quick/scenegraph/qsgrhilayer.cpp b/src/quick/scenegraph/qsgrhilayer.cpp
index cef9737fd8..849ed7d49f 100644
--- a/src/quick/scenegraph/qsgrhilayer.cpp
+++ b/src/quick/scenegraph/qsgrhilayer.cpp
@@ -214,12 +214,8 @@ void QSGRhiLayer::releaseResources()
delete m_rt;
m_rt = nullptr;
- if (m_rtRp) {
- if (m_renderer)
- m_renderer->invalidatePipelineCacheDependency(m_rtRp);
- delete m_rtRp;
- m_rtRp = nullptr;
- }
+ delete m_rtRp;
+ m_rtRp = nullptr;
delete m_ds;
m_ds = nullptr;
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode.cpp b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
index 9868a7b0f4..5575731675 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode.cpp
+++ b/src/quick/scenegraph/qsgrhishadereffectnode.cpp
@@ -47,6 +47,7 @@
#include <QQmlFile>
#include <QFile>
#include <QFileSelector>
+#include <QMutexLocker>
QT_BEGIN_NAMESPACE
@@ -116,6 +117,12 @@ void QSGRhiShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &sha
const QSGShaderEffectNode::VariableData &vd(shader.varData.at(i));
if (var.type == QSGGuiThreadShaderEffectManager::ShaderInfo::Sampler) {
Q_ASSERT(vd.specialType == QSGShaderEffectNode::VariableData::Source);
+
+#ifndef QT_NO_DEBUG
+ int existingBindPoint = m_samplerNameMap.value(var.name, -1);
+ Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
+#endif
+
m_samplers.insert(var.bindPoint, vd.value);
m_samplerNameMap.insert(var.name, var.bindPoint);
}
@@ -124,6 +131,12 @@ void QSGRhiShaderLinker::feedSamplers(const QSGShaderEffectNode::ShaderData &sha
for (int idx : *dirtyIndices) {
const QSGGuiThreadShaderEffectManager::ShaderInfo::Variable &var(shader.shaderInfo.variables.at(idx));
const QSGShaderEffectNode::VariableData &vd(shader.varData.at(idx));
+
+#ifndef QT_NO_DEBUG
+ int existingBindPoint = m_samplerNameMap.value(var.name, -1);
+ Q_ASSERT(existingBindPoint < 0 || existingBindPoint == var.bindPoint);
+#endif
+
m_samplers.insert(var.bindPoint, vd.value);
m_samplerNameMap.insert(var.name, var.bindPoint);
}
@@ -207,7 +220,8 @@ QSGMaterialType *QSGRhiShaderMaterialTypeCache::get(const QShader &vs, const QSh
return t;
}
-static QSGRhiShaderMaterialTypeCache shaderMaterialTypeCache;
+static QHash<void *, QSGRhiShaderMaterialTypeCache> shaderMaterialTypeCache;
+static QMutex shaderMaterialTypeCacheMutex;
class QSGRhiShaderEffectMaterialShader : public QSGMaterialShader
{
@@ -576,9 +590,9 @@ void QSGRhiShaderEffectMaterial::updateTextureProviders(bool layoutChange)
}
QSGRhiShaderEffectNode::QSGRhiShaderEffectNode(QSGDefaultRenderContext *rc)
- : m_rc(rc),
- m_material(this)
+ : m_material(this)
{
+ Q_UNUSED(rc);
setFlag(UsePreprocess, true);
setMaterial(&m_material);
}
@@ -657,7 +671,12 @@ void QSGRhiShaderEffectNode::syncMaterial(SyncData *syncData)
m_material.m_fragmentShader = defaultFragmentShader;
}
- m_material.m_materialType = shaderMaterialTypeCache.get(m_material.m_vertexShader, m_material.m_fragmentShader);
+ {
+ QMutexLocker lock(&shaderMaterialTypeCacheMutex);
+ m_material.m_materialType = shaderMaterialTypeCache[syncData->materialTypeCacheKey].get(m_material.m_vertexShader,
+ m_material.m_fragmentShader);
+ }
+
m_material.m_linker.reset(m_material.m_vertexShader, m_material.m_fragmentShader);
if (m_material.m_hasCustomVertexShader) {
@@ -775,9 +794,10 @@ void QSGRhiShaderEffectNode::preprocess()
}
}
-void QSGRhiShaderEffectNode::cleanupMaterialTypeCache()
+void QSGRhiShaderEffectNode::cleanupMaterialTypeCache(void *materialTypeCacheKey)
{
- shaderMaterialTypeCache.reset();
+ QMutexLocker lock(&shaderMaterialTypeCacheMutex);
+ shaderMaterialTypeCache[materialTypeCacheKey].reset();
}
bool QSGRhiGuiThreadShaderEffectManager::hasSeparateSamplerAndTextureObjects() const
@@ -805,7 +825,12 @@ void QSGRhiGuiThreadShaderEffectManager::prepareShaderCode(ShaderInfo::Type type
const QString fn = m_fileSelector->select(QQmlFile::urlToLocalFileOrQrc(src));
const QShader s = loadShaderFromFile(fn);
if (!s.isValid()) {
- qWarning("ShaderEffect: Failed to deserialize QShader from %s", qPrintable(fn));
+ qWarning("ShaderEffect: Failed to deserialize QShader from %s. "
+ "Either the filename is incorrect, or it is not a valid .qsb file. "
+ "In Qt 6 shaders must be preprocessed using the Qt Shader Tools infrastructure. "
+ "The vertexShader and fragmentShader properties are now URLs that are expected to point to .qsb files generated by the qsb tool. "
+ "See https://doc.qt.io/qt-6/qtshadertools-index.html for more information.",
+ qPrintable(fn));
m_status = Error;
emit shaderCodePrepared(false, typeHint, src, result);
emit logAndStatusChanged();
@@ -878,3 +903,5 @@ bool QSGRhiGuiThreadShaderEffectManager::reflect(ShaderInfo *result)
}
QT_END_NAMESPACE
+
+#include "moc_qsgrhishadereffectnode_p.cpp"
diff --git a/src/quick/scenegraph/qsgrhishadereffectnode_p.h b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
index 0bef0d571d..f60c5c8895 100644
--- a/src/quick/scenegraph/qsgrhishadereffectnode_p.h
+++ b/src/quick/scenegraph/qsgrhishadereffectnode_p.h
@@ -135,14 +135,13 @@ public:
void syncMaterial(SyncData *syncData) override;
void preprocess() override;
- static void cleanupMaterialTypeCache();
+ static void cleanupMaterialTypeCache(void *materialTypeCacheKey);
private Q_SLOTS:
void handleTextureChange();
void handleTextureProviderDestroyed(QObject *object);
private:
- QSGDefaultRenderContext *m_rc;
QSGRhiShaderEffectMaterial m_material;
};
diff --git a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
index 1ec7e0c92d..e46a2d9556 100644
--- a/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
+++ b/src/quick/scenegraph/qsgrhitextureglyphcache.cpp
@@ -38,15 +38,18 @@
****************************************************************************/
#include "qsgrhitextureglyphcache_p.h"
+#include "qsgdefaultrendercontext_p.h"
#include <qrgb.h>
#include <private/qdrawhelper_p.h>
QT_BEGIN_NAMESPACE
-QSGRhiTextureGlyphCache::QSGRhiTextureGlyphCache(QRhi *rhi, QFontEngine::GlyphFormat format, const QTransform &matrix,
+QSGRhiTextureGlyphCache::QSGRhiTextureGlyphCache(QSGDefaultRenderContext *rc,
+ QFontEngine::GlyphFormat format, const QTransform &matrix,
const QColor &color)
: QImageTextureGlyphCache(format, matrix, color),
- m_rhi(rhi)
+ m_rc(rc),
+ m_rhi(rc->rhi())
{
// Some OpenGL implementations, for instance macOS, have issues with
// GL_ALPHA render targets. Similarly, BGRA may be problematic on GLES 2.0.
@@ -56,13 +59,15 @@ QSGRhiTextureGlyphCache::QSGRhiTextureGlyphCache(QRhi *rhi, QFontEngine::GlyphFo
QSGRhiTextureGlyphCache::~QSGRhiTextureGlyphCache()
{
- if (m_resourceUpdates)
- m_resourceUpdates->release();
-
- delete m_texture;
+ // A plain delete should work, but just in case commitResourceUpdates was
+ // not called and something is enqueued on the update batch for m_texture,
+ // defer until the end of the frame.
+ if (m_texture)
+ m_texture->deleteLater();
// should be empty, but just in case
- qDeleteAll(m_pendingDispose);
+ for (QRhiTexture *t : qAsConst(m_pendingDispose))
+ t->deleteLater();
}
QRhiTexture *QSGRhiTextureGlyphCache::createEmptyTexture(QRhiTexture::Format format)
@@ -73,8 +78,7 @@ QRhiTexture *QSGRhiTextureGlyphCache::createEmptyTexture(QRhiTexture::Format for
return nullptr;
}
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
// The new texture must be cleared to 0 always, this cannot be avoided
// otherwise artifacts will occur around the glyphs.
@@ -85,7 +89,7 @@ QRhiTexture *QSGRhiTextureGlyphCache::createEmptyTexture(QRhiTexture::Format for
data.fill(0, m_size.width() * m_size.height() * 4);
QRhiTextureSubresourceUploadDescription subresDesc(data.constData(), data.size());
subresDesc.setSourceSize(m_size);
- m_resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
+ resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
return t;
}
@@ -116,11 +120,9 @@ void QSGRhiTextureGlyphCache::resizeTextureData(int width, int height)
if (!t)
return;
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
-
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
if (m_resizeWithTextureCopy) {
- m_resourceUpdates->copyTexture(t, m_texture);
+ resourceUpdates->copyTexture(t, m_texture);
} else {
QImageTextureGlyphCache::resizeTextureData(width, height);
QImage img = image();
@@ -128,7 +130,7 @@ void QSGRhiTextureGlyphCache::resizeTextureData(int width, int height)
QRhiTextureSubresourceUploadDescription subresDesc(img);
const QSize oldSize = m_texture->pixelSize();
subresDesc.setSourceSize(QSize(qMin(oldSize.width(), width), qMin(oldSize.height(), height)));
- m_resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
+ resourceUpdates->uploadTexture(t, QRhiTextureUploadEntry(0, 0, subresDesc));
}
m_pendingDispose.insert(m_texture);
@@ -222,18 +224,19 @@ void QSGRhiTextureGlyphCache::endFillTexture()
return;
}
- if (!m_resourceUpdates)
- m_resourceUpdates = m_rhi->nextResourceUpdateBatch();
-
+ QRhiResourceUpdateBatch *resourceUpdates = m_rc->glyphCacheResourceUpdates();
QRhiTextureUploadDescription desc;
desc.setEntries(m_uploads.cbegin(), m_uploads.cend());
- m_resourceUpdates->uploadTexture(m_texture, desc);
+ resourceUpdates->uploadTexture(m_texture, desc);
m_uploads.clear();
}
int QSGRhiTextureGlyphCache::glyphPadding() const
{
- return 1;
+ if (m_format == QFontEngine::Format_Mono)
+ return 8;
+ else
+ return 1;
}
int QSGRhiTextureGlyphCache::maxTextureWidth() const
@@ -251,14 +254,13 @@ int QSGRhiTextureGlyphCache::maxTextureHeight() const
void QSGRhiTextureGlyphCache::commitResourceUpdates(QRhiResourceUpdateBatch *mergeInto)
{
- if (m_resourceUpdates) {
- mergeInto->merge(m_resourceUpdates);
- m_resourceUpdates->release();
- m_resourceUpdates = nullptr;
+ if (QRhiResourceUpdateBatch *resourceUpdates = m_rc->maybeGlyphCacheResourceUpdates()) {
+ mergeInto->merge(resourceUpdates);
+ m_rc->releaseGlyphCacheResourceUpdates();
}
// now let's assume the resource updates will be committed in this frame
- for (QRhiTexture *t : m_pendingDispose)
+ for (QRhiTexture *t : qAsConst(m_pendingDispose))
t->deleteLater(); // will be deleted after the frame is submitted -> safe
m_pendingDispose.clear();
diff --git a/src/quick/scenegraph/qsgrhitextureglyphcache_p.h b/src/quick/scenegraph/qsgrhitextureglyphcache_p.h
index c3964ee09f..093d5424c8 100644
--- a/src/quick/scenegraph/qsgrhitextureglyphcache_p.h
+++ b/src/quick/scenegraph/qsgrhitextureglyphcache_p.h
@@ -56,10 +56,13 @@
QT_BEGIN_NAMESPACE
+class QSGDefaultRenderContext;
+
class QSGRhiTextureGlyphCache : public QImageTextureGlyphCache
{
public:
- QSGRhiTextureGlyphCache(QRhi *rhi, QFontEngine::GlyphFormat format, const QTransform &matrix,
+ QSGRhiTextureGlyphCache(QSGDefaultRenderContext *rc,
+ QFontEngine::GlyphFormat format, const QTransform &matrix,
const QColor &color = QColor());
~QSGRhiTextureGlyphCache();
@@ -86,9 +89,9 @@ private:
void prepareGlyphImage(QImage *img);
QRhiTexture *createEmptyTexture(QRhiTexture::Format format);
+ QSGDefaultRenderContext *m_rc;
QRhi *m_rhi;
bool m_resizeWithTextureCopy;
- QRhiResourceUpdateBatch *m_resourceUpdates = nullptr;
QRhiTexture *m_texture = nullptr;
QSize m_size;
bool m_bgra = false;
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 8a0202ede9..45639ba93b 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -285,7 +285,7 @@ public:
, stopEventProcessing(false)
{
sgrc = static_cast<QSGDefaultRenderContext *>(renderContext);
-#if defined(Q_OS_QNX) && defined(Q_PROCESSOR_X86)
+#if (defined(Q_OS_QNX) && defined(Q_PROCESSOR_X86)) || defined(Q_OS_INTEGRITY)
// The SDP 6.6.0 x86 MESA driver requires a larger stack than the default.
setStackSize(1024 * 1024);
#endif
@@ -444,11 +444,11 @@ bool QSGRenderThread::event(QEvent *e)
if (ce->window) {
if (rhi) {
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(ce->window);
- cd->rhi->makeThreadLocalNativeContextCurrent();
// The assumption is that the swapchain is usable, because on
// expose the thread starts up and renders a frame so one cannot
// get here without having done at least one on-screen frame.
cd->rhi->beginFrame(cd->swapchain);
+ cd->rhi->makeThreadLocalNativeContextCurrent(); // for custom GL rendering before/during/after sync
cd->syncSceneGraph();
sgrc->endSync();
cd->renderSceneGraph(ce->window->size());
@@ -511,27 +511,19 @@ void QSGRenderThread::invalidateGraphics(QQuickWindow *window, bool inDestructor
return;
}
-
bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
bool wipeGraphics = inDestructor || (wipeSG && !window->isPersistentGraphics());
- bool current = true;
- if (rhi)
- rhi->makeThreadLocalNativeContextCurrent();
-
- if (Q_UNLIKELY(!current)) {
- qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- cleanup without an OpenGL context");
- }
+ rhi->makeThreadLocalNativeContextCurrent();
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
-#if QT_CONFIG(quick_shadereffect)
- QSGRhiShaderEffectNode::cleanupMaterialTypeCache();
-#endif
-
// The canvas nodes must be cleaned up regardless if we are in the destructor..
if (wipeSG) {
dd->cleanupNodesOnShutdown();
+#if QT_CONFIG(quick_shadereffect)
+ QSGRhiShaderEffectNode::cleanupMaterialTypeCache(window);
+#endif
} else {
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent SG, avoiding cleanup");
return;
@@ -558,6 +550,7 @@ void QSGRenderThread::invalidateGraphics(QQuickWindow *window, bool inDestructor
}
QSGRhiSupport::instance()->destroyRhi(rhi);
rhi = nullptr;
+ dd->rhi = nullptr;
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- QRhi destroyed");
} else {
qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent GL, avoiding cleanup");
@@ -575,7 +568,7 @@ void QSGRenderThread::sync(bool inExpose)
Q_ASSERT_X(wm->m_lockedForSync, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
- bool current = true;
+ bool canSync = true;
if (rhi) {
if (windowSize.width() > 0 && windowSize.height() > 0) {
// With the rhi making the (OpenGL) context current serves only one
@@ -587,12 +580,12 @@ void QSGRenderThread::sync(bool inExpose)
} else {
// Zero size windows do not initialize a swapchain and
// rendercontext. So no sync or render can be done then.
- current = false;
+ canSync = false;
}
} else {
- current = false;
+ canSync = false;
}
- if (current) {
+ if (canSync) {
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != nullptr;
// If the scene graph was touched since the last sync() make sure it sends the
@@ -774,16 +767,15 @@ void QSGRenderThread::syncAndRender()
d->animationController->unlock();
}
- bool current = true;
// Zero size windows do not initialize a swapchain and
// rendercontext. So no sync or render can be done then.
- if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0 && rhi)
- rhi->makeThreadLocalNativeContextCurrent();
- else
- current = false;
+ const bool canRender = d->renderer && cd->swapchain && windowSize.width() > 0 && windowSize.height() > 0;
+
+ if (canRender) {
+ if (!syncRequested) // else this was already done in sync()
+ rhi->makeThreadLocalNativeContextCurrent();
- if (current) {
- d->renderSceneGraph(windowSize, rhi ? cd->swapchain->currentPixelSize() : QSize());
+ d->renderSceneGraph(windowSize, cd->swapchain->currentPixelSize());
if (profileFrames)
renderTime = threadTimer.nsecsElapsed();
@@ -821,7 +813,7 @@ void QSGRenderThread::syncAndRender()
// beforeFrameBegin - afterFrameEnd must always come in pairs; if there was
// no before due to 0 size then there shouldn't be an after either
- if (current)
+ if (canRender)
emit window->afterFrameEnd();
// Though it would be more correct to put this block directly after
@@ -915,6 +907,8 @@ void QSGRenderThread::ensureRhi()
}
}
if (!sgrc->rhi() && windowSize.width() > 0 && windowSize.height() > 0) {
+ // We need to guarantee that sceneGraphInitialized is emitted
+ // with a context current, if running with OpenGL.
rhi->makeThreadLocalNativeContextCurrent();
QSGDefaultRenderContext::InitParams rcParams;
rcParams.rhi = rhi;
@@ -1192,20 +1186,6 @@ void QSGThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
void QSGThreadedRenderLoop::releaseSwapchain(QQuickWindow *window)
{
QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
-
- // Counterintuitive, because this is not needed under normal circumstances
- // due to the render loop using a dedicated rendercontext per thread, so
- // per window. Problem is, there are cases like calling destroy(); show();
- // on the QQuickWindow. (and we get here on SurfaceAboutToBeDestroyed, i.e.
- // from destroy())
- //
- // That means recreating the native window and all the related graphics
- // infrastructure, but the rendercontext stays around. So still have to
- // notify the renderer to invalidate the relevant objects in the caches.
- //
- if (wd->renderer)
- wd->renderer->invalidatePipelineCacheDependency(wd->rpDescForSwapchain);
-
delete wd->rpDescForSwapchain;
wd->rpDescForSwapchain = nullptr;
delete wd->swapchain;
diff --git a/src/quick/scenegraph/shaders_ng/24bittextmask.frag b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
index bc3826a924..ed8da4cd30 100644
--- a/src/quick/scenegraph/shaders_ng/24bittextmask.frag
+++ b/src/quick/scenegraph/shaders_ng/24bittextmask.frag
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- vec4 color; // only alpha is used, but must be vec4 due to layout compat
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
+ vec4 color;
vec2 textureScale;
float dpr;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
index 63e445f90b..4198a4d339 100644
--- a/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
+++ b/src/quick/scenegraph/shaders_ng/32bitcolortext.frag
@@ -6,8 +6,9 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
- vec4 color; // only alpha is used, but must be vec4 due to layout compat
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
+ vec4 color;
vec2 textureScale;
float dpr;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask.frag b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
index 6304e821ff..a06743876d 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask.frag
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
index 0d0fa1cd3a..f725cbc5e7 100644
--- a/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
+++ b/src/quick/scenegraph/shaders_ng/8bittextmask_a.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.frag b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
index 947d161a50..e2f82d3845 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.frag
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.frag
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext.vert b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
index 023f9dfdc2..4068e42f28 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext.vert
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext.vert
@@ -10,11 +10,12 @@ layout(location = 3) out vec2 sCoordLeft;
layout(location = 4) out vec2 sCoordRight;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
@@ -28,6 +29,6 @@ void main()
sCoordDown = (tCoord - vec2(0.0, 1.0)) * ubuf.textureScale;
sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * ubuf.textureScale;
sCoordRight = (tCoord - vec2(1.0, 0.0)) * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
index 5b7bd9ca82..274d891a3c 100644
--- a/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
+++ b/src/quick/scenegraph/shaders_ng/outlinedtext_a.frag
@@ -11,11 +11,12 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- // must match styledtext
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
+ // the above must stay compatible with textmask/8bittextmask
vec4 styleColor;
vec2 shift;
} ubuf;
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.frag b/src/quick/scenegraph/shaders_ng/styledtext.frag
index 0b16396037..2e380dfeae 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.frag
+++ b/src/quick/scenegraph/shaders_ng/styledtext.frag
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/styledtext.vert b/src/quick/scenegraph/shaders_ng/styledtext.vert
index beadf07c79..271dae8d8a 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext.vert
+++ b/src/quick/scenegraph/shaders_ng/styledtext.vert
@@ -7,7 +7,8 @@ layout(location = 0) out vec2 sampleCoord;
layout(location = 1) out vec2 shiftedSampleCoord;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
@@ -22,6 +23,6 @@ void main()
{
sampleCoord = tCoord * ubuf.textureScale;
shiftedSampleCoord = (tCoord - ubuf.shift) * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/shaders_ng/styledtext_a.frag b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
index b673137895..62e162c851 100644
--- a/src/quick/scenegraph/shaders_ng/styledtext_a.frag
+++ b/src/quick/scenegraph/shaders_ng/styledtext_a.frag
@@ -8,7 +8,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/textmask.frag b/src/quick/scenegraph/shaders_ng/textmask.frag
index 518d5c965f..ed8da4cd30 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.frag
+++ b/src/quick/scenegraph/shaders_ng/textmask.frag
@@ -6,7 +6,8 @@ layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D _qt_texture;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
diff --git a/src/quick/scenegraph/shaders_ng/textmask.vert b/src/quick/scenegraph/shaders_ng/textmask.vert
index 9d80d5dadb..e0b3c01bce 100644
--- a/src/quick/scenegraph/shaders_ng/textmask.vert
+++ b/src/quick/scenegraph/shaders_ng/textmask.vert
@@ -6,7 +6,8 @@ layout(location = 1) in vec2 tCoord;
layout(location = 0) out vec2 sampleCoord;
layout(std140, binding = 0) uniform buf {
- mat4 matrix;
+ mat4 modelViewMatrix;
+ mat4 projectionMatrix;
vec4 color;
vec2 textureScale;
float dpr;
@@ -17,6 +18,6 @@ out gl_PerVertex { vec4 gl_Position; };
void main()
{
sampleCoord = tCoord * ubuf.textureScale;
- vec3 dprSnapPos = floor(vCoord.xyz * ubuf.dpr + 0.5) / ubuf.dpr;
- gl_Position = ubuf.matrix * vec4(dprSnapPos, vCoord.w);
+ vec4 xformed = ubuf.modelViewMatrix * vCoord;
+ gl_Position = ubuf.projectionMatrix * vec4(floor(xformed.xyz * ubuf.dpr + 0.5) / ubuf.dpr, xformed.w);
}
diff --git a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
index d97d48c78d..fc1b3aec24 100644
--- a/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultpainternode.cpp
@@ -206,13 +206,11 @@ void QSGDefaultPainterNode::updateRenderTarget()
m_image = QImage(m_textureSize, QImage::Format_ARGB32_Premultiplied);
m_image.fill(Qt::transparent);
- QSGPainterTexture *texture = new QSGPainterTexture;
- texture->setOwnsTexture(true);
- texture->setTextureSize(m_textureSize);
- if (m_texture)
- delete m_texture;
-
- m_texture = texture;
+ if (!m_texture) {
+ m_texture = new QSGPainterTexture;
+ m_texture->setOwnsTexture(true);
+ }
+ m_texture->setTextureSize(m_textureSize);
}
void QSGDefaultPainterNode::setPreferredRenderTarget(QQuickPaintedItem::RenderTarget target)
diff --git a/src/quick/scenegraph/util/qsgplaintexture.cpp b/src/quick/scenegraph/util/qsgplaintexture.cpp
index 6e59f9e607..128094cc94 100644
--- a/src/quick/scenegraph/util/qsgplaintexture.cpp
+++ b/src/quick/scenegraph/util/qsgplaintexture.cpp
@@ -231,7 +231,12 @@ void QSGPlainTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch
}
}
- bool needsRebuild = m_texture && m_texture->pixelSize() != m_texture_size;
+ bool needsRebuild = false;
+
+ if (m_texture && m_texture->pixelSize() != m_texture_size) {
+ m_texture->setPixelSize(m_texture_size);
+ needsRebuild = true;
+ }
if (mipmappingChanged) {
QRhiTexture::Flags f = m_texture->flags();
@@ -276,3 +281,5 @@ void QSGPlainTexture::commitTextureOperations(QRhi *rhi, QRhiResourceUpdateBatch
}
QT_END_NAMESPACE
+
+#include "moc_qsgplaintexture_p.cpp"
diff --git a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
index d60b77ce2e..2a7be48d3d 100644
--- a/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgrhiatlastexture.cpp
@@ -57,7 +57,7 @@ int qt_sg_envInt(const char *name, int defaultValue);
static QElapsedTimer qsg_renderer_timer;
-DEFINE_BOOL_CONFIG_OPTION(qsgDisableCompressedAtlas, QSG_DISABLE_COMPRESSED_ATLAS)
+DEFINE_BOOL_CONFIG_OPTION(qsgEnableCompressedAtlas, QSG_ENABLE_COMPRESSED_ATLAS)
namespace QSGRhiAtlasTexture
{
@@ -124,7 +124,7 @@ QSGTexture *Manager::create(const QImage &image, bool hasAlphaChannel)
QSGTexture *Manager::create(const QSGCompressedTextureFactory *factory)
{
QSGTexture *t = nullptr;
- if (qsgDisableCompressedAtlas() || !factory->textureData()->isValid())
+ if (!qsgEnableCompressedAtlas() || !factory->textureData()->isValid())
return t;
unsigned int format = factory->textureData()->glInternalFormat();
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 0573cd8966..82cdd03acc 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -81,6 +81,10 @@ void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(RenderState &state, i
Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newMaterial);
QSGTexture *t = tx->texture();
+ if (!t) {
+ *texture = nullptr;
+ return;
+ }
t->setFiltering(tx->filtering());
t->setMipmapFiltering(tx->mipmapFiltering());
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp
index 28cea4b93d..cb9102c1bd 100644
--- a/src/quick/util/qquickanimation.cpp
+++ b/src/quick/util/qquickanimation.cpp
@@ -2019,8 +2019,9 @@ void QQuickBulkValueAnimator::updateCurrentTime(int currentTime)
void QQuickBulkValueAnimator::topLevelAnimationLoopChanged()
{
- //check for new from every top-level loop (when the top level animation is started and all subsequent loops)
- if (fromIsSourced)
+ // Check for new "from" value only when animation has one loop.
+ // Otherwise use the initial "from" value for every iteration.
+ if (m_loopCount == 1 && fromIsSourced)
*fromIsSourced = false;
QAbstractAnimationJob::topLevelAnimationLoopChanged();
}
diff --git a/src/quick/util/qquickanimation_p_p.h b/src/quick/util/qquickanimation_p_p.h
index b37680e92a..56121221bf 100644
--- a/src/quick/util/qquickanimation_p_p.h
+++ b/src/quick/util/qquickanimation_p_p.h
@@ -125,7 +125,7 @@ public:
};
//animates QQuickBulkValueUpdater (assumes start and end values will be reals or compatible)
-class Q_AUTOTEST_EXPORT QQuickBulkValueAnimator : public QAbstractAnimationJob
+class Q_QUICK_AUTOTEST_EXPORT QQuickBulkValueAnimator : public QAbstractAnimationJob
{
Q_DISABLE_COPY(QQuickBulkValueAnimator)
public:
diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp
index e18e31c023..bdb47653df 100644
--- a/src/quick/util/qquickanimatorjob.cpp
+++ b/src/quick/util/qquickanimatorjob.cpp
@@ -280,6 +280,17 @@ qreal QQuickAnimatorJob::progress(int time) const
return m_easing.valueForProgress((m_duration == 0) ? qreal(1) : qreal(time) / qreal(m_duration));
}
+void QQuickAnimatorJob::boundValue()
+{
+ qreal rangeMin = m_from;
+ qreal rangeMax = m_to;
+ if (m_from > m_to) {
+ rangeMax = m_from;
+ rangeMin = m_to;
+ }
+ m_value = qBound(rangeMin, m_value, rangeMax);
+}
+
qreal QQuickAnimatorJob::value() const
{
qreal value = m_to;
@@ -383,11 +394,12 @@ void QQuickTransformAnimatorJob::Helper::sync()
wasSynced = true;
}
+ // We update the node before checking on dirty, as the node might have changed without the animator running
+ node = d->itemNode();
+
if (dirty == 0)
return;
- node = d->itemNode();
-
if (dirty & QQuickItemPrivate::Position) {
dx = item->x();
dy = item->y();
diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h
index 2aa0e1a380..171c0b302f 100644
--- a/src/quick/util/qquickanimatorjob_p.h
+++ b/src/quick/util/qquickanimatorjob_p.h
@@ -120,10 +120,16 @@ public:
virtual void setTarget(QQuickItem *target);
QQuickItem *target() const { return m_target; }
- void setFrom(qreal from) { m_from = from; }
+ void setFrom(qreal from) {
+ m_from = from;
+ boundValue();
+ }
qreal from() const { return m_from; }
- void setTo(qreal to) { m_to = to; }
+ void setTo(qreal to) {
+ m_to = to;
+ boundValue();
+ }
qreal to() const { return m_to; }
void setDuration(int duration) { m_duration = duration; }
@@ -169,6 +175,7 @@ protected:
void debugAnimation(QDebug d) const override;
qreal progress(int time) const;
+ void boundValue();
QPointer<QQuickItem> m_target;
QQuickAnimatorController *m_controller;
diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp
index fa67823824..fdd9cb2f13 100644
--- a/src/quick/util/qquickapplication.cpp
+++ b/src/quick/util/qquickapplication.cpp
@@ -50,11 +50,177 @@
QT_BEGIN_NAMESPACE
-/*
- This object and its properties are documented as part of the Qt object,
- in qqmlengine.cpp
+/*!
+ \qmltype Application
+ \instantiates QQuickApplication
+ \inqmlmodule QtQuick
+ //! once exposed: \inherits CoreApplication?
+ //! TODO: \ingroup ?
+
+ \brief Provides access to global application
+ state properties shared by many QML components.
+
+ The Application singleton exposes a subset of QApplication's properties to
+ QML applications.
+
+ It also provides an aboutToQuit() signal, which is the same as
+ QCoreApplication::aboutToQuit().
+
+ \qml
+ import QtQuick
+
+ Window {
+ id: root
+ visible: true
+ width: 800
+ height: 680
+
+ title: `${Application.name} (${Application.version})`
+
+ Connections {
+ target: Application
+ function onAboutToQuit() {
+ console.log("Bye!")
+ }
+ }
+ }
+ \endqml
+
+ \sa SystemPalette
+*/
+
+/*!
+ \qmlproperty bool Application::active
+ \deprecated [5.2]
+
+ Returns whether the application is active.
+ Use Application.state == Qt.ApplicationActive instead
+*/
+
+/*!
+ \qmlproperty Qt::ApplicationState Application::state
+
+ This property represents the current state of the application.
+
+ \qml
+ Timer {
+ interval: 1000; repeat: true
+ active: Application.state === Qt.Qt.ApplicationActive
+ onTriggered: imageFetcher.fetchLatestImages()
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty Qt::LayoutDirection Application::layoutDirection
+
+ This read-only property can be used to query the default layout
+ direction of the application. On system start-up, the default layout
+ direction depends on the application's language. The property has a
+ value of \c Qt.RightToLeft in locales where text and graphic elements
+ are read from right to left, and \c Qt.LeftToRight where the reading
+ direction flows from left to right. You can bind to this property to
+ customize your application layouts to support both layout directions.
+
+ \qml
+ RowLayout {
+ layoutDirection: Application.layoutDirection
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty bool Application::supportsMultipleWindows
+
+ Returns \c true if the platform supports multiple windows. Some embedded
+ platforms do not support multiple windows, for example.
+ */
+
+/*!
+ \qmlproperty QFont Application::font
+ Returns the default application font as returned by
+ \l QGuiApplication::font().
*/
+
+/*!
+ \qmlproperty QString Application::displayName
+
+ This property represents the application display name set on the
+ QGuiApplication instance. This property can be written to in order to set
+ the application display name.
+
+ \qml
+ Binding {
+ target: Application
+ property: "displayName"
+ value: "My Awesome Application"
+ }
+ \endqml
+*/
+
+/*!
+ \qmlproperty QQmlListProperty<QQuickScreenInfo> Application::screens
+
+ An array containing the descriptions of all connected screens. The
+ elements of the array are objects with the same properties as the
+ \l{Screen} attached object. In practice the array corresponds to the screen
+ list returned by QGuiApplication::screens(). In addition to examining
+ properties like name, width, height, etc., the array elements can also be
+ assigned to the screen property of Window items, thus serving as an
+ alternative to the C++ side's QWindow::setScreen().
+
+ \sa Screen, Window, {Window::screen}{Window.screen}
+*/
+
+/* The following properties are from QQmlApplication.
+ ### Document those in QQmlApplication instead once it is exposed
+*/
+
+/*!
+ \qmlproperty QStringList Application::arguments
+
+ This is a string list of the arguments the executable was invoked with.
+ */
+
+/*!
+ \qmlproperty QString Application::name
+
+ This is the application name set on the QCoreApplication instance. This
+ property can be written to in order to set the application name.
+ */
+
+/*!
+ \qmlproperty QString Application::version
+
+ This is the application version set on the QCoreApplication instance. This
+ property can be written to in order to set the application version.
+ */
+
+/*!
+ \qmlproperty QString Application::organization
+
+ This is the organization name set on the QCoreApplication instance.
+ This property can be written to in order to set the organization name.
+ */
+
+/*!
+ \qmlproperty QString Application::domain
+
+ This is the organization domain set on the QCoreApplication instance.
+ This property can be written to in order to set the organization domain.
+ */
+
+/*!
+ \qmlsignal Application::aboutToQuit()
+
+ This signal is emitted when the application is about to quit the main
+ event loop. The signal is particularly useful if your application has to
+ do some last-second cleanup. User interaction is not possible in this state.
+ For more information, see \l {Window::closing()}{Window.closing}.
+
+ \sa QCoreApplication::aboutToQuit
+*/
QQuickApplication::QQuickApplication(QObject *parent)
: QQmlApplication(parent)
{
diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp
index eeda609816..402c23e2af 100644
--- a/src/quick/util/qquickbehavior.cpp
+++ b/src/quick/util/qquickbehavior.cpp
@@ -109,8 +109,13 @@ public:
const QUntypedPropertyBinding &binding)
{
auto This = static_cast<UntypedProxyProperty *>(d);
- if (binding.valueMetaType() != This->type())
+ const QMetaType type = This->type();
+ if (binding.valueMetaType() != type)
return {};
+
+ // We want to notify in any case here because the target property should be set
+ // even if our proxy binding results in the default value.
+ QPropertyBindingPrivate::get(binding)->scheduleNotify();
return This->m_bindingData.setBinding(binding,
reinterpret_cast<QUntypedPropertyData *>(
This->m_storage.data()));
diff --git a/src/quick/util/qquickdeliveryagent.cpp b/src/quick/util/qquickdeliveryagent.cpp
index 344024ab7c..b8167ebed3 100644
--- a/src/quick/util/qquickdeliveryagent.cpp
+++ b/src/quick/util/qquickdeliveryagent.cpp
@@ -39,6 +39,7 @@
#include <QtCore/qdebug.h>
#include <QtGui/private/qevent_p.h>
+#include <QtGui/private/qeventpoint_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qpa/qplatformtheme.h>
#include <QtQml/private/qabstractanimationjob_p.h>
@@ -49,7 +50,7 @@
#include <QtQuick/private/qquickdrag_p.h>
#endif
#include <QtQuick/private/qquickprofiler_p.h>
-#include <QtQuick/qquickrendercontrol.h>
+#include <QtQuick/private/qquickrendercontrol_p.h>
#include <QtQuick/private/qquickwindow_p.h>
QT_BEGIN_NAMESPACE
@@ -81,6 +82,7 @@ void QQuickDeliveryAgentPrivate::touchToMouseEvent(QEvent::Type type, const QEve
(type == QEvent::MouseButtonRelease ? Qt::NoButton : Qt::LeftButton),
touchEvent->modifiers(), Qt::MouseEventSynthesizedByQt);
ret.setAccepted(true); // this now causes the persistent touchpoint to be accepted too
+ ret.setTimestamp(touchEvent->timestamp());
*mouseEvent = ret;
}
@@ -237,7 +239,7 @@ bool QQuickDeliveryAgentPrivate::deliverTouchAsMouse(QQuickItem *item, QTouchEve
if (item->acceptHoverEvents() && p.globalPosition() != QGuiApplicationPrivate::lastCursorPosition) {
QPointF localMousePos(qInf(), qInf());
if (QWindow *w = item->window())
- localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint()));
+ localMousePos = item->mapFromScene(w->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition));
QMouseEvent mm(QEvent::MouseMove, localMousePos, QGuiApplicationPrivate::lastCursorPosition,
Qt::NoButton, Qt::NoButton, event.modifiers());
QCoreApplication::sendEvent(item, &mm);
@@ -316,7 +318,7 @@ void QQuickDeliveryAgentPrivate::translateTouchEvent(QTouchEvent *touchEvent)
static inline bool windowHasFocus(QQuickWindow *win)
{
const QWindow *focusWindow = QGuiApplication::focusWindow();
- return win == focusWindow || QQuickRenderControl::renderWindowFor(win) == focusWindow;
+ return win == focusWindow || QQuickRenderControlPrivate::isRenderWindowFor(win, focusWindow) || !focusWindow;
}
#ifdef Q_OS_WEBOS
@@ -399,7 +401,9 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
if (oldSubFocusItem) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
+ QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
+ priv->focus = false;
+ priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
changed << oldSubFocusItem;
}
@@ -415,6 +419,7 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *
#endif
) {
itemPrivate->focus = true;
+ itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
changed << item;
}
}
@@ -454,7 +459,7 @@ void QQuickDeliveryAgentPrivate::setFocusInScope(QQuickItem *scope, QQuickItem *
emit rootItem->window()->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
if (isSubsceneAgent) {
auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
qCDebug(lcFocus) << " delegating setFocusInScope to" << da;
@@ -516,14 +521,18 @@ void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem
if (item != rootItem && !(options & DontChangeSubFocusItem)) {
QQuickItem *oldSubFocusItem = scopePrivate->subFocusItem;
if (oldSubFocusItem && !(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(oldSubFocusItem)->focus = false;
+ QQuickItemPrivate *priv = QQuickItemPrivate::get(oldSubFocusItem);
+ priv->focus = false;
+ priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, oldSubFocusItem, reason);
changed << oldSubFocusItem;
}
QQuickItemPrivate::get(item)->updateSubFocusItem(scope, false);
} else if (!(options & DontChangeFocusProperty)) {
- QQuickItemPrivate::get(item)->focus = false;
+ QQuickItemPrivate *priv = QQuickItemPrivate::get(item);
+ priv->focus = false;
+ priv->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
changed << item;
}
@@ -550,8 +559,12 @@ void QQuickDeliveryAgentPrivate::clearFocusInScope(QQuickItem *scope, QQuickItem
emit rootItem->window()->focusObjectChanged(activeFocusItem);
if (!changed.isEmpty())
- notifyFocusChangesRecur(changed.data(), changed.count() - 1);
-
+ notifyFocusChangesRecur(changed.data(), changed.count() - 1, reason);
+ if (isSubsceneAgent) {
+ auto da = QQuickWindowPrivate::get(rootItem->window())->deliveryAgent;
+ qCDebug(lcFocus) << " delegating clearFocusInScope to" << da;
+ QQuickWindowPrivate::get(rootItem->window())->deliveryAgentPrivate()->clearFocusInScope(da->rootItem(), item, reason, options);
+ }
if (oldActiveFocusItem == activeFocusItem)
qCDebug(lcFocus) << "activeFocusItem remains" << activeFocusItem << "in" << q;
else
@@ -566,27 +579,29 @@ void QQuickDeliveryAgentPrivate::clearFocusObject()
clearFocusInScope(rootItem, QQuickItemPrivate::get(rootItem)->subFocusItem, Qt::OtherFocusReason);
}
-void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining)
+void QQuickDeliveryAgentPrivate::notifyFocusChangesRecur(QQuickItem **items, int remaining, Qt::FocusReason reason)
{
QPointer<QQuickItem> item(*items);
- if (remaining)
- notifyFocusChangesRecur(items + 1, remaining - 1);
-
if (item) {
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (itemPrivate->notifiedFocus != itemPrivate->focus) {
itemPrivate->notifiedFocus = itemPrivate->focus;
+ itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
emit item->focusChanged(itemPrivate->focus);
}
if (item && itemPrivate->notifiedActiveFocus != itemPrivate->activeFocus) {
itemPrivate->notifiedActiveFocus = itemPrivate->activeFocus;
itemPrivate->itemChange(QQuickItem::ItemActiveFocusHasChanged, itemPrivate->activeFocus);
+ itemPrivate->notifyChangeListeners(QQuickItemPrivate::Focus, &QQuickItemChangeListener::itemFocusChanged, item, reason);
emit item->activeFocusChanged(itemPrivate->activeFocus);
}
}
+
+ if (remaining)
+ notifyFocusChangesRecur(items + 1, remaining - 1, reason);
}
bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
@@ -598,13 +613,14 @@ bool QQuickDeliveryAgentPrivate::clearHover(ulong timestamp)
if (!window)
return false;
- const QPointF lastPos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition.toPoint());
+ const QPointF lastPos = window->mapFromGlobal(QGuiApplicationPrivate::lastCursorPosition);
const auto modifiers = QGuiApplication::keyboardModifiers();
const bool clearHover = true;
for (auto hoverItem : hoverItems) {
auto item = hoverItem.first;
- deliverHoverEventToItem(item, lastPos, lastPos, modifiers, timestamp, clearHover);
+ if (item)
+ deliverHoverEventToItem(item, lastPos, lastPos, modifiers, timestamp, clearHover);
}
hoverItems.clear();
@@ -960,9 +976,6 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
const QPointF &scenePos, const QPointF &lastScenePos,
Qt::KeyboardModifiers modifiers, ulong timestamp)
{
- if (!QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled)
- return false;
-
// The first time this function is called, hoverItems is empty.
// We then call deliverHoverEventRecursive from the rootItem, and
// populate the list with all the children and grandchildren that
@@ -978,10 +991,19 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
// visit will still have an old hoverId. We can therefore go through the
// list at the end of this function and look for items with an old hoverId,
// remove them from the list, and update their state accordingly.
- currentHoverId++;
+ const bool subtreeHoverEnabled = QQuickItemPrivate::get(rootItem)->subtreeHoverEnabled;
const bool itemsWasHovered = !hoverItems.isEmpty();
- deliverHoverEventRecursive(rootItem, scenePos, lastScenePos, modifiers, timestamp);
+
+ if (!subtreeHoverEnabled && !itemsWasHovered)
+ return false;
+
+ currentHoverId++;
+
+ if (subtreeHoverEnabled) {
+ hoveredLeafItemFound = false;
+ deliverHoverEventRecursive(rootItem, scenePos, lastScenePos, modifiers, timestamp);
+ }
// Prune the list for items that are no longer hovered
for (auto it = hoverItems.begin(); it != hoverItems.end();) {
@@ -1012,10 +1034,11 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
accepted, recursion stops. Returns \c true in that case, or \c false if the
event is rejected.
- All items that have hover enabled (either explicitly, from
- setAcceptHoverEvents(), or implicitly by having HoverHandlers) will have
- the QQuickItemPrivate::hoverEnabled flag set. And all their anchestors will
- have the QQuickItemPrivate::subtreeHoverEnabledset. This function will
+ Each item that has hover enabled (from setAcceptHoverEvents()) has the
+ QQuickItemPrivate::hoverEnabled flag set. This only controls whether we
+ should send hover events to the item itself. (HoverHandlers no longer set
+ this flag.) When an item has hoverEnabled set, all its ancestors have the
+ QQuickItemPrivate::subtreeHoverEnabled set. This function will
follow the subtrees that have subtreeHoverEnabled by recursing into each
child with that flag set. And for each child (in addition to the item
itself) that also has hoverEnabled set, we call deliverHoverEventToItem()
@@ -1026,6 +1049,20 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEvent(
end up as the only one hovered. Any other HoverHandler that may be a child
of an item that is stacked underneath, will not. Note that since siblings
can overlap, there can be more than one leaf item under the mouse.
+
+ Note that HoverHandler doesn't set the hoverEnabled flag on the parent item.
+ But still, adding a HoverHandler to an item will set its subtreeHoverEnabled flag.
+ So all the propagation logic described above will otherwise be the same.
+ But the hoverEnabled flag can be used to resolve if subtreeHoverEnabled is on
+ because the application explicitly requested it (setAcceptHoverEvents()), or
+ indirectly, because the item has HoverHandlers.
+
+ For legacy reasons (Qt 6.1), as soon as we find a leaf item that has hover
+ enabled, and therefore receives the event, we stop recursing into the remaining
+ siblings (even if the event was ignored). This means that we only allow hover
+ events to propagate up the direct parent-child hierarchy, and not to siblings.
+ However, if the first candidate HoverHandler is disabled, delivery continues
+ to the next one, which may be a sibling (QTBUG-106548).
*/
bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
QQuickItem *item, const QPointF &scenePos, const QPointF &lastScenePos,
@@ -1055,12 +1092,15 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventRecursive(
// Stop propagation / recursion
return true;
}
+ if (hoveredLeafItemFound) {
+ // Don't propagate to siblings, only to ancestors
+ break;
+ }
}
// All decendants have been visited.
// Now deliver the event to the item
- if (itemPrivate->hoverEnabled)
- return deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, false);
+ return deliverHoverEventToItem(item, scenePos, lastScenePos, modifiers, timestamp, false);
// Continue propagation / recursion
return false;
@@ -1087,11 +1127,17 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
qCDebug(lcHoverTrace) << "item:" << item << "scene pos:" << scenePos << "localPos:" << localPos
<< "wasHovering:" << wasHovering << "isHovering:" << isHovering;
- // Send enter/move/leave event to the item
bool accepted = false;
- if (isHovering && !clearHover) {
+
+ // Start by sending out enter/move/leave events to the item.
+ // Note that hoverEnabled only controls if we should send out hover events to the
+ // item itself. HoverHandlers are not included, and are dealt with separately below.
+ if (itemPrivate->hoverEnabled && isHovering && !clearHover) {
// Add the item to the list of hovered items (if it doesn't exist there
// from before), and update hoverId to mark that it's (still) hovered.
+ // Also set hoveredLeafItemFound, so that only propagate in a straight
+ // line towards the root from now on.
+ hoveredLeafItemFound = true;
hoverItems[item] = currentHoverId;
if (wasHovering)
accepted = sendHoverEvent(QEvent::HoverMove, item, scenePos, lastScenePos, modifiers, timestamp);
@@ -1106,6 +1152,7 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
if (!itemPrivate->hasPointerHandlers())
return accepted;
+ // Next, send out hover events to the hover handlers.
// If the item didn't accept the hover event, 'accepted' is now false.
// Otherwise it's true, and then it should stay the way regardless of
// whether or not the hoverhandlers themselves are hovered.
@@ -1119,6 +1166,8 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
+ if (!hh->isHovered())
+ continue;
hoverEvent.setAccepted(true);
QCoreApplication::sendEvent(hh, &hoverEvent);
}
@@ -1129,11 +1178,14 @@ bool QQuickDeliveryAgentPrivate::deliverHoverEventToItem(
for (QQuickPointerHandler *h : itemPrivate->extra->pointerHandlers) {
if (QQuickHoverHandler *hh = qmlobject_cast<QQuickHoverHandler *>(h)) {
+ if (!hh->enabled())
+ continue;
hoverEvent.setAccepted(true);
hh->handlePointerEvent(&hoverEvent);
if (hh->isHovered()) {
// Mark the whole item as updated, even if only the handler is
// actually in a hovered state (because of HoverHandler.margins)
+ hoveredLeafItemFound = true;
hoverItems[item] = currentHoverId;
}
}
@@ -1181,6 +1233,8 @@ bool QQuickDeliveryAgentPrivate::deliverTouchCancelEvent(QTouchEvent *event)
const_cast<QPointingDevicePrivate *>(QPointingDevicePrivate::get(event->pointingDevice()))->
sendTouchCancelEvent(event);
+ cancelTouchMouseSynthesis();
+
return true;
}
@@ -1191,6 +1245,7 @@ void QQuickDeliveryAgentPrivate::deliverDelayedTouchEvent()
// event loop recursions (e.g if it the touch starts a dnd session).
QScopedPointer<QTouchEvent> e(delayedTouch.take());
qCDebug(lcTouchCmprs) << "delivering" << e.data();
+ compressedTouchCount = 0;
deliverPointerEvent(e.data());
}
@@ -1281,6 +1336,15 @@ bool QQuickDeliveryAgentPrivate::anyPointGrabbed(const QPointerEvent *ev)
return false;
}
+bool QQuickDeliveryAgentPrivate::allPointsGrabbed(const QPointerEvent *ev)
+{
+ for (const auto &point : ev->points()) {
+ if (!ev->exclusiveGrabber(point) && ev->passiveGrabbers(point).isEmpty())
+ return false;
+ }
+ return true;
+}
+
bool QQuickDeliveryAgentPrivate::isMouseEvent(const QPointerEvent *ev)
{
switch (ev->type()) {
@@ -1347,10 +1411,40 @@ QQuickPointingDeviceExtra *QQuickDeliveryAgentPrivate::deviceExtra(const QInputD
return extra;
}
+/*!
+ \internal
+ This function is called from handleTouchEvent() in case a series of touch
+ events containing only \c Updated and \c Stationary points arrives within a
+ short period of time. (Some touchscreens are more "jittery" than others.)
+
+ It would be a waste of CPU time to deliver events and have items in the
+ scene getting modified more often than once per frame; so here we try to
+ coalesce the series of updates into a single event containing all updates
+ that occur within one frame period, and deliverDelayedTouchEvent() is
+ called from flushFrameSynchronousEvents() to send that single event. This
+ is the reason why touch compression lives here so far, instead of in a
+ lower layer: the render loop updates the scene in sync with the screen's
+ vsync, and flushFrameSynchronousEvents() is called from there (for example
+ from QSGThreadedRenderLoop::polishAndSync(), and equivalent places in other
+ render loops). It would be preferable to move this code down to a lower
+ level eventually, though, because it's not fundamentally a Qt Quick concern.
+
+ This optimization can be turned off by setting the environment variable
+ \c QML_NO_TOUCH_COMPRESSION.
+
+ Returns \c true if "done", \c false if the caller needs to finish the
+ \a event delivery.
+*/
bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
{
+ // If this is a subscene agent, don't store any events, because
+ // flushFrameSynchronousEvents() is only called on the window's DA.
+ if (isSubsceneAgent)
+ return false;
+
QEventPoint::States states = event->touchPointStates();
if (states.testFlag(QEventPoint::State::Pressed) || states.testFlag(QEventPoint::State::Released)) {
+ qCDebug(lcTouchCmprs) << "no compression" << event;
// we can only compress an event that doesn't include any pressed or released points
return false;
}
@@ -1358,7 +1452,12 @@ bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
if (!delayedTouch) {
delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), event->points()));
delayedTouch->setTimestamp(event->timestamp());
- qCDebug(lcTouchCmprs) << "delayed" << delayedTouch.data();
+ for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
+ auto &tp = delayedTouch->point(i);
+ QMutableEventPoint::from(tp).detach();
+ }
+ ++compressedTouchCount;
+ qCDebug(lcTouchCmprs) << "delayed" << compressedTouchCount << delayedTouch.data();
if (QQuickWindow *window = rootItem->window())
window->maybeUpdate();
return true;
@@ -1392,7 +1491,14 @@ bool QQuickDeliveryAgentPrivate::compressTouchEvent(QTouchEvent *event)
// TODO optimize, or move event compression elsewhere
delayedTouch.reset(new QMutableTouchEvent(event->type(), event->pointingDevice(), event->modifiers(), tpts));
delayedTouch->setTimestamp(event->timestamp());
- qCDebug(lcTouchCmprs) << "coalesced" << delayedTouch.data();
+ for (qsizetype i = 0; i < delayedTouch->pointCount(); ++i) {
+ auto &tp = delayedTouch->point(i);
+ QMutableEventPoint::from(tp).detach();
+ }
+ ++compressedTouchCount;
+ qCDebug(lcTouchCmprs) << "coalesced" << compressedTouchCount << delayedTouch.data();
+ if (QQuickWindow *window = rootItem->window())
+ window->maybeUpdate();
return true;
}
}
@@ -1690,9 +1796,17 @@ void QQuickDeliveryAgentPrivate::deliverPointerEvent(QPointerEvent *event)
if (event->isEndEvent())
deliverPressOrReleaseEvent(event, true);
- // failsafe: never allow touch->mouse synthesis to persist after release
- if (event->isEndEvent() && isTouchEvent(event))
- cancelTouchMouseSynthesis();
+ // failsafe: never allow touch->mouse synthesis to persist after all touchpoints are released,
+ // or after the touchmouse is released
+ if (isTouchEvent(event) && touchMouseId >= 0) {
+ if (static_cast<QTouchEvent *>(event)->touchPointStates() == QEventPoint::State::Released) {
+ cancelTouchMouseSynthesis();
+ } else {
+ auto touchMousePoint = event->pointById(touchMouseId);
+ if (touchMousePoint && touchMousePoint->state() == QEventPoint::State::Released)
+ cancelTouchMouseSynthesis();
+ }
+ }
eventsInDelivery.pop();
if (sceneTransform) {
@@ -1744,7 +1858,8 @@ QVector<QQuickItem *> QQuickDeliveryAgentPrivate::pointerTargets(QQuickItem *ite
for (int ii = children.count() - 1; ii >= 0; --ii) {
QQuickItem *child = children.at(ii);
auto childPrivate = QQuickItemPrivate::get(child);
- if (!child->isVisible() || !child->isEnabled() || childPrivate->culled)
+ if (!child->isVisible() || !child->isEnabled() || childPrivate->culled ||
+ (child != item && childPrivate->extra.isAllocated() && childPrivate->extra->subsceneDeliveryAgent))
continue;
if (child != item)
@@ -1833,7 +1948,7 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
return;
// If some points weren't grabbed, deliver only to non-grabber PointerHandlers in reverse paint order
- if (!event->allPointsGrabbed()) {
+ if (!allPointsGrabbed(event)) {
QVector<QQuickItem *> targetItems;
for (auto &point : event->points()) {
// Presses were delivered earlier; not the responsibility of deliverUpdatedTouchPoints.
@@ -1853,7 +1968,7 @@ void QQuickDeliveryAgentPrivate::deliverUpdatedPoints(QPointerEvent *event)
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
localizePointerEvent(event, item);
itemPrivate->handlePointerEvent(event, true); // avoid re-delivering to grabbers
- if (event->allPointsGrabbed())
+ if (allPointsGrabbed(event))
break;
}
}
@@ -2010,21 +2125,19 @@ void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item, b
qCDebug(lcTouch) << "actually delivering" << &touchEvent << " to " << item;
QCoreApplication::sendEvent(item, &touchEvent);
eventAccepted = touchEvent.isAccepted();
- } else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents))) {
+ } else {
// If the touch event wasn't accepted, synthesize a mouse event and see if the item wants it.
- if (!eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton)) {
- // send mouse event
- if (deliverTouchAsMouse(item, &touchEvent))
- eventAccepted = true;
- }
+ if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
+ !eventAccepted && (itemPrivate->acceptedMouseButtons() & Qt::LeftButton))
+ deliverTouchAsMouse(item, &touchEvent);
+ return;
}
+ Q_ASSERT(item->acceptTouchEvents()); // else we would've returned early above
if (eventAccepted) {
- // If the touch was accepted (regardless by whom or in what form),
- // update accepted new points.
bool isPressOrRelease = pointerEvent->isBeginEvent() || pointerEvent->isEndEvent();
for (int i = 0; i < touchEvent.pointCount(); ++i) {
- auto &point = QMutableEventPoint::from(touchEvent.point(i));
+ auto &point = touchEvent.point(i);
// legacy-style delivery: if the item doesn't reject the event, that means it handled ALL the points
point.setAccepted();
// but don't let the root of a subscene implicitly steal the grab from some other item (such as one of its children)
@@ -2048,6 +2161,7 @@ void QQuickDeliveryAgentPrivate::deliverMatchingPointsToItem(QQuickItem *item, b
#if QT_CONFIG(quick_draganddrop)
void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QEvent *event)
{
+ QObject *formerTarget = grabber->target();
grabber->resetTarget();
QQuickDragGrabber::iterator grabItem = grabber->begin();
if (grabItem != grabber->end()) {
@@ -2073,6 +2187,7 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
QDragLeaveEvent leaveEvent;
for (; grabItem != grabber->end(); grabItem = grabber->release(grabItem))
QCoreApplication::sendEvent(**grabItem, &leaveEvent);
+ grabber->ignoreList().clear();
return;
} else {
QDragMoveEvent *moveEvent = static_cast<QDragMoveEvent *>(event);
@@ -2091,7 +2206,8 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
moveEvent->buttons(),
moveEvent->modifiers());
QQuickDropEventEx::copyActions(&enterEvent, *moveEvent);
- event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, &currentGrabItems));
+ event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent, &currentGrabItems,
+ formerTarget));
for (grabItem = grabber->begin(); grabItem != grabber->end(); ++grabItem) {
int i = currentGrabItems.indexOf(**grabItem);
@@ -2129,10 +2245,14 @@ void QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QE
e->modifiers());
QQuickDropEventEx::copyActions(&enterEvent, *e);
event->setAccepted(deliverDragEvent(grabber, rootItem, &enterEvent));
+ } else {
+ grabber->ignoreList().clear();
}
}
-bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event, QVarLengthArray<QQuickItem*, 64> *currentGrabItems)
+bool QQuickDeliveryAgentPrivate::deliverDragEvent(
+ QQuickDragGrabber *grabber, QQuickItem *item, QDragMoveEvent *event,
+ QVarLengthArray<QQuickItem *, 64> *currentGrabItems, QObject *formerTarget)
{
QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
if (!item->isVisible() || !item->isEnabled() || QQuickItemPrivate::get(item)->culled)
@@ -2140,8 +2260,13 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
QPointF p = item->mapFromScene(event->position().toPoint());
bool itemContained = item->contains(p);
- if (!itemContained && itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape) {
- return false;
+ const int itemIndex = grabber->ignoreList().indexOf(item);
+ if (!itemContained) {
+ if (itemIndex >= 0)
+ grabber->ignoreList().remove(itemIndex);
+
+ if (itemPrivate->flags & QQuickItem::ItemClipsChildrenToShape)
+ return false;
}
QDragEnterEvent enterEvent(
@@ -2157,7 +2282,7 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
for (int ii = children.count() - 1; ii >= 0; --ii) {
if (children.at(ii)->z() < 0)
continue;
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
return true;
}
@@ -2171,13 +2296,24 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
}
if (event->type() == QEvent::DragMove || itemPrivate->flags & QQuickItem::ItemAcceptsDrops) {
- QDragMoveEvent translatedEvent(
- p.toPoint(),
- event->possibleActions(),
- event->mimeData(),
- event->buttons(),
- event->modifiers(),
- event->type());
+ if (event->type() == QEvent::DragEnter) {
+ if (formerTarget) {
+ QQuickItem *formerTargetItem = qobject_cast<QQuickItem *>(formerTarget);
+ if (formerTargetItem && currentGrabItems) {
+ QDragLeaveEvent leaveEvent;
+ QCoreApplication::sendEvent(formerTarget, &leaveEvent);
+
+ // Remove the item from the currentGrabItems so a leave event won't be generated
+ // later on
+ currentGrabItems->removeAll(formerTarget);
+ }
+ } else if (itemIndex >= 0) {
+ return false;
+ }
+ }
+
+ QDragMoveEvent translatedEvent(p.toPoint(), event->possibleActions(), event->mimeData(),
+ event->buttons(), event->modifiers(), event->type());
QQuickDropEventEx::copyActions(&translatedEvent, *event);
translatedEvent.setAccepted(event->isAccepted());
QCoreApplication::sendEvent(item, &translatedEvent);
@@ -2188,6 +2324,8 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
grabber->grab(item);
grabber->setTarget(item);
return true;
+ } else if (itemIndex < 0) {
+ grabber->ignoreList().append(item);
}
} else {
return true;
@@ -2199,7 +2337,7 @@ bool QQuickDeliveryAgentPrivate::deliverDragEvent(QQuickDragGrabber *grabber, QQ
for (int ii = children.count() - 1; ii >= 0; --ii) {
if (children.at(ii)->z() >= 0)
continue;
- if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems))
+ if (deliverDragEvent(grabber, children.at(ii), &enterEvent, currentGrabItems, formerTarget))
return true;
}
@@ -2263,8 +2401,11 @@ bool QQuickDeliveryAgentPrivate::sendFilteredPointerEventImpl(QPointerEvent *eve
if (filteringParent->childMouseEventFilter(receiver, &filteringParentTouchEvent)) {
qCDebug(lcTouch) << "touch event intercepted by childMouseEventFilter of " << filteringParent;
skipDelivery.append(filteringParent);
- for (auto point : filteringParentTouchEvent.points())
- event->setExclusiveGrabber(point, filteringParent);
+ for (auto point : filteringParentTouchEvent.points()) {
+ const QQuickItem *exclusiveGrabber = qobject_cast<const QQuickItem *>(event->exclusiveGrabber(point));
+ if (!exclusiveGrabber || !exclusiveGrabber->keepTouchGrab())
+ event->setExclusiveGrabber(point, filteringParent);
+ }
return true;
} else if (Q_LIKELY(QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) &&
!filteringParent->acceptTouchEvents()) {
diff --git a/src/quick/util/qquickdeliveryagent_p_p.h b/src/quick/util/qquickdeliveryagent_p_p.h
index f9095158e8..ed1ec86481 100644
--- a/src/quick/util/qquickdeliveryagent_p_p.h
+++ b/src/quick/util/qquickdeliveryagent_p_p.h
@@ -76,8 +76,8 @@ struct QQuickPointingDeviceExtra {
class Q_QUICK_PRIVATE_EXPORT QQuickDeliveryAgentPrivate : public QObjectPrivate
{
- Q_DECLARE_PUBLIC(QQuickDeliveryAgent)
public:
+ Q_DECLARE_PUBLIC(QQuickDeliveryAgent)
QQuickDeliveryAgentPrivate(QQuickItem *root);
~QQuickDeliveryAgentPrivate();
@@ -95,7 +95,7 @@ public:
void setFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = { });
void clearFocusInScope(QQuickItem *scope, QQuickItem *item, Qt::FocusReason reason, FocusOptions = { });
- static void notifyFocusChangesRecur(QQuickItem **item, int remaining);
+ static void notifyFocusChangesRecur(QQuickItem **item, int remaining, Qt::FocusReason reason);
void clearFocusObject();
void updateFocusItemTransform();
@@ -116,9 +116,11 @@ public:
#if QT_CONFIG(wheelevent)
uint lastWheelEventAccepted = 0;
#endif
+ uchar compressedTouchCount = 0;
bool allowChildEventFiltering = true;
bool allowDoubleClick = true;
bool frameSynchronousHoverEnabled = true;
+ bool hoveredLeafItemFound = false;
bool isSubsceneAgent = false;
static bool subsceneAgentsExist;
@@ -170,6 +172,7 @@ public:
static void localizePointerEvent(QPointerEvent *ev, const QQuickItem *dest);
QList<QObject *> exclusiveGrabbers(QPointerEvent *ev);
static bool anyPointGrabbed(const QPointerEvent *ev);
+ static bool allPointsGrabbed(const QPointerEvent *ev);
static bool isMouseEvent(const QPointerEvent *ev);
static bool isHoverEvent(const QPointerEvent *ev);
static bool isTouchEvent(const QPointerEvent *ev);
@@ -199,7 +202,9 @@ public:
#if QT_CONFIG(quick_draganddrop)
void deliverDragEvent(QQuickDragGrabber *, QEvent *);
- bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *, QVarLengthArray<QQuickItem*, 64> *currentGrabItems = nullptr);
+ bool deliverDragEvent(QQuickDragGrabber *, QQuickItem *, QDragMoveEvent *,
+ QVarLengthArray<QQuickItem *, 64> *currentGrabItems = nullptr,
+ QObject *formerTarget = nullptr);
#endif
static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1);
diff --git a/src/quick/util/qquickfontmetrics.cpp b/src/quick/util/qquickfontmetrics.cpp
index ed9759d25f..b365ade5db 100644
--- a/src/quick/util/qquickfontmetrics.cpp
+++ b/src/quick/util/qquickfontmetrics.cpp
@@ -280,8 +280,8 @@ qreal QQuickFontMetrics::lineWidth() const
string should be drawn.
This method is offered as an imperative alternative to the
- \l {QQuickTextMetrics::advanceWidth}{advanceWidth} property of
- \l {QQuickTextMetrics::advanceWidth}{TextMetrics}.
+ \l {QtQuick::TextMetrics::advanceWidth}{advanceWidth} property of
+ TextMetrics.
\sa {QFontMetricsF::horizontalAdvance()}, {QFontMetricsF::height()}
*/
@@ -297,8 +297,8 @@ qreal QQuickFontMetrics::advanceWidth(const QString &text) const
specified by \a text.
This method is offered as an imperative alternative to the
- \l {QQuickTextMetrics::boundingRect}{boundingRect} property of
- \l {QQuickTextMetrics::boundingRect}{TextMetrics}.
+ \l {QtQuick::TextMetrics::boundingRect}{boundingRect} property of
+ TextMetrics.
\sa {QFontMetricsF::boundingRect()}, tightBoundingRect()
*/
@@ -314,8 +314,8 @@ QRectF QQuickFontMetrics::boundingRect(const QString &text) const
string specified by \a text.
This method is offered as an imperative alternative to the
- \l {QQuickTextMetrics::tightBoundingRect}{tightBoundingRect} property of
- \l {QQuickTextMetrics::tightBoundingRect}{TextMetrics}.
+ \l {QtQuick::TextMetrics::tightBoundingRect}{tightBoundingRect} property of
+ TextMetrics.
\sa {QFontMetricsF::tightBoundingRect()}, boundingRect()
*/
@@ -338,8 +338,8 @@ QRectF QQuickFontMetrics::tightBoundingRect(const QString &text) const
\l {Qt::TextShowMnemonic}.
This method is offered as an imperative alternative to the
- \l {QQuickTextMetrics::elidedText}{elidedText} property of
- \l {QQuickTextMetrics::elidedText}{TextMetrics}.
+ \l {QtQuick::TextMetrics::elidedText}{elidedText} property of
+ TextMetrics.
\sa Qt::TextElideMode, QFontMetricsF::elidedText()
*/
diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp
index b885f0406a..3edce10947 100644
--- a/src/quick/util/qquickimageprovider.cpp
+++ b/src/quick/util/qquickimageprovider.cpp
@@ -469,7 +469,7 @@ QQuickTextureFactory *QQuickImageProvider::requestTexture(const QString &id, QSi
\class QQuickAsyncImageProvider
\since 5.6
\inmodule QtQuick
- \brief The QQuickAsyncImageProvider class provides an interface for for asynchronous control of QML image requests.
+ \brief The QQuickAsyncImageProvider class provides an interface for asynchronous control of QML image requests.
See the \l {imageresponseprovider}{Image Response Provider Example} for a complete implementation.
@@ -681,14 +681,21 @@ QQuickImageResponse *QQuickImageProviderWithOptions::requestImageResponse(const
and \a options. If the calculation otherwise concludes that scaled loading
is not recommended, an invalid size is returned.
*/
-QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options)
+QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options,
+ qreal devicePixelRatio)
{
QSize res;
- if ((requestedSize.width() <= 0 && requestedSize.height() <= 0) || originalSize.isEmpty())
+ const bool formatIsScalable = (format == "svg" || format == "svgz" || format == "pdf");
+ const bool noRequestedSize = requestedSize.width() <= 0 && requestedSize.height() <= 0;
+ if ((noRequestedSize && !formatIsScalable) || originalSize.isEmpty())
return res;
+ // If no sourceSize was set and we're loading an SVG, ensure that we provide
+ // a default size that accounts for DPR so that the image isn't blurry.
+ if (noRequestedSize && formatIsScalable)
+ return originalSize * devicePixelRatio;
+
const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit();
- const bool formatIsScalable = (format == "svg" || format == "svgz" || format == "pdf");
if (!preserveAspectCropOrFit && formatIsScalable && !requestedSize.isEmpty())
return requestedSize;
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 1550e7e65d..0513b477d4 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -419,7 +419,8 @@ static void maybeRemoveAlpha(QImage *image)
static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount,
const QRect &requestRegion, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions,
- QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0)
+ QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0,
+ qreal devicePixelRatio = 1.0)
{
QImageReader imgio(dev);
if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform)
@@ -433,7 +434,7 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
if (frameCount)
*frameCount = imgio.imageCount();
- QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions);
+ QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions, devicePixelRatio);
if (scSize.isValid())
imgio.setScaledSize(scSize);
if (!requestRegion.isNull())
@@ -1334,7 +1335,8 @@ void QQuickPixmapData::removeFromCache()
static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url,
const QRect &requestRegion, const QSize &requestSize,
- const QQuickImageProviderOptions &providerOptions, int frame, bool *ok)
+ const QQuickImageProviderOptions &providerOptions, int frame, bool *ok,
+ qreal devicePixelRatio)
{
if (url.scheme() == QLatin1String("image")) {
QSize readSize;
@@ -1424,7 +1426,8 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q
QImage image;
QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform();
int frameCount;
- if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestRegion, requestSize, providerOptions, &appliedTransform, frame)) {
+ if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestRegion, requestSize,
+ providerOptions, &appliedTransform, frame, devicePixelRatio)) {
*ok = true;
return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestRegion, requestSize,
providerOptions, appliedTransform, frame, frameCount);
@@ -1641,7 +1644,8 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &reques
}
void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &requestRegion, const QSize &requestSize,
- QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount)
+ QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount,
+ qreal devicePixelRatio)
{
if (d) {
d->declarativePixmaps.remove(this);
@@ -1691,7 +1695,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QRect &reques
if (!(options & QQuickPixmap::Asynchronous)) {
bool ok = false;
PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url));
- d = createPixmapDataSync(this, engine, url, requestRegion, requestSize, providerOptions, frame, &ok);
+ d = createPixmapDataSync(this, engine, url, requestRegion, requestSize, providerOptions, frame, &ok, devicePixelRatio);
if (ok) {
PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height())));
if (options & QQuickPixmap::Cache)
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index 87724d6210..5600443d31 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -172,7 +172,8 @@ public:
void load(QQmlEngine *, const QUrl &, const QRect &requestRegion, const QSize &requestSize);
void load(QQmlEngine *, const QUrl &, const QRect &requestRegion, const QSize &requestSize, QQuickPixmap::Options options);
void load(QQmlEngine *, const QUrl &, const QRect &requestRegion, const QSize &requestSize,
- QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1);
+ QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1,
+ qreal devicePixelRatio = 1.0);
void clear();
void clear(QObject *);
@@ -214,7 +215,8 @@ public:
virtual QQuickTextureFactory *requestTexture(const QString &id, QSize *size, const QSize &requestedSize, const QQuickImageProviderOptions &options);
virtual QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize, const QQuickImageProviderOptions &options);
- static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options);
+ static QSize loadSize(const QSize &originalSize, const QSize &requestedSize, const QByteArray &format, const QQuickImageProviderOptions &options,
+ qreal devicePixelRatio = 1.0);
static QQuickImageProviderWithOptions *checkedCast(QQuickImageProvider *provider);
};
diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp
index e7186d349e..4b20912bf6 100644
--- a/src/quick/util/qquickpropertychanges.cpp
+++ b/src/quick/util/qquickpropertychanges.cpp
@@ -240,18 +240,22 @@ public:
void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding)
{
- if (binding->type == QV4::CompiledData::Binding::Type_Object) {
- error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects."));
- return;
- }
-
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_Object:
+ error(compilationUnit->objectAt(binding->value.objectIndex),
+ QQuickPropertyChanges::tr(
+ "PropertyChanges does not support creating state-specific objects."));
+ break;
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
- for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding) {
+ for (quint32 i = 0; i < subObj->nBindings; ++i, ++subBinding)
verifyList(compilationUnit, subBinding);
- }
+ break;
+ }
+ default:
+ break;
}
}
@@ -274,8 +278,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
QString propertyName = propertyPrefix + compilationUnit->stringAt(binding->propertyNameIndex);
- if (binding->type == QV4::CompiledData::Binding::Type_GroupProperty
- || binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
+ switch (binding->type()) {
+ case QV4::CompiledData::Binding::Type_GroupProperty:
+ case QV4::CompiledData::Binding::Type_AttachedProperty: {
QString pre = propertyName + QLatin1Char('.');
const QV4::CompiledData::Object *subObj = compilationUnit->objectAt(binding->value.objectIndex);
const QV4::CompiledData::Binding *subBinding = subObj->bindingTable();
@@ -284,6 +289,9 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
return;
}
+ default:
+ break;
+ }
if (propertyName.count() >= 3 &&
propertyName.at(0) == QLatin1Char('o') &&
@@ -303,7 +311,8 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
}
- if (binding->type == QV4::CompiledData::Binding::Type_Script || binding->isTranslationBinding()) {
+ if (binding->type() == QV4::CompiledData::Binding::Type_Script
+ || binding->isTranslationBinding()) {
QUrl url = QUrl();
int line = -1;
int column = -1;
@@ -327,7 +336,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
}
QVariant var;
- switch (binding->type) {
+ switch (binding->type()) {
case QV4::CompiledData::Binding::Type_Script:
case QV4::CompiledData::Binding::Type_Translation:
case QV4::CompiledData::Binding::Type_TranslationById:
diff --git a/src/quick/util/qquicksmoothedanimation.cpp b/src/quick/util/qquicksmoothedanimation.cpp
index 254b1af0a2..d511dc0562 100644
--- a/src/quick/util/qquicksmoothedanimation.cpp
+++ b/src/quick/util/qquicksmoothedanimation.cpp
@@ -569,4 +569,6 @@ void QQuickSmoothedAnimation::setMaximumEasingTime(int v)
QT_END_NAMESPACE
+#include "moc_qquicksmoothedanimation_p_p.cpp"
+
#include "moc_qquicksmoothedanimation_p.cpp"
diff --git a/src/quick/util/qquickstatechangescript.cpp b/src/quick/util/qquickstatechangescript.cpp
index f971d7e551..8e978a2943 100644
--- a/src/quick/util/qquickstatechangescript.cpp
+++ b/src/quick/util/qquickstatechangescript.cpp
@@ -149,8 +149,6 @@ QQuickStateActionEvent::EventType QQuickStateChangeScript::type() const
return Script;
}
-
-#include <moc_qquickstatechangescript_p.cpp>
-
QT_END_NAMESPACE
+#include <moc_qquickstatechangescript_p.cpp>
diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp
index b86333943c..5d28c7bc0c 100644
--- a/src/quick/util/qquickstategroup.cpp
+++ b/src/quick/util/qquickstategroup.cpp
@@ -376,7 +376,19 @@ bool QQuickStateGroupPrivate::updateAutoState()
QQuickState *state = states.at(ii);
if (state->isWhenKnown()) {
if (state->isNamed()) {
- if (state->when()) {
+ bool whenValue = state->when();
+ const QQmlProperty whenProp(state, u"when"_qs);
+ const auto potentialWhenBinding = QQmlAnyBinding::ofProperty(whenProp);
+ Q_ASSERT(!potentialWhenBinding.isUntypedPropertyBinding());
+
+ // if there is a binding, the value in when might not be up-to-date at this point
+ // so we manually re-evaluate the binding
+ if (auto binding = dynamic_cast<QQmlBinding *>(potentialWhenBinding.asAbstractBinding())) {
+ if (binding->hasValidContext())
+ whenValue = binding->evaluate().toBool();
+ }
+
+ if (whenValue) {
if (stateChangeDebug())
qWarning() << "Setting auto state due to expression";
if (currentState != state->name()) {
diff --git a/src/quick/util/qquickstyledtext.cpp b/src/quick/util/qquickstyledtext.cpp
index 13ece608be..f402172891 100644
--- a/src/quick/util/qquickstyledtext.cpp
+++ b/src/quick/util/qquickstyledtext.cpp
@@ -583,10 +583,10 @@ bool QQuickStyledTextPrivate::parseFontAttributes(const QChar *&ch, const QStrin
attr = parseAttribute(ch, textIn);
if (attr.first == QLatin1String("color")) {
valid = true;
- format.setForeground(QColor(attr.second.toString()));
+ format.setForeground(QColor(attr.second));
} else if (attr.first == QLatin1String("size")) {
valid = true;
- int size = attr.second.toString().toInt();
+ int size = attr.second.toInt();
if (attr.second.at(0) == QLatin1Char('-') || attr.second.at(0) == QLatin1Char('+'))
size += 3;
if (size >= 1 && size <= 7)
diff --git a/src/quick/util/qquicktimeline.cpp b/src/quick/util/qquicktimeline.cpp
index abe6eb7261..949724e87c 100644
--- a/src/quick/util/qquicktimeline.cpp
+++ b/src/quick/util/qquicktimeline.cpp
@@ -957,3 +957,5 @@ QQuickTimeLineObject *QQuickTimeLineCallback::callbackObject() const
}
QT_END_NAMESPACE
+
+#include "moc_qquicktimeline_p_p.cpp"
diff --git a/src/quick/util/qquicktransition.cpp b/src/quick/util/qquicktransition.cpp
index 9c55454c0e..64394ee285 100644
--- a/src/quick/util/qquicktransition.cpp
+++ b/src/quick/util/qquicktransition.cpp
@@ -82,6 +82,11 @@ QT_BEGIN_NAMESPACE
values can be set to restrict the animations to only be applied when changing
from one particular state to another.
+ Top-level animations within a transition are run in parallel. To run them
+ sequentially, define them within a SequentialAnimation:
+
+ \snippet qml/transition-reversible.qml sequential animations
+
To define multiple Transitions, specify \l Item::transitions as a list:
\snippet qml/transitions-list.qml list of transitions
@@ -229,6 +234,12 @@ void QQuickTransitionInstance::stop()
m_anim->stop();
}
+void QQuickTransitionInstance::complete()
+{
+ if (m_anim)
+ m_anim->complete();
+}
+
bool QQuickTransitionInstance::isRunning() const
{
return m_anim && m_anim->state() == QAbstractAnimationJob::Running;
diff --git a/src/quick/util/qquicktransition_p.h b/src/quick/util/qquicktransition_p.h
index bfb7d75821..ed2ec705b2 100644
--- a/src/quick/util/qquicktransition_p.h
+++ b/src/quick/util/qquicktransition_p.h
@@ -73,6 +73,7 @@ public:
void start();
void stop();
+ void complete();
bool isRunning() const;
diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp
index c309460263..7e93d87555 100644
--- a/src/quick/util/qquickvalidator.cpp
+++ b/src/quick/util/qquickvalidator.cpp
@@ -56,6 +56,8 @@ QT_BEGIN_NAMESPACE
interpret the number and will accept locale specific digits, group separators, and positive
and negative signs. In addition, IntValidator is always guaranteed to accept a number
formatted according to the "C" locale.
+
+ \sa DoubleValidator, RegularExpressionValidator, {Validating Input Text}
*/
QQuickIntValidator::QQuickIntValidator(QObject *parent)
@@ -131,6 +133,8 @@ void QQuickIntValidator::resetLocaleName()
it is also rejected. If \l notation is DoubleValidator.ScientificNotation,
and the input is not in the valid range, it is accecpted but invalid. The
value may yet become valid by changing the exponent.
+
+ \sa IntValidator, RegularExpressionValidator, {Validating Input Text}
*/
QQuickDoubleValidator::QQuickDoubleValidator(QObject *parent)
@@ -210,6 +214,8 @@ void QQuickDoubleValidator::resetLocaleName()
The RegularExpressionValidator type provides a validator, that counts as valid any string which
matches a specified regular expression.
+
+ \sa IntValidator, DoubleValidator, {Validating Input Text}
*/
/*!
\qmlproperty regularExpression QtQuick::RegularExpressionValidator::regularExpression
diff --git a/src/quickcontrols2/CMakeLists.txt b/src/quickcontrols2/CMakeLists.txt
new file mode 100644
index 0000000000..1e04587af0
--- /dev/null
+++ b/src/quickcontrols2/CMakeLists.txt
@@ -0,0 +1,85 @@
+#####################################################################
+## QuickControls2 Module:
+#####################################################################
+
+qt_internal_add_qml_module(QuickControls2
+ URI "QtQuick.Controls"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ DESIGNER_SUPPORTED
+ CLASS_NAME QtQuickControls2Plugin
+ PLUGIN_TARGET qtquickcontrols2plugin
+ IMPORTS
+ QtQuick.Controls.impl/auto
+ OPTIONAL_IMPORTS
+ QtQuick.Controls.Basic/auto
+ QtQuick.Controls.Fusion/auto
+ QtQuick.Controls.Material/auto
+ QtQuick.Controls.Imagine/auto
+ QtQuick.Controls.Universal/auto
+ QtQuick.Controls.Windows/auto
+ QtQuick.Controls.macOS/auto
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickstyle.cpp qquickstyle.h qquickstyle_p.h
+ qquickstyleplugin.cpp qquickstyleplugin_p.h
+ qtquickcontrols2global.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2
+ Qt::QuickTemplates2Private
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+qt_internal_extend_target(qtquickcontrols2plugin
+ SOURCES
+ qtquickcontrols2plugin.cpp
+ LIBRARIES
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickTemplates2Private
+)
+
+if(QT_FEATURE_quick_designer)
+ add_subdirectory(designer)
+endif()
+
+add_subdirectory(basic)
+add_subdirectory(fusion)
+add_subdirectory(imagine)
+add_subdirectory(material)
+add_subdirectory(universal)
+
+if(MACOS)
+ add_subdirectory(macos)
+endif()
+
+if(WIN32)
+ add_subdirectory(windows)
+endif()
+
+qt_internal_add_docs(QuickControls2
+ doc/qtquickcontrols.qdocconf
+)
+
+# Make the doc files available to Creator's locator.
+file(GLOB doc_files
+ "${CMAKE_CURRENT_SOURCE_DIR}/doc/snippets/*.qml"
+ "${CMAKE_CURRENT_SOURCE_DIR}/doc/src/*.qdoc"
+ "${CMAKE_CURRENT_SOURCE_DIR}/doc/src/templates/*.qdoc"
+)
+target_sources(QuickControls2
+ PRIVATE
+ ${doc_files}
+ doc/qtquickcontrols.qdocconf
+)
diff --git a/src/quickcontrols2/basic/AbstractButton.qml b/src/quickcontrols2/basic/AbstractButton.qml
new file mode 100644
index 0000000000..a4855c2197
--- /dev/null
+++ b/src/quickcontrols2/basic/AbstractButton.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.AbstractButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+}
diff --git a/src/quickcontrols2/basic/Action.qml b/src/quickcontrols2/basic/Action.qml
new file mode 100644
index 0000000000..bb66fc8fb5
--- /dev/null
+++ b/src/quickcontrols2/basic/Action.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.Action { }
diff --git a/src/quickcontrols2/basic/ActionGroup.qml b/src/quickcontrols2/basic/ActionGroup.qml
new file mode 100644
index 0000000000..70170f0e4e
--- /dev/null
+++ b/src/quickcontrols2/basic/ActionGroup.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.ActionGroup { }
diff --git a/src/quickcontrols2/basic/ApplicationWindow.qml b/src/quickcontrols2/basic/ApplicationWindow.qml
new file mode 100644
index 0000000000..ac50d5fa79
--- /dev/null
+++ b/src/quickcontrols2/basic/ApplicationWindow.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ApplicationWindow {
+ id: window
+
+ color: window.palette.window
+}
diff --git a/src/quickcontrols2/basic/BusyIndicator.qml b/src/quickcontrols2/basic/BusyIndicator.qml
new file mode 100644
index 0000000000..0c51c9a280
--- /dev/null
+++ b/src/quickcontrols2/basic/BusyIndicator.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Basic.impl
+import QtQuick.Templates as T
+
+T.BusyIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ contentItem: BusyIndicatorImpl {
+ implicitWidth: 48
+ implicitHeight: 48
+
+ pen: control.palette.dark
+ fill: control.palette.dark
+
+ running: control.running
+ opacity: control.running ? 1 : 0
+ Behavior on opacity { OpacityAnimator { duration: 250 } }
+ }
+}
diff --git a/src/quickcontrols2/basic/Button.qml b/src/quickcontrols2/basic/Button.qml
new file mode 100644
index 0000000000..f657a0d243
--- /dev/null
+++ b/src/quickcontrols2/basic/Button.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ padding: 6
+ horizontalPadding: padding + 2
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.checked || control.highlighted ? control.palette.brightText :
+ control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.checked || control.highlighted ? control.palette.brightText :
+ control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: !control.flat || control.down || control.checked || control.highlighted
+ color: Color.blend(control.checked || control.highlighted ? control.palette.dark : control.palette.button,
+ control.palette.mid, control.down ? 0.5 : 0.0)
+ border.color: control.palette.highlight
+ border.width: control.visualFocus ? 2 : 0
+ }
+}
diff --git a/src/quickcontrols2/basic/ButtonGroup.qml b/src/quickcontrols2/basic/ButtonGroup.qml
new file mode 100644
index 0000000000..fadc538a49
--- /dev/null
+++ b/src/quickcontrols2/basic/ButtonGroup.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.ButtonGroup { }
diff --git a/src/quickcontrols2/basic/CMakeLists.txt b/src/quickcontrols2/basic/CMakeLists.txt
new file mode 100644
index 0000000000..b871284b99
--- /dev/null
+++ b/src/quickcontrols2/basic/CMakeLists.txt
@@ -0,0 +1,171 @@
+#####################################################################
+## qtquickcontrols2basicstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "AbstractButton.qml"
+ "Action.qml"
+ "ActionGroup.qml"
+ "ApplicationWindow.qml"
+ "BusyIndicator.qml"
+ "Button.qml"
+ "ButtonGroup.qml"
+ "CheckBox.qml"
+ "CheckDelegate.qml"
+ "ComboBox.qml"
+ "Container.qml"
+ "Control.qml"
+ "DelayButton.qml"
+ "Dial.qml"
+ "Dialog.qml"
+ "DialogButtonBox.qml"
+ "Drawer.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "HorizontalHeaderView.qml"
+ "ItemDelegate.qml"
+ "Label.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
+ "Page.qml"
+ "PageIndicator.qml"
+ "Pane.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RadioDelegate.qml"
+ "RangeSlider.qml"
+ "RoundButton.qml"
+ "ScrollBar.qml"
+ "ScrollIndicator.qml"
+ "ScrollView.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "SplitView.qml"
+ "StackView.qml"
+ "SwipeDelegate.qml"
+ "Switch.qml"
+ "SwitchDelegate.qml"
+ "SwipeView.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "TextArea.qml"
+ "TextField.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "ToolSeparator.qml"
+ "ToolTip.qml"
+ "Tumbler.qml"
+ "VerticalHeaderView.qml"
+)
+set_source_files_properties(Action.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(ActionGroup.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(DelayButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(Dialog.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(DialogButtonBox.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(HorizontalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+set_source_files_properties(MenuBar.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuBarItem.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(RoundButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(ScrollView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(SelectionRectangle.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "6.2"
+)
+set_source_files_properties(SplitView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.13;6.0"
+)
+set_source_files_properties(ToolSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(VerticalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2basicstyleplugin
+ URI "QtQuick.Controls.Basic"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2BasicStylePlugin
+ PLUGIN_TARGET qtquickcontrols2basicstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickbasicstyle.cpp qquickbasicstyle_p.h
+ qquickbasictheme.cpp qquickbasictheme_p.h
+ qtquickcontrols2basicstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+# Resources:
+set(qtquickcontrols2basicstyleplugin_resource_files
+ "images/arrow-indicator.png"
+ "images/arrow-indicator@2x.png"
+ "images/arrow-indicator@3x.png"
+ "images/arrow-indicator@4x.png"
+ "images/check.png"
+ "images/check@2x.png"
+ "images/check@3x.png"
+ "images/check@4x.png"
+ "images/dial-indicator.png"
+ "images/dial-indicator@2x.png"
+ "images/dial-indicator@3x.png"
+ "images/dial-indicator@4x.png"
+ "images/double-arrow.png"
+ "images/double-arrow@2x.png"
+ "images/double-arrow@3x.png"
+ "images/double-arrow@4x.png"
+ "images/drop-indicator.png"
+ "images/drop-indicator@2x.png"
+ "images/drop-indicator@3x.png"
+ "images/drop-indicator@4x.png"
+)
+
+qt_internal_add_resource(qtquickcontrols2basicstyleplugin "qtquickcontrols2basicstyleplugin"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/Basic"
+ FILES
+ ${qtquickcontrols2basicstyleplugin_resource_files}
+)
+
+add_subdirectory(impl)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2basicstyleplugin
+ qtquickcontrols2basicstyleimplplugin)
diff --git a/src/quickcontrols2/basic/CheckBox.qml b/src/quickcontrols2/basic/CheckBox.qml
new file mode 100644
index 0000000000..6465460d33
--- /dev/null
+++ b/src/quickcontrols2/basic/CheckBox.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+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)
+
+ padding: 6
+ spacing: 6
+
+ // keep in sync with CheckDelegate.qml (shared CheckIndicator.qml was removed for performance reasons)
+ indicator: Rectangle {
+ implicitWidth: 28
+ implicitHeight: 28
+
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ color: control.down ? control.palette.light : control.palette.base
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.palette.mid
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ defaultColor: "#353637"
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/check.png"
+ visible: control.checkState === Qt.Checked
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 16
+ height: 3
+ color: control.palette.text
+ visible: control.checkState === Qt.PartiallyChecked
+ }
+ }
+
+ contentItem: CheckLabel {
+ 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.windowText
+ }
+}
diff --git a/src/quickcontrols2/basic/CheckDelegate.qml b/src/quickcontrols2/basic/CheckDelegate.qml
new file mode 100644
index 0000000000..1a1827e30c
--- /dev/null
+++ b/src/quickcontrols2/basic/CheckDelegate.qml
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.CheckDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 12
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ // keep in sync with CheckBox.qml (shared CheckIndicator.qml was removed for performance reasons)
+ indicator: Rectangle {
+ implicitWidth: 28
+ implicitHeight: 28
+
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ color: control.down ? control.palette.light : control.palette.base
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.palette.mid
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ defaultColor: "#353637"
+ color: control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/check.png"
+ visible: control.checkState === Qt.Checked
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 16
+ height: 3
+ color: control.palette.text
+ visible: control.checkState === Qt.PartiallyChecked
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? control.palette.midlight : control.palette.light
+ }
+}
diff --git a/src/quickcontrols2/basic/ComboBox.qml b/src/quickcontrols2/basic/ComboBox.qml
new file mode 100644
index 0000000000..6a1924ed10
--- /dev/null
+++ b/src/quickcontrols2/basic/ComboBox.qml
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+ rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ palette.text: control.palette.text
+ palette.highlightedText: control.palette.highlightedText
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ color: control.palette.dark
+ defaultColor: "#353637"
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/double-arrow.png"
+ opacity: enabled ? 1 : 0.3
+ }
+
+ contentItem: T.TextField {
+ leftPadding: !control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1
+ rightPadding: control.mirrored ? 12 : control.editable && activeFocus ? 3 : 1
+ topPadding: 6 - control.padding
+ bottomPadding: 6 - control.padding
+
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+
+ background: Rectangle {
+ visible: control.enabled && control.editable && !control.flat
+ border.width: parent && parent.activeFocus ? 2 : 1
+ border.color: parent && parent.activeFocus ? control.palette.highlight : control.palette.button
+ color: control.palette.base
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 140
+ implicitHeight: 40
+
+ color: control.down ? control.palette.mid : control.palette.button
+ border.color: control.palette.highlight
+ border.width: !control.editable && control.visualFocus ? 2 : 0
+ visible: !control.flat || control.down
+ }
+
+ popup: T.Popup {
+ y: control.height
+ width: control.width
+ height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
+ topMargin: 6
+ bottomMargin: 6
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ Rectangle {
+ z: 10
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ border.color: control.palette.mid
+ }
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/Container.qml b/src/quickcontrols2/basic/Container.qml
new file mode 100644
index 0000000000..939190755c
--- /dev/null
+++ b/src/quickcontrols2/basic/Container.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.Container {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+}
diff --git a/src/quickcontrols2/basic/Control.qml b/src/quickcontrols2/basic/Control.qml
new file mode 100644
index 0000000000..7a68a43166
--- /dev/null
+++ b/src/quickcontrols2/basic/Control.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.Control {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+}
diff --git a/src/quickcontrols2/basic/DelayButton.qml b/src/quickcontrols2/basic/DelayButton.qml
new file mode 100644
index 0000000000..367384c031
--- /dev/null
+++ b/src/quickcontrols2/basic/DelayButton.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.DelayButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ horizontalPadding: padding + 2
+
+ transition: Transition {
+ NumberAnimation {
+ duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress)
+ }
+ }
+
+ contentItem: ItemGroup {
+ ClippedText {
+ clip: control.progress > 0
+ clipX: -control.leftPadding + control.progress * control.width
+ clipWidth: (1.0 - control.progress) * control.width
+ visible: control.progress < 1
+
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1 : 0.3
+ color: control.palette.buttonText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ ClippedText {
+ clip: control.progress > 0
+ clipX: -control.leftPadding
+ clipWidth: control.progress * control.width
+ visible: control.progress > 0
+
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1 : 0.3
+ color: control.palette.brightText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: Color.blend(control.palette.button, control.palette.mid, control.down ? 0.5 : 0.0)
+ border.color: control.palette.highlight
+ border.width: control.visualFocus ? 2 : 0
+
+ PaddedRectangle {
+ padding: control.visualFocus ? 2 : 0
+ width: control.progress * parent.width
+ height: parent.height
+ color: Color.blend(control.palette.dark, control.palette.mid, control.down ? 0.5 : 0.0)
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/Dial.qml b/src/quickcontrols2/basic/Dial.qml
new file mode 100644
index 0000000000..8450e9f9e5
--- /dev/null
+++ b/src/quickcontrols2/basic/Dial.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Basic.impl
+import QtQuick.Templates as T
+
+T.Dial {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ background: DialImpl {
+ implicitWidth: 184
+ implicitHeight: 184
+ color: control.visualFocus ? control.palette.highlight : control.palette.dark
+ progress: control.position
+ opacity: control.enabled ? 1 : 0.3
+ }
+
+ handle: ColorImage {
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+ width: 14
+ height: 10
+ defaultColor: "#353637"
+ color: control.visualFocus ? control.palette.highlight : control.palette.dark
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/dial-indicator.png"
+ antialiasing: true
+ opacity: control.enabled ? 1 : 0.3
+ transform: [
+ Translate {
+ y: -Math.min(control.background.width, control.background.height) * 0.4 + control.handle.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: control.handle.width / 2
+ origin.y: control.handle.height / 2
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols2/basic/Dialog.qml b/src/quickcontrols2/basic/Dialog.qml
new file mode 100644
index 0000000000..1f2b4fbb6a
--- /dev/null
+++ b/src/quickcontrols2/basic/Dialog.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.Dialog {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.palette.window
+ border.color: control.palette.dark
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 12
+ background: Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 1
+ color: control.palette.window
+ }
+ }
+
+ footer: DialogButtonBox {
+ visible: count > 0
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickcontrols2/basic/DialogButtonBox.qml b/src/quickcontrols2/basic/DialogButtonBox.qml
new file mode 100644
index 0000000000..f69944852c
--- /dev/null
+++ b/src/quickcontrols2/basic/DialogButtonBox.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.DialogButtonBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ (control.count === 1 ? implicitContentWidth * 2 : implicitContentWidth) + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ contentWidth: contentItem.contentWidth
+
+ spacing: 1
+ padding: 12
+ alignment: count === 1 ? Qt.AlignRight : undefined
+
+ delegate: Button {
+ width: control.count === 1 ? control.availableWidth / 2 : undefined
+ }
+
+ contentItem: ListView {
+ implicitWidth: contentWidth
+ model: control.contentModel
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ snapMode: ListView.SnapToItem
+ }
+
+ background: Rectangle {
+ implicitHeight: 40
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/basic/Drawer.qml b/src/quickcontrols2/basic/Drawer.qml
new file mode 100644
index 0000000000..0d286f9910
--- /dev/null
+++ b/src/quickcontrols2/basic/Drawer.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Drawer {
+ id: control
+
+ parent: T.Overlay.overlay
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: control.edge === Qt.BottomEdge
+ leftPadding: control.edge === Qt.RightEdge
+ rightPadding: control.edge === Qt.LeftEdge
+ bottomPadding: control.edge === Qt.TopEdge
+
+ enter: Transition { SmoothedAnimation { velocity: 5 } }
+ exit: Transition { SmoothedAnimation { velocity: 5 } }
+
+ background: Rectangle {
+ color: control.palette.window
+ Rectangle {
+ readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge
+ width: horizontal ? 1 : parent.width
+ height: horizontal ? parent.height : 1
+ color: control.palette.dark
+ x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0
+ y: control.edge === Qt.TopEdge ? parent.height - 1 : 0
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickcontrols2/basic/Frame.qml b/src/quickcontrols2/basic/Frame.qml
new file mode 100644
index 0000000000..22f2980612
--- /dev/null
+++ b/src/quickcontrols2/basic/Frame.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: control.palette.mid
+ }
+}
diff --git a/src/quickcontrols2/basic/GroupBox.qml b/src/quickcontrols2/basic/GroupBox.qml
new file mode 100644
index 0000000000..27ff8ce6e4
--- /dev/null
+++ b/src/quickcontrols2/basic/GroupBox.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 6
+ padding: 12
+ topPadding: padding + (implicitLabelWidth > 0 ? implicitLabelHeight + spacing : 0)
+
+ label: Text {
+ x: control.leftPadding
+ width: control.availableWidth
+
+ text: control.title
+ font: control.font
+ color: control.palette.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ y: control.topPadding - control.bottomPadding
+ width: parent.width
+ height: parent.height - control.topPadding + control.bottomPadding
+
+ color: "transparent"
+ border.color: control.palette.mid
+ }
+}
diff --git a/src/quickcontrols2/basic/HorizontalHeaderView.qml b/src/quickcontrols2/basic/HorizontalHeaderView.qml
new file mode 100644
index 0000000000..e52145932f
--- /dev/null
+++ b/src/quickcontrols2/basic/HorizontalHeaderView.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.HorizontalHeaderView {
+ id: control
+
+ implicitWidth: syncView ? syncView.width : 0
+ implicitHeight: contentHeight
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: text.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(control.height, text.implicitHeight + (cellPadding * 2))
+ color: "#f6f6f6"
+ border.color: "#e4e4e4"
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/ItemDelegate.qml b/src/quickcontrols2/basic/ItemDelegate.qml
new file mode 100644
index 0000000000..3a1cb298b9
--- /dev/null
+++ b/src/quickcontrols2/basic/ItemDelegate.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 8
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? control.palette.highlightedText : control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted || control.visualFocus
+ color: Color.blend(control.down ? control.palette.midlight : control.palette.light,
+ control.palette.highlight, control.visualFocus ? 0.15 : 0.0)
+ }
+}
diff --git a/src/quickcontrols2/basic/Label.qml b/src/quickcontrols2/basic/Label.qml
new file mode 100644
index 0000000000..9d7dfdfdf0
--- /dev/null
+++ b/src/quickcontrols2/basic/Label.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Label {
+ id: control
+
+ color: control.palette.windowText
+ linkColor: control.palette.link
+}
diff --git a/src/quickcontrols2/basic/Menu.qml b/src/quickcontrols2/basic/Menu.qml
new file mode 100644
index 0000000000..475e58ccb8
--- /dev/null
+++ b/src/quickcontrols2/basic/Menu.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 0
+ overlap: 1
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height
+ : false
+ clip: true
+ currentIndex: control.currentIndex
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ color: control.palette.window
+ border.color: control.palette.dark
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickcontrols2/basic/MenuBar.qml b/src/quickcontrols2/basic/MenuBar.qml
new file mode 100644
index 0000000000..79199d121f
--- /dev/null
+++ b/src/quickcontrols2/basic/MenuBar.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: control.palette.button
+ }
+}
diff --git a/src/quickcontrols2/basic/MenuBarItem.qml b/src/quickcontrols2/basic/MenuBarItem.qml
new file mode 100644
index 0000000000..e7fd1c0bea
--- /dev/null
+++ b/src/quickcontrols2/basic/MenuBarItem.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ spacing: 6
+ padding: 6
+ leftPadding: 12
+ rightPadding: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.buttonText
+
+ 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.buttonText
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.down || control.highlighted ? control.palette.mid : "transparent"
+ }
+}
diff --git a/src/quickcontrols2/basic/MenuItem.qml b/src/quickcontrols2/basic/MenuItem.qml
new file mode 100644
index 0000000000..ab1f12f5a9
--- /dev/null
+++ b/src/quickcontrols2/basic/MenuItem.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+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)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.windowText
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+ leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
+ rightPadding: control.mirrored ? indicatorPadding : 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.windowText
+ }
+
+ indicator: ColorImage {
+ x: control.mirrored ? control.width - width - control.rightPadding : control.leftPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.checked
+ source: control.checkable ? "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/check.png" : ""
+ color: control.palette.windowText
+ defaultColor: "#353637"
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.subMenu
+ mirror: control.mirrored
+ source: control.subMenu ? "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/arrow-indicator.png" : ""
+ color: control.palette.windowText
+ defaultColor: "#353637"
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ x: 1
+ y: 1
+ width: control.width - 2
+ height: control.height - 2
+ color: control.down ? control.palette.midlight : control.highlighted ? control.palette.light : "transparent"
+ }
+}
diff --git a/src/quickcontrols2/basic/MenuSeparator.qml b/src/quickcontrols2/basic/MenuSeparator.qml
new file mode 100644
index 0000000000..bc17dc391f
--- /dev/null
+++ b/src/quickcontrols2/basic/MenuSeparator.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+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)
+
+ padding: 2
+ verticalPadding: padding + 4
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ color: control.palette.mid
+ }
+}
diff --git a/src/quickcontrols2/basic/Page.qml b/src/quickcontrols2/basic/Page.qml
new file mode 100644
index 0000000000..ff75ee4ef4
--- /dev/null
+++ b/src/quickcontrols2/basic/Page.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Page {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/basic/PageIndicator.qml b/src/quickcontrols2/basic/PageIndicator.qml
new file mode 100644
index 0000000000..7197333ca7
--- /dev/null
+++ b/src/quickcontrols2/basic/PageIndicator.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.PageIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ delegate: Rectangle {
+ implicitWidth: 8
+ implicitHeight: 8
+
+ radius: width / 2
+ color: control.palette.dark
+
+ opacity: index === control.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
+
+ required property int index
+
+ Behavior on opacity { OpacityAnimator { duration: 100 } }
+ }
+
+ contentItem: Row {
+ spacing: control.spacing
+
+ Repeater {
+ model: control.count
+ delegate: control.delegate
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/Pane.qml b/src/quickcontrols2/basic/Pane.qml
new file mode 100644
index 0000000000..181db9e44f
--- /dev/null
+++ b/src/quickcontrols2/basic/Pane.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Pane {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/basic/Popup.qml b/src/quickcontrols2/basic/Popup.qml
new file mode 100644
index 0000000000..720483d97f
--- /dev/null
+++ b/src/quickcontrols2/basic/Popup.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.palette.window
+ border.color: control.palette.dark
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickcontrols2/basic/ProgressBar.qml b/src/quickcontrols2/basic/ProgressBar.qml
new file mode 100644
index 0000000000..a49538d100
--- /dev/null
+++ b/src/quickcontrols2/basic/ProgressBar.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Basic.impl
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: ProgressBarImpl {
+ implicitHeight: 6
+ implicitWidth: 116
+ scale: control.mirrored ? -1 : 1
+ progress: control.position
+ indeterminate: control.visible && control.indeterminate
+ color: control.palette.dark
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 6
+ y: (control.height - height) / 2
+ height: 6
+
+ color: control.palette.midlight
+ }
+}
diff --git a/src/quickcontrols2/basic/RadioButton.qml b/src/quickcontrols2/basic/RadioButton.qml
new file mode 100644
index 0000000000..adb914357d
--- /dev/null
+++ b/src/quickcontrols2/basic/RadioButton.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ padding: 6
+ spacing: 6
+
+ // keep in sync with RadioDelegate.qml (shared RadioIndicator.qml was removed for performance reasons)
+ indicator: Rectangle {
+ implicitWidth: 28
+ implicitHeight: 28
+
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ radius: width / 2
+ color: control.down ? control.palette.light : control.palette.base
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.palette.mid
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 20
+ height: 20
+ radius: width / 2
+ color: control.palette.text
+ visible: control.checked
+ }
+ }
+
+ contentItem: CheckLabel {
+ 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.windowText
+ }
+}
diff --git a/src/quickcontrols2/basic/RadioDelegate.qml b/src/quickcontrols2/basic/RadioDelegate.qml
new file mode 100644
index 0000000000..69be290c72
--- /dev/null
+++ b/src/quickcontrols2/basic/RadioDelegate.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RadioDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 12
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ // keep in sync with RadioButton.qml (shared RadioIndicator.qml was removed for performance reasons)
+ indicator: Rectangle {
+ implicitWidth: 28
+ implicitHeight: 28
+
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ radius: width / 2
+ color: control.down ? control.palette.light : control.palette.base
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.palette.mid
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 20
+ height: 20
+ radius: width / 2
+ color: control.palette.text
+ visible: control.checked
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? control.palette.midlight : control.palette.light
+ }
+}
diff --git a/src/quickcontrols2/basic/RangeSlider.qml b/src/quickcontrols2/basic/RangeSlider.qml
new file mode 100644
index 0000000000..e47cbd524b
--- /dev/null
+++ b/src/quickcontrols2/basic/RangeSlider.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ padding: 6
+
+ first.handle: Rectangle {
+ x: control.leftPadding + (control.horizontal ? control.first.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.first.visualPosition * (control.availableHeight - height))
+ implicitWidth: 28
+ implicitHeight: 28
+ radius: width / 2
+ border.width: activeFocus ? 2 : 1
+ border.color: activeFocus ? control.palette.highlight : control.enabled ? control.palette.mid : control.palette.midlight
+ color: control.first.pressed ? control.palette.light : control.palette.window
+ }
+
+ second.handle: Rectangle {
+ x: control.leftPadding + (control.horizontal ? control.second.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.second.visualPosition * (control.availableHeight - height))
+ implicitWidth: 28
+ implicitHeight: 28
+ radius: width / 2
+ border.width: activeFocus ? 2 : 1
+ border.color: activeFocus ? control.palette.highlight : control.enabled ? control.palette.mid : control.palette.midlight
+ color: control.second.pressed ? control.palette.light : control.palette.window
+ }
+
+ background: Rectangle {
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ implicitWidth: control.horizontal ? 200 : 6
+ implicitHeight: control.horizontal ? 6 : 200
+ width: control.horizontal ? control.availableWidth : implicitWidth
+ height: control.horizontal ? implicitHeight : control.availableHeight
+ radius: 3
+ color: control.palette.midlight
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ Rectangle {
+ x: control.horizontal ? control.first.position * parent.width + 3 : 0
+ y: control.horizontal ? 0 : control.second.visualPosition * parent.height + 3
+ width: control.horizontal ? control.second.position * parent.width - control.first.position * parent.width - 6 : 6
+ height: control.horizontal ? 6 : control.second.position * parent.height - control.first.position * parent.height - 6
+
+ color: control.palette.dark
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/RoundButton.qml b/src/quickcontrols2/basic/RoundButton.qml
new file mode 100644
index 0000000000..6ab810fd9e
--- /dev/null
+++ b/src/quickcontrols2/basic/RoundButton.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.RoundButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.checked || control.highlighted ? control.palette.brightText :
+ control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.checked || control.highlighted ? control.palette.brightText :
+ control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ radius: control.radius
+ opacity: enabled ? 1 : 0.3
+ visible: !control.flat || control.down || control.checked || control.highlighted
+ color: Color.blend(control.checked || control.highlighted ? control.palette.dark : control.palette.button,
+ control.palette.mid, control.down ? 0.5 : 0.0)
+ border.color: control.palette.highlight
+ border.width: control.visualFocus ? 2 : 0
+ }
+}
diff --git a/src/quickcontrols2/basic/ScrollBar.qml b/src/quickcontrols2/basic/ScrollBar.qml
new file mode 100644
index 0000000000..f3c06ef1fc
--- /dev/null
+++ b/src/quickcontrols2/basic/ScrollBar.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+ visible: control.policy !== T.ScrollBar.AlwaysOff
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ contentItem: Rectangle {
+ implicitWidth: control.interactive ? 6 : 2
+ implicitHeight: control.interactive ? 6 : 2
+
+ radius: width / 2
+ color: control.pressed ? control.palette.dark : control.palette.mid
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
+ PropertyChanges { target: 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/quickcontrols2/basic/ScrollIndicator.qml b/src/quickcontrols2/basic/ScrollIndicator.qml
new file mode 100644
index 0000000000..dcb23d6536
--- /dev/null
+++ b/src/quickcontrols2/basic/ScrollIndicator.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+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 { target: 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/quickcontrols2/basic/ScrollView.qml b/src/quickcontrols2/basic/ScrollView.qml
new file mode 100644
index 0000000000..43c4e428c6
--- /dev/null
+++ b/src/quickcontrols2/basic/ScrollView.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/basic/SelectionRectangle.qml b/src/quickcontrols2/basic/SelectionRectangle.qml
new file mode 100644
index 0000000000..060fb909d8
--- /dev/null
+++ b/src/quickcontrols2/basic/SelectionRectangle.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Shapes
+import QtQuick.Templates as T
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: Handle {}
+ bottomRightHandle: Handle {}
+
+ component Handle : Rectangle {
+ id: handle
+ width: 28
+ height: width
+ radius: width / 2
+ color: SelectionRectangle.dragging ? control.palette.light : control.palette.window
+ border.width: 1
+ border.color: control.enabled ? control.palette.mid : control.palette.midlight
+ visible: SelectionRectangle.control.active
+
+ property Item control: SelectionRectangle.control
+ }
+
+}
diff --git a/src/quickcontrols2/basic/Slider.qml b/src/quickcontrols2/basic/Slider.qml
new file mode 100644
index 0000000000..425f4975fd
--- /dev/null
+++ b/src/quickcontrols2/basic/Slider.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+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)
+
+ padding: 6
+
+ handle: Rectangle {
+ x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+ implicitWidth: 28
+ implicitHeight: 28
+ radius: width / 2
+ color: control.pressed ? control.palette.light : control.palette.window
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.enabled ? control.palette.mid : control.palette.midlight
+ }
+
+ background: Rectangle {
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ implicitWidth: control.horizontal ? 200 : 6
+ implicitHeight: control.horizontal ? 6 : 200
+ width: control.horizontal ? control.availableWidth : implicitWidth
+ height: control.horizontal ? implicitHeight : control.availableHeight
+ radius: 3
+ color: control.palette.midlight
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ Rectangle {
+ y: control.horizontal ? 0 : control.visualPosition * parent.height
+ width: control.horizontal ? control.position * parent.width : 6
+ height: control.horizontal ? 6 : control.position * parent.height
+
+ radius: 3
+ color: control.palette.dark
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/SpinBox.qml b/src/quickcontrols2/basic/SpinBox.qml
new file mode 100644
index 0000000000..f992e7c9ba
--- /dev/null
+++ b/src/quickcontrols2/basic/SpinBox.qml
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth + 2 * padding +
+ up.implicitIndicatorWidth +
+ down.implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight,
+ up.implicitIndicatorHeight,
+ down.implicitIndicatorHeight)
+
+ padding: 6
+ leftPadding: padding + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: padding + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ z: 2
+ text: control.displayText
+
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+
+ Rectangle {
+ x: -6 - (control.down.indicator ? 1 : 0)
+ y: -6
+ width: control.width - (control.up.indicator ? control.up.indicator.width - 1 : 0) - (control.down.indicator ? control.down.indicator.width - 1 : 0)
+ height: control.height
+ visible: control.activeFocus
+ color: "transparent"
+ border.color: control.palette.highlight
+ border.width: 2
+ }
+ }
+
+ up.indicator: Rectangle {
+ x: control.mirrored ? 0 : control.width - width
+ height: control.height
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.up.pressed ? control.palette.mid : control.palette.button
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 3
+ height: 2
+ color: enabled ? control.palette.buttonText : control.palette.mid
+ }
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 2
+ height: parent.width / 3
+ color: enabled ? control.palette.buttonText : control.palette.mid
+ }
+ }
+
+ down.indicator: Rectangle {
+ x: control.mirrored ? parent.width - width : 0
+ height: control.height
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.down.pressed ? control.palette.mid : control.palette.button
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 3
+ height: 2
+ color: enabled ? control.palette.buttonText : control.palette.mid
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 140
+ color: enabled ? control.palette.base : control.palette.button
+ border.color: control.palette.button
+ }
+}
diff --git a/src/quickcontrols2/basic/SplitView.qml b/src/quickcontrols2/basic/SplitView.qml
new file mode 100644
index 0000000000..66d24743eb
--- /dev/null
+++ b/src/quickcontrols2/basic/SplitView.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.SplitView {
+ id: control
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ handle: Rectangle {
+ implicitWidth: control.orientation === Qt.Horizontal ? 6 : control.width
+ implicitHeight: control.orientation === Qt.Horizontal ? control.height : 6
+ color: T.SplitHandle.pressed ? control.palette.mid
+ : (T.SplitHandle.hovered ? control.palette.midlight : control.palette.button)
+ }
+}
diff --git a/src/quickcontrols2/basic/StackView.qml b/src/quickcontrols2/basic/StackView.qml
new file mode 100644
index 0000000000..cbf13f3637
--- /dev/null
+++ b/src/quickcontrols2/basic/StackView.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.StackView {
+ id: control
+
+ popEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * -control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ popExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ pushEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ pushExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * -control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ replaceEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ replaceExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * -control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+}
diff --git a/src/quickcontrols2/basic/SwipeDelegate.qml b/src/quickcontrols2/basic/SwipeDelegate.qml
new file mode 100644
index 0000000000..f8209a1ea0
--- /dev/null
+++ b/src/quickcontrols2/basic/SwipeDelegate.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.SwipeDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 12
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ swipe.transition: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: Color.blend(control.down ? control.palette.midlight : control.palette.light,
+ control.palette.highlight, control.visualFocus ? 0.15 : 0.0)
+ }
+}
diff --git a/src/quickcontrols2/basic/SwipeView.qml b/src/quickcontrols2/basic/SwipeView.qml
new file mode 100644
index 0000000000..6ce4ee6ca2
--- /dev/null
+++ b/src/quickcontrols2/basic/SwipeView.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.SwipeView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ contentItem: ListView {
+ model: control.contentModel
+ interactive: control.interactive
+ currentIndex: control.currentIndex
+ focus: control.focus
+
+ spacing: control.spacing
+ orientation: control.orientation
+ snapMode: ListView.SnapOneItem
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+ highlightMoveDuration: 250
+ maximumFlickVelocity: 4 * (control.orientation === Qt.Horizontal ? width : height)
+ }
+}
diff --git a/src/quickcontrols2/basic/Switch.qml b/src/quickcontrols2/basic/Switch.qml
new file mode 100644
index 0000000000..0d919f9e97
--- /dev/null
+++ b/src/quickcontrols2/basic/Switch.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ indicator: PaddedRectangle {
+ implicitWidth: 56
+ implicitHeight: 28
+
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ radius: 8
+ leftPadding: 0
+ rightPadding: 0
+ padding: (height - 16) / 2
+ color: control.checked ? control.palette.dark : control.palette.midlight
+
+ Rectangle {
+ x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 28
+ height: 28
+ radius: 16
+ color: control.down ? control.palette.light : control.palette.window
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.enabled ? control.palette.mid : control.palette.midlight
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+ }
+
+ contentItem: CheckLabel {
+ 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.windowText
+ }
+}
diff --git a/src/quickcontrols2/basic/SwitchDelegate.qml b/src/quickcontrols2/basic/SwitchDelegate.qml
new file mode 100644
index 0000000000..8203e107c1
--- /dev/null
+++ b/src/quickcontrols2/basic/SwitchDelegate.qml
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+
+T.SwitchDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 12
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ indicator: PaddedRectangle {
+ implicitWidth: 56
+ implicitHeight: 28
+
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ radius: 8
+ leftPadding: 0
+ rightPadding: 0
+ padding: (height - 16) / 2
+ color: control.checked ? control.palette.dark : control.palette.midlight
+
+ Rectangle {
+ x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 28
+ height: 28
+ radius: 16
+ color: control.down ? control.palette.light : control.palette.window
+ border.width: control.visualFocus ? 2 : 1
+ border.color: control.visualFocus ? control.palette.highlight : control.enabled ? control.palette.mid : control.palette.midlight
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+ }
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? control.palette.midlight : control.palette.light
+ }
+}
diff --git a/src/quickcontrols2/basic/TabBar.qml b/src/quickcontrols2/basic/TabBar.qml
new file mode 100644
index 0000000000..f1b11ac297
--- /dev/null
+++ b/src/quickcontrols2/basic/TabBar.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 1
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 0
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 40
+ preferredHighlightEnd: width - 40
+ }
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/basic/TabButton.qml b/src/quickcontrols2/basic/TabButton.qml
new file mode 100644
index 0000000000..5e38f69c5f
--- /dev/null
+++ b/src/quickcontrols2/basic/TabButton.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: checked ? control.palette.windowText : control.palette.brightText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.checked ? control.palette.windowText : control.palette.brightText
+ }
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: Color.blend(control.checked ? control.palette.window : control.palette.dark,
+ control.palette.mid, control.down ? 0.5 : 0.0)
+ }
+}
diff --git a/src/quickcontrols2/basic/TextArea.qml b/src/quickcontrols2/basic/TextArea.qml
new file mode 100644
index 0000000000..99d73362d4
--- /dev/null
+++ b/src/quickcontrols2/basic/TextArea.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ padding: 6
+ leftPadding: padding + 4
+
+ color: control.palette.text
+ placeholderTextColor: control.palette.placeholderText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+
+ 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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+}
diff --git a/src/quickcontrols2/basic/TextField.qml b/src/quickcontrols2/basic/TextField.qml
new file mode 100644
index 0000000000..2833916eda
--- /dev/null
+++ b/src/quickcontrols2/basic/TextField.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+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)
+
+ padding: 6
+ leftPadding: padding + 4
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: TextInput.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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ border.width: control.activeFocus ? 2 : 1
+ color: control.palette.base
+ border.color: control.activeFocus ? control.palette.highlight : control.palette.mid
+ }
+}
diff --git a/src/quickcontrols2/basic/ToolBar.qml b/src/quickcontrols2/basic/ToolBar.qml
new file mode 100644
index 0000000000..1d21c51d09
--- /dev/null
+++ b/src/quickcontrols2/basic/ToolBar.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: control.palette.button
+ }
+}
diff --git a/src/quickcontrols2/basic/ToolButton.qml b/src/quickcontrols2/basic/ToolButton.qml
new file mode 100644
index 0000000000..8a4f8097be
--- /dev/null
+++ b/src/quickcontrols2/basic/ToolButton.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: visualFocus ? control.palette.highlight : control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.visualFocus ? control.palette.highlight : control.palette.buttonText
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+
+ opacity: control.down ? 1.0 : 0.5
+ color: control.down || control.checked || control.highlighted ? control.palette.mid : control.palette.button
+ }
+}
diff --git a/src/quickcontrols2/basic/ToolSeparator.qml b/src/quickcontrols2/basic/ToolSeparator.qml
new file mode 100644
index 0000000000..e35aca0af1
--- /dev/null
+++ b/src/quickcontrols2/basic/ToolSeparator.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ToolSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: vertical ? 6 : 2
+ verticalPadding: vertical ? 2 : 6
+
+ contentItem: Rectangle {
+ implicitWidth: control.vertical ? 1 : 30
+ implicitHeight: control.vertical ? 30 : 1
+ color: control.palette.mid
+ }
+}
diff --git a/src/quickcontrols2/basic/ToolTip.qml b/src/quickcontrols2/basic/ToolTip.qml
new file mode 100644
index 0000000000..9d10f7fa4b
--- /dev/null
+++ b/src/quickcontrols2/basic/ToolTip.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ToolTip {
+ id: control
+
+ x: parent ? (parent.width - implicitWidth) / 2 : 0
+ y: -implicitHeight - 3
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 6
+ padding: 6
+
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ wrapMode: Text.Wrap
+ color: control.palette.toolTipText
+ }
+
+ background: Rectangle {
+ border.color: control.palette.dark
+ color: control.palette.toolTipBase
+ }
+}
diff --git a/src/quickcontrols2/basic/Tumbler.qml b/src/quickcontrols2/basic/Tumbler.qml
new file mode 100644
index 0000000000..e687783785
--- /dev/null
+++ b/src/quickcontrols2/basic/Tumbler.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.Tumbler {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ delegate: Text {
+ text: modelData
+ color: control.visualFocus ? control.palette.highlight : control.palette.text
+ font: control.font
+ opacity: 1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ // We use required property here to satisfy qmllint, but that means
+ // we also need to declare the index for the attached properties
+ // (see QQuickTumblerAttachedPrivate::init).
+ required property var modelData
+ required property int index
+ }
+
+ contentItem: TumblerView {
+ implicitWidth: 60
+ implicitHeight: 200
+ model: control.model
+ delegate: control.delegate
+ path: Path {
+ startX: control.contentItem.width / 2
+ startY: -control.contentItem.delegateHeight / 2
+ PathLine {
+ x: control.contentItem.width / 2
+ y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: control.availableHeight / control.visibleItemCount
+ }
+}
diff --git a/src/quickcontrols2/basic/VerticalHeaderView.qml b/src/quickcontrols2/basic/VerticalHeaderView.qml
new file mode 100644
index 0000000000..7c057e01e2
--- /dev/null
+++ b/src/quickcontrols2/basic/VerticalHeaderView.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.VerticalHeaderView {
+ id: control
+
+ implicitWidth: contentWidth
+ implicitHeight: syncView ? syncView.height : 0
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: Math.max(control.width, text.implicitWidth + (cellPadding * 2))
+ implicitHeight: text.implicitHeight + (cellPadding * 2)
+ color: "#f6f6f6"
+ border.color: "#e4e4e4"
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/basic/basic.pri b/src/quickcontrols2/basic/basic.pri
new file mode 100644
index 0000000000..dcea52c73f
--- /dev/null
+++ b/src/quickcontrols2/basic/basic.pri
@@ -0,0 +1,67 @@
+HEADERS += \
+ $$PWD/qquickbasicstyle_p.h \
+ $$PWD/qquickbasictheme_p.h
+
+SOURCES += \
+ $$PWD/qquickbasicstyle.cpp \
+ $$PWD/qquickbasictheme.cpp
+
+QML_FILES += \
+ $$PWD/AbstractButton.qml \
+ $$PWD/Action.qml \
+ $$PWD/ActionGroup.qml \
+ $$PWD/ApplicationWindow.qml \
+ $$PWD/BusyIndicator.qml \
+ $$PWD/Button.qml \
+ $$PWD/ButtonGroup.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/CheckDelegate.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/Container.qml \
+ $$PWD/Control.qml \
+ $$PWD/DelayButton.qml \
+ $$PWD/Dial.qml \
+ $$PWD/Dialog.qml \
+ $$PWD/DialogButtonBox.qml \
+ $$PWD/Drawer.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/HorizontalHeaderView.qml \
+ $$PWD/ItemDelegate.qml \
+ $$PWD/Label.qml \
+ $$PWD/Menu.qml \
+ $$PWD/MenuBar.qml \
+ $$PWD/MenuBarItem.qml \
+ $$PWD/MenuItem.qml \
+ $$PWD/MenuSeparator.qml \
+ $$PWD/Page.qml \
+ $$PWD/PageIndicator.qml \
+ $$PWD/Pane.qml \
+ $$PWD/Popup.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/RadioDelegate.qml \
+ $$PWD/RangeSlider.qml \
+ $$PWD/RoundButton.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollIndicator.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/SplitView.qml \
+ $$PWD/StackView.qml \
+ $$PWD/SwipeDelegate.qml \
+ $$PWD/Switch.qml \
+ $$PWD/SwitchDelegate.qml \
+ $$PWD/SwipeView.qml \
+ $$PWD/TabBar.qml \
+ $$PWD/TabButton.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TextField.qml \
+ $$PWD/ToolBar.qml \
+ $$PWD/ToolButton.qml \
+ $$PWD/ToolSeparator.qml \
+ $$PWD/ToolTip.qml \
+ $$PWD/Tumbler.qml \
+ $$PWD/VerticalHeaderView.qml
diff --git a/src/quickcontrols2/basic/images/arrow-indicator.png b/src/quickcontrols2/basic/images/arrow-indicator.png
new file mode 100644
index 0000000000..d833d52c40
--- /dev/null
+++ b/src/quickcontrols2/basic/images/arrow-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/arrow-indicator@2x.png b/src/quickcontrols2/basic/images/arrow-indicator@2x.png
new file mode 100644
index 0000000000..55c7940a51
--- /dev/null
+++ b/src/quickcontrols2/basic/images/arrow-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/arrow-indicator@3x.png b/src/quickcontrols2/basic/images/arrow-indicator@3x.png
new file mode 100644
index 0000000000..c7067c5cd0
--- /dev/null
+++ b/src/quickcontrols2/basic/images/arrow-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/arrow-indicator@4x.png b/src/quickcontrols2/basic/images/arrow-indicator@4x.png
new file mode 100644
index 0000000000..4c5cf3515a
--- /dev/null
+++ b/src/quickcontrols2/basic/images/arrow-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/check.png b/src/quickcontrols2/basic/images/check.png
new file mode 100644
index 0000000000..479a84428d
--- /dev/null
+++ b/src/quickcontrols2/basic/images/check.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/check@2x.png b/src/quickcontrols2/basic/images/check@2x.png
new file mode 100644
index 0000000000..79663c0b03
--- /dev/null
+++ b/src/quickcontrols2/basic/images/check@2x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/check@3x.png b/src/quickcontrols2/basic/images/check@3x.png
new file mode 100644
index 0000000000..fd0135abe2
--- /dev/null
+++ b/src/quickcontrols2/basic/images/check@3x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/check@4x.png b/src/quickcontrols2/basic/images/check@4x.png
new file mode 100644
index 0000000000..e7e0b64044
--- /dev/null
+++ b/src/quickcontrols2/basic/images/check@4x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/dial-indicator.png b/src/quickcontrols2/basic/images/dial-indicator.png
new file mode 100644
index 0000000000..92357c51d4
--- /dev/null
+++ b/src/quickcontrols2/basic/images/dial-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/dial-indicator@2x.png b/src/quickcontrols2/basic/images/dial-indicator@2x.png
new file mode 100644
index 0000000000..f436443b0a
--- /dev/null
+++ b/src/quickcontrols2/basic/images/dial-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/dial-indicator@3x.png b/src/quickcontrols2/basic/images/dial-indicator@3x.png
new file mode 100644
index 0000000000..d883045bcb
--- /dev/null
+++ b/src/quickcontrols2/basic/images/dial-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/dial-indicator@4x.png b/src/quickcontrols2/basic/images/dial-indicator@4x.png
new file mode 100644
index 0000000000..794777128b
--- /dev/null
+++ b/src/quickcontrols2/basic/images/dial-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/double-arrow.png b/src/quickcontrols2/basic/images/double-arrow.png
new file mode 100644
index 0000000000..3ecd7f89f3
--- /dev/null
+++ b/src/quickcontrols2/basic/images/double-arrow.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/double-arrow@2x.png b/src/quickcontrols2/basic/images/double-arrow@2x.png
new file mode 100644
index 0000000000..eeb03e2847
--- /dev/null
+++ b/src/quickcontrols2/basic/images/double-arrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/double-arrow@3x.png b/src/quickcontrols2/basic/images/double-arrow@3x.png
new file mode 100644
index 0000000000..f0662d2026
--- /dev/null
+++ b/src/quickcontrols2/basic/images/double-arrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/double-arrow@4x.png b/src/quickcontrols2/basic/images/double-arrow@4x.png
new file mode 100644
index 0000000000..10891e9133
--- /dev/null
+++ b/src/quickcontrols2/basic/images/double-arrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/drop-indicator.png b/src/quickcontrols2/basic/images/drop-indicator.png
new file mode 100644
index 0000000000..80c1d958e3
--- /dev/null
+++ b/src/quickcontrols2/basic/images/drop-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/drop-indicator@2x.png b/src/quickcontrols2/basic/images/drop-indicator@2x.png
new file mode 100644
index 0000000000..6e0f228c54
--- /dev/null
+++ b/src/quickcontrols2/basic/images/drop-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/drop-indicator@3x.png b/src/quickcontrols2/basic/images/drop-indicator@3x.png
new file mode 100644
index 0000000000..199752fbf8
--- /dev/null
+++ b/src/quickcontrols2/basic/images/drop-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/images/drop-indicator@4x.png b/src/quickcontrols2/basic/images/drop-indicator@4x.png
new file mode 100644
index 0000000000..58311fbe2a
--- /dev/null
+++ b/src/quickcontrols2/basic/images/drop-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/basic/impl/CMakeLists.txt b/src/quickcontrols2/basic/impl/CMakeLists.txt
new file mode 100644
index 0000000000..2b937ae286
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/CMakeLists.txt
@@ -0,0 +1,25 @@
+#####################################################################
+## qtquickcontrols2basicstyleimplplugin Plugin:
+#####################################################################
+
+qt_internal_add_qml_module(qtquickcontrols2basicstyleimplplugin
+ URI "QtQuick.Controls.Basic.impl"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickControls2BasicStyleImplPlugin
+ PLUGIN_TARGET qtquickcontrols2basicstyleimplplugin
+ NO_PLUGIN_OPTIONAL
+ SOURCES
+ qquickbasicbusyindicator.cpp qquickbasicbusyindicator_p.h
+ qquickbasicdial.cpp qquickbasicdial_p.h
+ qquickbasicprogressbar.cpp qquickbasicprogressbar_p.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
diff --git a/src/quickcontrols2/basic/impl/qquickbasicbusyindicator.cpp b/src/quickcontrols2/basic/impl/qquickbasicbusyindicator.cpp
new file mode 100644
index 0000000000..b497f57f70
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicbusyindicator.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasicbusyindicator_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int CircleCount = 10;
+static const int TotalDuration = 100 * CircleCount * 2;
+static const QRgb TransparentColor = 0x00000000;
+
+static QPointF moveCircle(const QPointF &pos, qreal rotation, qreal distance)
+{
+ return pos - QTransform().rotate(rotation).map(QPointF(0, distance));
+}
+
+class QQuickBasicBusyIndicatorNode : public QQuickAnimatedNode
+{
+public:
+ QQuickBasicBusyIndicatorNode(QQuickBasicBusyIndicator *item);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ QColor m_pen;
+ QColor m_fill;
+};
+
+QQuickBasicBusyIndicatorNode::QQuickBasicBusyIndicatorNode(QQuickBasicBusyIndicator *item)
+ : QQuickAnimatedNode(item)
+{
+ setLoopCount(Infinite);
+ setDuration(TotalDuration);
+ setCurrentTime(item->elapsed());
+
+ for (int i = 0; i < CircleCount; ++i) {
+ QSGTransformNode *transformNode = new QSGTransformNode;
+ appendChildNode(transformNode);
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ transformNode->appendChildNode(rectNode);
+ }
+}
+
+void QQuickBasicBusyIndicatorNode::updateCurrentTime(int time)
+{
+ const qreal percentageComplete = time / qreal(TotalDuration);
+ const qreal firstPhaseProgress = percentageComplete <= 0.5 ? percentageComplete * 2 : 0;
+ const qreal secondPhaseProgress = percentageComplete > 0.5 ? (percentageComplete - 0.5) * 2 : 0;
+
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild());
+ Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
+ for (int i = 0; i < CircleCount; ++i) {
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ const bool fill = (firstPhaseProgress > qreal(i) / CircleCount) || (secondPhaseProgress > 0 && secondPhaseProgress < qreal(i) / CircleCount);
+ rectNode->setColor(fill ? m_fill : QColor::fromRgba(TransparentColor));
+ rectNode->setPenColor(m_pen);
+ rectNode->setPenWidth(1);
+ rectNode->update();
+
+ transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling());
+ }
+}
+
+void QQuickBasicBusyIndicatorNode::sync(QQuickItem *item)
+{
+ const qreal w = item->width();
+ const qreal h = item->height();
+ const qreal sz = qMin(w, h);
+ const qreal dx = (w - sz) / 2;
+ const qreal dy = (h - sz) / 2;
+ const int circleRadius = sz / 12;
+
+ m_pen = static_cast<QQuickBasicBusyIndicator *>(item)->pen();
+ m_fill = static_cast<QQuickBasicBusyIndicator *>(item)->fill();
+
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(firstChild());
+ for (int i = 0; i < CircleCount; ++i) {
+ Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ QPointF pos = QPointF(sz / 2 - circleRadius, sz / 2 - circleRadius);
+ pos = moveCircle(pos, 360.0 / CircleCount * i, sz / 2 - circleRadius);
+
+ QMatrix4x4 m;
+ m.translate(dx + pos.x(), dy + pos.y());
+ transformNode->setMatrix(m);
+
+ rectNode->setRect(QRectF(QPointF(), QSizeF(circleRadius * 2, circleRadius * 2)));
+ rectNode->setRadius(circleRadius);
+
+ transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling());
+ }
+}
+
+QQuickBasicBusyIndicator::QQuickBasicBusyIndicator(QQuickItem *parent) :
+ QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QColor QQuickBasicBusyIndicator::pen() const
+{
+ return m_pen;
+}
+
+void QQuickBasicBusyIndicator::setPen(const QColor &pen)
+{
+ if (pen == m_pen)
+ return;
+
+ m_pen = pen;
+ update();
+}
+
+QColor QQuickBasicBusyIndicator::fill() const
+{
+ return m_fill;
+}
+
+void QQuickBasicBusyIndicator::setFill(const QColor &fill)
+{
+ if (fill == m_fill)
+ return;
+
+ m_fill = fill;
+ update();
+}
+
+bool QQuickBasicBusyIndicator::isRunning() const
+{
+ return isVisible();
+}
+
+void QQuickBasicBusyIndicator::setRunning(bool running)
+{
+ if (running)
+ setVisible(true);
+}
+
+int QQuickBasicBusyIndicator::elapsed() const
+{
+ return m_elapsed;
+}
+
+void QQuickBasicBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ switch (change) {
+ case ItemOpacityHasChanged:
+ if (qFuzzyIsNull(data.realValue))
+ setVisible(false);
+ break;
+ case ItemVisibleHasChanged:
+ update();
+ break;
+ default:
+ break;
+ }
+}
+
+QSGNode *QQuickBasicBusyIndicator::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QQuickBasicBusyIndicatorNode *node = static_cast<QQuickBasicBusyIndicatorNode *>(oldNode);
+ if (isRunning() && width() > 0 && height() > 0) {
+ if (!node) {
+ node = new QQuickBasicBusyIndicatorNode(this);
+ node->start();
+ }
+ node->sync(this);
+ } else {
+ m_elapsed = node ? node->currentTime() : 0;
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbasicbusyindicator_p.cpp"
diff --git a/src/quickcontrols2/basic/impl/qquickbasicbusyindicator_p.h b/src/quickcontrols2/basic/impl/qquickbasicbusyindicator_p.h
new file mode 100644
index 0000000000..7eea665675
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicbusyindicator_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDEFAULTBUSYINDICATOR_P_H
+#define QQUICKDEFAULTBUSYINDICATOR_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/qquickitem.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBasicBusyIndicator : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor pen READ pen WRITE setPen FINAL)
+ Q_PROPERTY(QColor fill READ fill WRITE setFill FINAL)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning)
+ QML_NAMED_ELEMENT(BusyIndicatorImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickBasicBusyIndicator(QQuickItem *parent = nullptr);
+
+ QColor pen() const;
+ void setPen(const QColor &pen);
+
+ QColor fill() const;
+ void setFill(const QColor &fill);
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+ int elapsed() const;
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ int m_elapsed = 0;
+ QColor m_pen;
+ QColor m_fill;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickBasicBusyIndicator)
+
+#endif // QQUICKDEFAULTBUSYINDICATOR_P_H
diff --git a/src/quickcontrols2/basic/impl/qquickbasicdial.cpp b/src/quickcontrols2/basic/impl/qquickbasicdial.cpp
new file mode 100644
index 0000000000..df6626e2e8
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicdial.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasicdial_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtGui/qpainter.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickBasicDial::QQuickBasicDial(QQuickItem *parent) :
+ QQuickPaintedItem(parent)
+{
+}
+
+qreal QQuickBasicDial::progress() const
+{
+ return m_progress;
+}
+
+void QQuickBasicDial::setProgress(qreal progress)
+{
+ if (progress == m_progress)
+ return;
+
+ m_progress = progress;
+ update();
+}
+
+QColor QQuickBasicDial::color() const
+{
+ return m_color;
+}
+
+void QQuickBasicDial::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+void QQuickBasicDial::paint(QPainter *painter)
+{
+ if (width() <= 0 || height() <= 0)
+ return;
+
+ QPen pen(m_color);
+ pen.setWidth(8);
+ pen.setCapStyle(Qt::FlatCap);
+ painter->setPen(pen);
+
+ const QRectF bounds = boundingRect();
+ const qreal smallest = qMin(bounds.width(), bounds.height());
+ QRectF rect = QRectF(pen.widthF() / 2.0 + 1, pen.widthF() / 2.0 + 1, smallest - pen.widthF() - 2, smallest - pen.widthF() - 2);
+ rect.moveCenter(bounds.center());
+
+ // Make sure the arc is aligned to whole pixels.
+ if (rect.x() - int(rect.x()) > 0)
+ rect.setX(qCeil(rect.x()));
+ if (rect.y() - int(rect.y()) > 0)
+ rect.setY(qCeil(rect.y()));
+ if (rect.width() - int(rect.width()) > 0)
+ rect.setWidth(qFloor(rect.width()));
+ if (rect.height() - int(rect.height()) > 0)
+ rect.setHeight(qFloor(rect.height()));
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ const qreal startAngle = (140 + 90);
+ const qreal spanAngle = (m_progress * 280) * -1;
+ QPainterPath path;
+ path.arcMoveTo(rect, startAngle);
+ path.arcTo(rect, startAngle, spanAngle);
+ painter->drawPath(path);
+
+ rect.adjust(-pen.widthF() / 2.0, -pen.widthF() / 2.0, pen.widthF() / 2.0, pen.widthF() / 2.0);
+ pen.setWidth(1);
+ painter->setPen(pen);
+
+ path = QPainterPath();
+ path.arcMoveTo(rect, 0);
+ path.arcTo(rect, 0, 360);
+ painter->drawPath(path);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbasicdial_p.cpp"
diff --git a/src/quickcontrols2/basic/impl/qquickbasicdial_p.h b/src/quickcontrols2/basic/impl/qquickbasicdial_p.h
new file mode 100644
index 0000000000..bd9bbb7201
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicdial_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDEFAULTDIAL_P_H
+#define QQUICKDEFAULTDIAL_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>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBasicDial : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ QML_NAMED_ELEMENT(DialImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickBasicDial(QQuickItem *parent = nullptr);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ void paint(QPainter *painter) override;
+
+private:
+ qreal m_progress = 0;
+ QColor m_color = Qt::black;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDEFAULTDIAL_P_H
diff --git a/src/quickcontrols2/basic/impl/qquickbasicprogressbar.cpp b/src/quickcontrols2/basic/impl/qquickbasicprogressbar.cpp
new file mode 100644
index 0000000000..c492b1a920
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicprogressbar.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasicprogressbar_p.h"
+
+#include <QtCore/qeasingcurve.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int Blocks = 4;
+static const int BlockWidth = 16;
+static const int BlockRestingSpacing = 4;
+static const int BlockMovingSpacing = 48;
+static const int BlockSpan = Blocks * (BlockWidth + BlockRestingSpacing) - BlockRestingSpacing;
+static const int TotalDuration = 4000;
+static const int SecondPhaseStart = TotalDuration * 0.4;
+static const int ThirdPhaseStart = TotalDuration * 0.6;
+
+static inline qreal blockStartX(int blockIndex)
+{
+ return ((blockIndex + 1) * -BlockWidth) - (blockIndex * BlockMovingSpacing);
+}
+
+static inline qreal blockRestX(int blockIndex, qreal availableWidth)
+{
+ const qreal spanRightEdgePos = availableWidth / 2 + BlockSpan / 2.0;
+ return spanRightEdgePos - (blockIndex + 1) * BlockWidth - (blockIndex * BlockRestingSpacing);
+}
+
+static inline qreal blockEndX(int blockIndex, qreal availableWidth)
+{
+ return availableWidth - blockStartX(Blocks - 1 - blockIndex) - BlockWidth;
+}
+
+class QQuickBasicProgressBarNode : public QQuickAnimatedNode
+{
+public:
+ QQuickBasicProgressBarNode(QQuickBasicProgressBar *item);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ bool m_indeterminate = false;
+ qreal m_pixelsPerSecond = 0;
+};
+
+QQuickBasicProgressBarNode::QQuickBasicProgressBarNode(QQuickBasicProgressBar *item)
+ : QQuickAnimatedNode(item),
+ m_pixelsPerSecond(item->width())
+{
+ setLoopCount(Infinite);
+ setDuration(TotalDuration);
+}
+
+void QQuickBasicProgressBarNode::updateCurrentTime(int time)
+{
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild());
+ for (int i = 0; i < Blocks; ++i) {
+ Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
+
+ QMatrix4x4 m;
+ const qreal restX = blockRestX(i, m_pixelsPerSecond);
+ const qreal timeInSeconds = time / 1000.0;
+
+ if (time < SecondPhaseStart) {
+ // Move into the resting position for the first phase.
+ QEasingCurve easingCurve(QEasingCurve::InQuad);
+ const qreal easedCompletion = easingCurve.valueForProgress(time / qreal(SecondPhaseStart));
+ const qreal distance = m_pixelsPerSecond * (easedCompletion * (SecondPhaseStart / 1000.0));
+ const qreal position = blockStartX(i) + distance;
+ const qreal destination = restX;
+ m.translate(qMin(position, destination), 0);
+ } else if (time < ThirdPhaseStart) {
+ // Stay in the same position for the second phase.
+ m.translate(restX, 0);
+ } else {
+ // Move out of view for the third phase.
+ const int thirdPhaseSubKickoff = (BlockMovingSpacing / m_pixelsPerSecond) * 1000;
+ const int subphase = (time - ThirdPhaseStart) / thirdPhaseSubKickoff;
+ // If we're not at this subphase yet, don't try to animate movement,
+ // because it will be incorrect.
+ if (subphase < i)
+ return;
+
+ const qreal timeSinceSecondPhase = timeInSeconds - (ThirdPhaseStart / 1000.0);
+ // We only want to start keeping track of time once our subphase has started,
+ // otherwise we move too much because we account for time that has already elapsed.
+ // For example, if we were 60 milliseconds into the third subphase:
+ //
+ // 0 ..... 1 ..... 2 ...
+ // 100 100 60
+ //
+ // i == 0, timeSinceOurKickoff == 260
+ // i == 1, timeSinceOurKickoff == 160
+ // i == 2, timeSinceOurKickoff == 60
+ const qreal timeSinceOurKickoff = timeSinceSecondPhase - (thirdPhaseSubKickoff / 1000.0 * i);
+ const qreal position = restX + (m_pixelsPerSecond * (timeSinceOurKickoff));
+ const qreal destination = blockEndX(i, m_pixelsPerSecond);
+ m.translate(qMin(position, destination), 0);
+ }
+
+ transformNode->setMatrix(m);
+
+ transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling());
+ }
+}
+
+void QQuickBasicProgressBarNode::sync(QQuickItem *item)
+{
+ QQuickBasicProgressBar *bar = static_cast<QQuickBasicProgressBar *>(item);
+ if (m_indeterminate != bar->isIndeterminate()) {
+ m_indeterminate = bar->isIndeterminate();
+ if (m_indeterminate)
+ start();
+ else
+ stop();
+ }
+ m_pixelsPerSecond = item->width();
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+
+ QMatrix4x4 m;
+ m.translate(0, (item->height() - item->implicitHeight()) / 2);
+ setMatrix(m);
+
+ if (m_indeterminate) {
+ if (childCount() != Blocks) {
+ // This was previously a regular progress bar; remove the old nodes.
+ removeAllChildNodes();
+ }
+
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild());
+ for (int i = 0; i < Blocks; ++i) {
+ if (!transformNode) {
+ transformNode = new QSGTransformNode;
+ appendChildNode(transformNode);
+ }
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild());
+ if (!rectNode) {
+ rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setColor(bar->color());
+ transformNode->appendChildNode(rectNode);
+ }
+
+ QMatrix4x4 m;
+ m.translate(blockStartX(i), 0);
+ transformNode->setMatrix(m);
+
+ rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(BlockWidth, item->implicitHeight())));
+ rectNode->update();
+
+ transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling());
+ }
+ } else {
+ if (childCount() > 1) {
+ // This was previously an indeterminate progress bar; remove the old nodes.
+ removeAllChildNodes();
+ }
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(firstChild());
+ if (!rectNode) {
+ rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setColor(bar->color());
+ appendChildNode(rectNode);
+ }
+
+ rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(bar->progress() * item->width(), item->implicitHeight())));
+ rectNode->update();
+ }
+}
+
+QQuickBasicProgressBar::QQuickBasicProgressBar(QQuickItem *parent) :
+ QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+qreal QQuickBasicProgressBar::progress() const
+{
+ return m_progress;
+}
+
+void QQuickBasicProgressBar::setProgress(qreal progress)
+{
+ if (progress == m_progress)
+ return;
+
+ m_progress = progress;
+ update();
+}
+
+bool QQuickBasicProgressBar::isIndeterminate() const
+{
+ return m_indeterminate;
+}
+
+void QQuickBasicProgressBar::setIndeterminate(bool indeterminate)
+{
+ if (indeterminate == m_indeterminate)
+ return;
+
+ m_indeterminate = indeterminate;
+ setClip(m_indeterminate);
+ update();
+}
+
+QColor QQuickBasicProgressBar::color() const
+{
+ return m_color;
+}
+
+void QQuickBasicProgressBar::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+void QQuickBasicProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ if (change == ItemVisibleHasChanged)
+ update();
+}
+
+QSGNode *QQuickBasicProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QQuickBasicProgressBarNode *node = static_cast<QQuickBasicProgressBarNode *>(oldNode);
+ if (isVisible() && width() > 0 && height() > 0) {
+ if (!node)
+ node = new QQuickBasicProgressBarNode(this);
+ node->sync(this);
+ } else {
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbasicprogressbar_p.cpp"
diff --git a/src/quickcontrols2/basic/impl/qquickbasicprogressbar_p.h b/src/quickcontrols2/basic/impl/qquickbasicprogressbar_p.h
new file mode 100644
index 0000000000..1d853ecb41
--- /dev/null
+++ b/src/quickcontrols2/basic/impl/qquickbasicprogressbar_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDEFAULTPROGRESSBAR_P_H
+#define QQUICKDEFAULTPROGRESSBAR_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/qquickitem.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBasicProgressBar : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate FINAL)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ QML_NAMED_ELEMENT(ProgressBarImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickBasicProgressBar(QQuickItem *parent = nullptr);
+
+ bool isIndeterminate() const;
+ void setIndeterminate(bool indeterminate);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ qreal m_progress = 0;
+ bool m_indeterminate = false;
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickBasicProgressBar)
+
+#endif // QQUICKDEFAULTPROGRESSBAR_P_H
diff --git a/src/quickcontrols2/basic/qquickbasicstyle.cpp b/src/quickcontrols2/basic/qquickbasicstyle.cpp
new file mode 100644
index 0000000000..0cf82bb01b
--- /dev/null
+++ b/src/quickcontrols2/basic/qquickbasicstyle.cpp
@@ -0,0 +1,248 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasicstyle_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickBasicStyle::QQuickBasicStyle(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QColor QQuickBasicStyle::backgroundColor() const
+{
+ return QColor::fromRgba(0xFFFFFFFF);
+}
+
+QColor QQuickBasicStyle::overlayModalColor() const
+{
+ return QColor::fromRgba(0x7F28282A);
+}
+
+QColor QQuickBasicStyle::overlayDimColor() const
+{
+ return QColor::fromRgba(0x1F28282A);
+}
+
+QColor QQuickBasicStyle::textColor() const
+{
+ return QColor::fromRgba(0xFF353637);
+}
+
+QColor QQuickBasicStyle::textDarkColor() const
+{
+ return QColor::fromRgba(0xFF26282A);
+}
+
+QColor QQuickBasicStyle::textLightColor() const
+{
+ return QColor::fromRgba(0xFFFFFFFF);
+}
+
+QColor QQuickBasicStyle::textLinkColor() const
+{
+ return QColor::fromRgba(0xFF45A7D7);
+}
+
+QColor QQuickBasicStyle::textSelectionColor() const
+{
+ return QColor::fromRgba(0xFFFDDD5C);
+}
+
+QColor QQuickBasicStyle::textDisabledColor() const
+{
+ return QColor::fromRgba(0xFFBDBEBF);
+}
+
+QColor QQuickBasicStyle::textDisabledLightColor() const
+{
+ return QColor::fromRgba(0xFFC2C2C2);
+}
+
+QColor QQuickBasicStyle::textPlaceholderColor() const
+{
+ return QColor::fromRgba(0xFF777777);
+}
+
+QColor QQuickBasicStyle::focusColor() const
+{
+ return QColor::fromRgba(0xFF0066FF);
+}
+
+QColor QQuickBasicStyle::focusLightColor() const
+{
+ return QColor::fromRgba(0xFFF0F6FF);
+}
+
+QColor QQuickBasicStyle::focusPressedColor() const
+{
+ return QColor::fromRgba(0xFFCCE0FF);
+}
+
+QColor QQuickBasicStyle::buttonColor() const
+{
+ return QColor::fromRgba(0xFFE0E0E0);
+}
+
+QColor QQuickBasicStyle::buttonPressedColor() const
+{
+ return QColor::fromRgba(0xFFD0D0D0);
+}
+
+QColor QQuickBasicStyle::buttonCheckedColor() const
+{
+ return QColor::fromRgba(0xFF353637);
+}
+
+QColor QQuickBasicStyle::buttonCheckedPressedColor() const
+{
+ return QColor::fromRgba(0xFF585A5C);
+}
+
+QColor QQuickBasicStyle::buttonCheckedFocusColor() const
+{
+ return QColor::fromRgba(0xFF599BFF);
+}
+
+QColor QQuickBasicStyle::toolButtonColor() const
+{
+ return QColor::fromRgba(0x33333333);
+}
+
+QColor QQuickBasicStyle::tabButtonColor() const
+{
+ return QColor::fromRgba(0xFF353637);
+}
+
+QColor QQuickBasicStyle::tabButtonPressedColor() const
+{
+ return QColor::fromRgba(0xFF585A5C);
+}
+
+QColor QQuickBasicStyle::tabButtonCheckedPressedColor() const
+{
+ return QColor::fromRgba(0xFFE4E4E4);
+}
+
+QColor QQuickBasicStyle::delegateColor() const
+{
+ return QColor::fromRgba(0xFFEEEEEE);
+}
+
+QColor QQuickBasicStyle::delegatePressedColor() const
+{
+ return QColor::fromRgba(0xFFBDBEBF);
+}
+
+QColor QQuickBasicStyle::delegateFocusColor() const
+{
+ return QColor::fromRgba(0xFFE5EFFF);
+}
+
+QColor QQuickBasicStyle::indicatorPressedColor() const
+{
+ return QColor::fromRgba(0xFFF6F6F6);
+}
+
+QColor QQuickBasicStyle::indicatorDisabledColor() const
+{
+ return QColor::fromRgba(0xFFFDFDFD);
+}
+
+QColor QQuickBasicStyle::indicatorFrameColor() const
+{
+ return QColor::fromRgba(0xFF909090);
+}
+
+QColor QQuickBasicStyle::indicatorFramePressedColor() const
+{
+ return QColor::fromRgba(0xFF808080);
+}
+
+QColor QQuickBasicStyle::indicatorFrameDisabledColor() const
+{
+ return QColor::fromRgba(0xFFD6D6D6);
+}
+
+QColor QQuickBasicStyle::frameDarkColor() const
+{
+ return QColor::fromRgba(0xFF353637);
+}
+
+QColor QQuickBasicStyle::frameLightColor() const
+{
+ return QColor::fromRgba(0xFFBDBEBF);
+}
+
+QColor QQuickBasicStyle::scrollBarColor() const
+{
+ return QColor::fromRgba(0xFFBDBEBF);
+}
+
+QColor QQuickBasicStyle::scrollBarPressedColor() const
+{
+ return QColor::fromRgba(0xFF28282A);
+}
+
+QColor QQuickBasicStyle::progressBarColor() const
+{
+ return QColor::fromRgba(0xFFE4E4E4);
+}
+
+QColor QQuickBasicStyle::pageIndicatorColor() const
+{
+ return QColor::fromRgba(0xFF28282A);
+}
+
+QColor QQuickBasicStyle::separatorColor() const
+{
+ return QColor::fromRgba(0xFFCCCCCC);
+}
+
+QColor QQuickBasicStyle::disabledDarkColor() const
+{
+ return QColor::fromRgba(0xFF353637);
+}
+
+QColor QQuickBasicStyle::disabledLightColor() const
+{
+ return QColor::fromRgba(0xFFBDBEBF);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbasicstyle_p.cpp"
diff --git a/src/quickcontrols2/basic/qquickbasicstyle_p.h b/src/quickcontrols2/basic/qquickbasicstyle_p.h
new file mode 100644
index 0000000000..3f3d84b8f3
--- /dev/null
+++ b/src/quickcontrols2/basic/qquickbasicstyle_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBASICSTYLE_P_H
+#define QQUICKBASICSTYLE_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 <QtGui/qcolor.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBasicStyle : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor backgroundColor READ backgroundColor CONSTANT FINAL)
+ Q_PROPERTY(QColor overlayModalColor READ overlayModalColor CONSTANT FINAL)
+ Q_PROPERTY(QColor overlayDimColor READ overlayDimColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textColor READ textColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textDarkColor READ textDarkColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textLightColor READ textLightColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textLinkColor READ textLinkColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textSelectionColor READ textSelectionColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textDisabledColor READ textDisabledColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textDisabledLightColor READ textDisabledLightColor CONSTANT FINAL)
+ Q_PROPERTY(QColor textPlaceholderColor READ textPlaceholderColor CONSTANT FINAL)
+ Q_PROPERTY(QColor focusColor READ focusColor CONSTANT FINAL)
+ Q_PROPERTY(QColor focusLightColor READ focusLightColor CONSTANT FINAL)
+ Q_PROPERTY(QColor focusPressedColor READ focusPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor buttonColor READ buttonColor CONSTANT FINAL)
+ Q_PROPERTY(QColor buttonPressedColor READ buttonPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor buttonCheckedColor READ buttonCheckedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor buttonCheckedPressedColor READ buttonCheckedPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor buttonCheckedFocusColor READ buttonCheckedFocusColor CONSTANT FINAL)
+ Q_PROPERTY(QColor toolButtonColor READ toolButtonColor CONSTANT FINAL)
+ Q_PROPERTY(QColor tabButtonColor READ tabButtonColor CONSTANT FINAL)
+ Q_PROPERTY(QColor tabButtonPressedColor READ tabButtonPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor tabButtonCheckedPressedColor READ tabButtonCheckedPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor delegateColor READ delegateColor CONSTANT FINAL)
+ Q_PROPERTY(QColor delegatePressedColor READ delegatePressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor delegateFocusColor READ delegateFocusColor CONSTANT FINAL)
+ Q_PROPERTY(QColor indicatorPressedColor READ indicatorPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor indicatorDisabledColor READ indicatorDisabledColor CONSTANT FINAL)
+ Q_PROPERTY(QColor indicatorFrameColor READ indicatorFrameColor CONSTANT FINAL)
+ Q_PROPERTY(QColor indicatorFramePressedColor READ indicatorFramePressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor indicatorFrameDisabledColor READ indicatorFrameDisabledColor CONSTANT FINAL)
+ Q_PROPERTY(QColor frameDarkColor READ frameDarkColor CONSTANT FINAL)
+ Q_PROPERTY(QColor frameLightColor READ frameLightColor CONSTANT FINAL)
+ Q_PROPERTY(QColor scrollBarColor READ scrollBarColor CONSTANT FINAL)
+ Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor CONSTANT FINAL)
+ Q_PROPERTY(QColor progressBarColor READ progressBarColor CONSTANT FINAL)
+ Q_PROPERTY(QColor pageIndicatorColor READ pageIndicatorColor CONSTANT FINAL)
+ Q_PROPERTY(QColor separatorColor READ separatorColor CONSTANT FINAL)
+ Q_PROPERTY(QColor disabledDarkColor READ disabledDarkColor CONSTANT FINAL)
+ Q_PROPERTY(QColor disabledLightColor READ disabledLightColor CONSTANT FINAL)
+ QML_NAMED_ELEMENT(Basic)
+ QML_SINGLETON
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickBasicStyle(QObject *parent = nullptr);
+
+ QColor backgroundColor() const;
+ QColor overlayModalColor() const;
+ QColor overlayDimColor() const;
+ QColor textColor() const;
+ QColor textDarkColor() const;
+ QColor textLightColor() const;
+ QColor textLinkColor() const;
+ QColor textSelectionColor() const;
+ QColor textDisabledColor() const;
+ QColor textDisabledLightColor() const;
+ QColor textPlaceholderColor() const;
+ QColor focusColor() const;
+ QColor focusLightColor() const;
+ QColor focusPressedColor() const;
+ QColor buttonColor() const;
+ QColor buttonPressedColor() const;
+ QColor buttonCheckedColor() const;
+ QColor buttonCheckedPressedColor() const;
+ QColor buttonCheckedFocusColor() const;
+ QColor toolButtonColor() const;
+ QColor tabButtonColor() const;
+ QColor tabButtonPressedColor() const;
+ QColor tabButtonCheckedPressedColor() const;
+ QColor delegateColor() const;
+ QColor delegatePressedColor() const;
+ QColor delegateFocusColor() const;
+ QColor indicatorPressedColor() const;
+ QColor indicatorDisabledColor() const;
+ QColor indicatorFrameColor() const;
+ QColor indicatorFramePressedColor() const;
+ QColor indicatorFrameDisabledColor() const;
+ QColor frameDarkColor() const;
+ QColor frameLightColor() const;
+ QColor scrollBarColor() const;
+ QColor scrollBarPressedColor() const;
+ QColor progressBarColor() const;
+ QColor pageIndicatorColor() const;
+ QColor separatorColor() const;
+ QColor disabledDarkColor() const;
+ QColor disabledLightColor() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKBASICSTYLE_P_H
diff --git a/src/quickcontrols2/basic/qquickbasictheme.cpp b/src/quickcontrols2/basic/qquickbasictheme.cpp
new file mode 100644
index 0000000000..c65a7bc1c4
--- /dev/null
+++ b/src/quickcontrols2/basic/qquickbasictheme.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasictheme_p.h"
+
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickBasicTheme::initialize(QQuickTheme *theme)
+{
+ QPalette systemPalette;
+
+ systemPalette.setColor(QPalette::Base, QColor::fromRgba(0xFFFFFFFF));
+ systemPalette.setColor(QPalette::Disabled, QPalette::Base, QColor::fromRgba(0xFFD6D6D6));
+
+ systemPalette.setColor(QPalette::Button, QColor::fromRgba(0xFFE0E0E0));
+
+ systemPalette.setColor(QPalette::ButtonText, QColor::fromRgba(0xFF26282A));
+ systemPalette.setColor(QPalette::Disabled, QPalette::ButtonText, QColor::fromRgba(0x4D26282A));
+
+ systemPalette.setColor(QPalette::BrightText, QColor::fromRgba(0xFFFFFFFF));
+ systemPalette.setColor(QPalette::Disabled, QPalette::BrightText, QColor::fromRgba(0x4DFFFFFF));
+
+ systemPalette.setColor(QPalette::Dark, QColor::fromRgba(0xFF353637));
+
+ systemPalette.setColor(QPalette::Highlight, QColor::fromRgba(0xFF0066FF));
+ systemPalette.setColor(QPalette::Disabled, QPalette::Highlight, QColor::fromRgba(0xFFF0F6FF));
+
+ systemPalette.setColor(QPalette::HighlightedText, QColor::fromRgba(0xFF090909));
+
+ systemPalette.setColor(QPalette::Light, QColor::fromRgba(0xFFF6F6F6));
+
+ systemPalette.setColor(QPalette::Link, QColor::fromRgba(0xFF45A7D7));
+
+ systemPalette.setColor(QPalette::Mid, QColor::fromRgba(0xFFBDBDBD));
+
+ systemPalette.setColor(QPalette::Midlight, QColor::fromRgba(0xFFE4E4E4));
+
+ systemPalette.setColor(QPalette::Text, QColor::fromRgba(0xFF353637));
+ systemPalette.setColor(QPalette::Disabled, QPalette::Text, QColor::fromRgba(0x7F353637));
+
+ systemPalette.setColor(QPalette::Shadow, QColor::fromRgba(0xFF28282A));
+
+ systemPalette.setColor(QPalette::ToolTipBase, QColor::fromRgba(0xFFFFFFFF));
+ systemPalette.setColor(QPalette::ToolTipText, QColor::fromRgba(0xFF000000));
+
+ systemPalette.setColor(QPalette::Window, QColor::fromRgba(0xFFFFFFFF));
+
+ systemPalette.setColor(QPalette::WindowText, QColor::fromRgba(0xFF26282A));
+ systemPalette.setColor(QPalette::Disabled, QPalette::WindowText, QColor::fromRgba(0xFFBDBEBF));
+
+ systemPalette.setColor(QPalette::PlaceholderText, QColor::fromRgba(0x88353637));
+
+ theme->setPalette(QQuickTheme::System, systemPalette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/basic/qquickbasictheme_p.h b/src/quickcontrols2/basic/qquickbasictheme_p.h
new file mode 100644
index 0000000000..a0a299535a
--- /dev/null
+++ b/src/quickcontrols2/basic/qquickbasictheme_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBASICTHEME_P_H
+#define QQUICKBASICTHEME_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 QQuickBasicTheme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKBASICTHEME_P_H
diff --git a/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.cpp b/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.cpp
new file mode 100644
index 0000000000..ff7c3a5d63
--- /dev/null
+++ b/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbasicstyle_p.h"
+#include "qquickbasictheme_p.h"
+
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+extern void qml_register_types_QtQuick_Controls_Basic();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Basic);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2BasicStylePlugin: public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2BasicStylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+
+ QQuickBasicTheme theme;
+};
+
+QtQuickControls2BasicStylePlugin::QtQuickControls2BasicStylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Basic;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2BasicStylePlugin::name() const
+{
+ return QStringLiteral("Basic");
+}
+
+void QtQuickControls2BasicStylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ this->theme.initialize(theme);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2basicstyleplugin.moc"
diff --git a/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.qrc b/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.qrc
new file mode 100644
index 0000000000..27fd6ac2d4
--- /dev/null
+++ b/src/quickcontrols2/basic/qtquickcontrols2basicstyleplugin.qrc
@@ -0,0 +1,24 @@
+<RCC>
+ <qresource prefix="/qt-project.org/imports/QtQuick/Controls/Basic">
+ <file>images/arrow-indicator.png</file>
+ <file>images/arrow-indicator@2x.png</file>
+ <file>images/arrow-indicator@3x.png</file>
+ <file>images/arrow-indicator@4x.png</file>
+ <file>images/check.png</file>
+ <file>images/check@2x.png</file>
+ <file>images/check@3x.png</file>
+ <file>images/check@4x.png</file>
+ <file>images/dial-indicator.png</file>
+ <file>images/dial-indicator@2x.png</file>
+ <file>images/dial-indicator@3x.png</file>
+ <file>images/dial-indicator@4x.png</file>
+ <file>images/drop-indicator.png</file>
+ <file>images/drop-indicator@2x.png</file>
+ <file>images/drop-indicator@3x.png</file>
+ <file>images/drop-indicator@4x.png</file>
+ <file>images/double-arrow.png</file>
+ <file>images/double-arrow@2x.png</file>
+ <file>images/double-arrow@3x.png</file>
+ <file>images/double-arrow@4x.png</file>
+ </qresource>
+</RCC>
diff --git a/src/quickcontrols2/configure.cmake b/src/quickcontrols2/configure.cmake
new file mode 100644
index 0000000000..f996cf2884
--- /dev/null
+++ b/src/quickcontrols2/configure.cmake
@@ -0,0 +1,62 @@
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+
+#### Tests
+
+
+
+#### Features
+
+qt_feature("quickcontrols2-basic" PRIVATE
+ LABEL "Basic"
+)
+qt_feature("quickcontrols2-fusion" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "Fusion"
+ PURPOSE "Provides the platform agnostic desktop-oriented Fusion style."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+qt_feature("quickcontrols2-imagine" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "Imagine"
+ PURPOSE "Provides a style based on configurable image assets."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+qt_feature("quickcontrols2-material" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "Material"
+ PURPOSE "Provides a style based on the Material Design guidelines."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+qt_feature("quickcontrols2-universal" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "Universal"
+ PURPOSE "Provides a style based on the Universal Design guidelines."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+qt_feature("quickcontrols2-macos" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "macOS"
+ PURPOSE "Provides a native macOS desktop style."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+qt_feature("quickcontrols2-windows" PRIVATE
+ SECTION "Quick Controls 2"
+ LABEL "Windows"
+ PURPOSE "Provides a native Windows desktop style."
+ CONDITION QT_FEATURE_quickcontrols2_basic
+)
+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-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/quickcontrols2/designer/AbstractButtonSection.qml b/src/quickcontrols2/designer/AbstractButtonSection.qml
new file mode 100644
index 0000000000..2ccb82312b
--- /dev/null
+++ b/src/quickcontrols2/designer/AbstractButtonSection.qml
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("AbstractButton")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Text")
+ tooltip: qsTr("The text displayed on the button.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.text
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Display")
+ tooltip: qsTr("Determines how the icon and text are displayed within the button.")
+ disabledState: !backendValues.display.isAvailable
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.display
+ model: [ "IconOnly", "TextOnly", "TextBesideIcon" ]
+ scope: "AbstractButton"
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ visible: checkable
+ text: qsTr("Checkable")
+ tooltip: qsTr("Whether the button is checkable.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.checkable.valueToString
+ backendValue: backendValues.checkable
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Checked")
+ tooltip: qsTr("Whether the button is checked.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.checked.valueToString
+ backendValue: backendValues.checked
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Exclusive")
+ tooltip: qsTr("Whether the button is exclusive.")
+ disabledState: !backendValues.autoExclusive.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.autoExclusive.valueToString
+ backendValue: backendValues.autoExclusive
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Auto-Repeat")
+ tooltip: qsTr("Whether the button repeats pressed(), released() and clicked() signals while the button is pressed and held down.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.autoRepeat.valueToString
+ backendValue: backendValues.autoRepeat
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/BusyIndicatorSpecifics.qml b/src/quickcontrols2/designer/BusyIndicatorSpecifics.qml
new file mode 100644
index 0000000000..7b2899d304
--- /dev/null
+++ b/src/quickcontrols2/designer/BusyIndicatorSpecifics.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("BusyIndicator")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Running")
+ tooltip: qsTr("Whether the busy indicator is currently indicating activity.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.running.valueToString
+ backendValue: backendValues.running
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ButtonSection.qml b/src/quickcontrols2/designer/ButtonSection.qml
new file mode 100644
index 0000000000..ff70d52c6f
--- /dev/null
+++ b/src/quickcontrols2/designer/ButtonSection.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ id: section
+ caption: qsTr("Button")
+
+ SectionLayout {
+
+ Label {
+ text: qsTr("Flat")
+ tooltip: qsTr("Whether the button is flat.")
+ disabledState: !backendValues.flat.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.flat.valueToString
+ backendValue: backendValues.flat
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+ Label {
+ text: qsTr("Highlighted")
+ tooltip: qsTr("Whether the button is highlighted.")
+ disabledState: !backendValues.highlighted.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.highlighted.valueToString
+ backendValue: backendValues.highlighted
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ButtonSpecifics.qml b/src/quickcontrols2/designer/ButtonSpecifics.qml
new file mode 100644
index 0000000000..5a46e72aff
--- /dev/null
+++ b/src/quickcontrols2/designer/ButtonSpecifics.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ButtonSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/CMakeLists.txt b/src/quickcontrols2/designer/CMakeLists.txt
new file mode 100644
index 0000000000..a62461ed75
--- /dev/null
+++ b/src/quickcontrols2/designer/CMakeLists.txt
@@ -0,0 +1,61 @@
+file(GLOB_RECURSE __aux_qml_glob_files
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ "images/*.png"
+)
+qt_path_join(images_destination ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/QtQuick/Controls/designer/images")
+qt_copy_or_install(
+ FILES
+ ${__aux_qml_glob_files}
+ DESTINATION "${images_destination}"
+)
+qt_path_join(destination ${QT_INSTALL_DIR} "${INSTALL_QMLDIR}/QtQuick/Controls/designer")
+qt_copy_or_install(
+ FILES
+ AbstractButtonSection.qml
+ BusyIndicatorSpecifics.qml
+ ButtonSection.qml
+ ButtonSpecifics.qml
+ CheckBoxSpecifics.qml
+ CheckDelegateSpecifics.qml
+ CheckSection.qml
+ ComboBoxSpecifics.qml
+ ContainerSection.qml
+ ControlSection.qml
+ ControlSpecifics.qml
+ DelayButtonSpecifics.qml
+ DialSpecifics.qml
+ FrameSpecifics.qml
+ GroupBoxSpecifics.qml
+ InsetSection.qml
+ ItemDelegateSection.qml
+ ItemDelegateSpecifics.qml
+ LabelSpecifics.qml
+ PaddingSection.qml
+ PageIndicatorSpecifics.qml
+ PageSpecifics.qml
+ PaneSection.qml
+ PaneSpecifics.qml
+ ProgressBarSpecifics.qml
+ RadioButtonSpecifics.qml
+ RadioDelegateSpecifics.qml
+ RangeSliderSpecifics.qml
+ RoundButtonSpecifics.qml
+ ScrollViewSpecifics.qml
+ SliderSpecifics.qml
+ SpinBoxSpecifics.qml
+ StackViewSpecifics.qml
+ SwipeDelegateSpecifics.qml
+ SwipeViewSpecifics.qml
+ SwitchDelegateSpecifics.qml
+ SwitchSpecifics.qml
+ TabBarSpecifics.qml
+ TabButtonSpecifics.qml
+ TextAreaSpecifics.qml
+ TextFieldSpecifics.qml
+ ToolBarSpecifics.qml
+ ToolButtonSpecifics.qml
+ ToolSeparatorSpecifics.qml
+ TumblerSpecifics.qml
+ qtquickcontrols2.metainfo
+ DESTINATION "${destination}"
+)
diff --git a/src/quickcontrols2/designer/CheckBoxSpecifics.qml b/src/quickcontrols2/designer/CheckBoxSpecifics.qml
new file mode 100644
index 0000000000..d3aae9b679
--- /dev/null
+++ b/src/quickcontrols2/designer/CheckBoxSpecifics.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ CheckSection {
+ width: parent.width
+ caption: qsTr("CheckBox")
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/CheckDelegateSpecifics.qml b/src/quickcontrols2/designer/CheckDelegateSpecifics.qml
new file mode 100644
index 0000000000..8014480cd5
--- /dev/null
+++ b/src/quickcontrols2/designer/CheckDelegateSpecifics.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ CheckSection {
+ width: parent.width
+ caption: qsTr("CheckDelegate")
+ }
+
+ ItemDelegateSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/CheckSection.qml b/src/quickcontrols2/designer/CheckSection.qml
new file mode 100644
index 0000000000..0f49fa25af
--- /dev/null
+++ b/src/quickcontrols2/designer/CheckSection.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ SectionLayout {
+ Label {
+ text: qsTr("Check State")
+ tooltip: qsTr("The current check state.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.checkState
+ model: [ "Unchecked", "PartiallyChecked", "Checked" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Tri-state")
+ tooltip: qsTr("Whether the checkbox has three states.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.tristate.valueToString
+ backendValue: backendValues.tristate
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ComboBoxSpecifics.qml b/src/quickcontrols2/designer/ComboBoxSpecifics.qml
new file mode 100644
index 0000000000..810f19b5ff
--- /dev/null
+++ b/src/quickcontrols2/designer/ComboBoxSpecifics.qml
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("ComboBox")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Text Role")
+ tooltip: qsTr("The model role used for displaying text.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.textRole
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Current")
+ tooltip: qsTr("The index of the current item.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.currentIndex
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("Editable")
+ tooltip: qsTr("Whether the combo box is editable.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.editable.valueToString
+ backendValue: backendValues.editable
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("Flat")
+ tooltip: qsTr("Whether the combo box button is flat.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.flat.valueToString
+ backendValue: backendValues.flat
+ Layout.fillWidth: true
+ }
+ }
+ Label {
+ text: qsTr("DisplayText")
+ tooltip: qsTr("Holds the text that is displayed on the combo box button.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.displayText
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ContainerSection.qml b/src/quickcontrols2/designer/ContainerSection.qml
new file mode 100644
index 0000000000..15d1ddf598
--- /dev/null
+++ b/src/quickcontrols2/designer/ContainerSection.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("Container")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Current")
+ tooltip: qsTr("The index of the current item.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.currentIndex
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ControlSection.qml b/src/quickcontrols2/designer/ControlSection.qml
new file mode 100644
index 0000000000..12033eeaa3
--- /dev/null
+++ b/src/quickcontrols2/designer/ControlSection.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("Control")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Enabled")
+ tooltip: qsTr("Whether the control is enabled.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.enabled.valueToString
+ backendValue: backendValues.enabled
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Focus Policy")
+ tooltip: qsTr("Focus policy of the control.")
+ disabledState: !backendValues.focusPolicy.isAvailable
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.focusPolicy
+ model: [ "TabFocus", "ClickFocus", "StrongFocus", "WheelFocus", "NoFocus" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Hover")
+ tooltip: qsTr("Whether control accepts hover events.")
+ disabledState: !backendValues.hoverEnabled.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.hoverEnabled.valueToString
+ backendValue: backendValues.hoverEnabled
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Spacing")
+ tooltip: qsTr("Spacing between internal elements of the control.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.spacing
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Wheel")
+ tooltip: qsTr("Whether control accepts wheel events.")
+ disabledState: !backendValues.wheelEnabled.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.wheelEnabled.valueToString
+ backendValue: backendValues.wheelEnabled
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ControlSpecifics.qml b/src/quickcontrols2/designer/ControlSpecifics.qml
new file mode 100644
index 0000000000..3937437b5e
--- /dev/null
+++ b/src/quickcontrols2/designer/ControlSpecifics.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/DelayButtonSpecifics.qml b/src/quickcontrols2/designer/DelayButtonSpecifics.qml
new file mode 100644
index 0000000000..024fe589d7
--- /dev/null
+++ b/src/quickcontrols2/designer/DelayButtonSpecifics.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("DelayButton")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Delay")
+ tooltip: qsTr("The delay in milliseconds.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 9999999
+ decimals: 0
+ stepSize: 1
+ backendValue: backendValues.delay
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/DialSpecifics.qml b/src/quickcontrols2/designer/DialSpecifics.qml
new file mode 100644
index 0000000000..026cb2b1b0
--- /dev/null
+++ b/src/quickcontrols2/designer/DialSpecifics.qml
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("Dial")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Value")
+ tooltip: qsTr("The current value of the dial.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("From")
+ tooltip: qsTr("The starting value of the dial range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.from
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("To")
+ tooltip: qsTr("The ending value of the dial range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.to
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Step Size")
+ tooltip: qsTr("The step size of the dial.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.stepSize
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Snap Mode")
+ tooltip: qsTr("The snap mode of the dial.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.snapMode
+ model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ]
+ scope: "Dial"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Live")
+ tooltip: qsTr("Whether the dial provides live value updates.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.live.valueToString
+ backendValue: backendValues.live
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Input Mode")
+ tooltip: qsTr("How the dial tracks movement.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.inputMode
+ model: [ "Circular", "Horizontal", "Vertical" ]
+ scope: "Dial"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Wrap")
+ tooltip: qsTr("Whether the dial wraps when dragged.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.wrap.valueToString
+ backendValue: backendValues.wrap
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/FrameSpecifics.qml b/src/quickcontrols2/designer/FrameSpecifics.qml
new file mode 100644
index 0000000000..3673995659
--- /dev/null
+++ b/src/quickcontrols2/designer/FrameSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ PaneSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/GroupBoxSpecifics.qml b/src/quickcontrols2/designer/GroupBoxSpecifics.qml
new file mode 100644
index 0000000000..f808b00103
--- /dev/null
+++ b/src/quickcontrols2/designer/GroupBoxSpecifics.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("GroupBox")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Title")
+ tooltip: qsTr("The title of the group box.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.title
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ PaneSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/InsetSection.qml b/src/quickcontrols2/designer/InsetSection.qml
new file mode 100644
index 0000000000..45a4df4fcc
--- /dev/null
+++ b/src/quickcontrols2/designer/InsetSection.qml
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("Inset")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Vertical")
+ }
+ SecondColumnLayout {
+ Label {
+ text: qsTr("Top")
+ tooltip: qsTr("Top inset for the background.")
+ width: 42
+ }
+ SpinBox {
+ maximumValue: 10000
+ minimumValue: -10000
+ realDragRange: 5000
+ decimals: 0
+ backendValue: backendValues.topInset
+ Layout.fillWidth: true
+ }
+ Item {
+ width: 4
+ height: 4
+ }
+
+ Label {
+ text: qsTr("Bottom")
+ tooltip: qsTr("Bottom inset for the background.")
+ width: 42
+ }
+ SpinBox {
+ maximumValue: 10000
+ minimumValue: -10000
+ realDragRange: 5000
+ decimals: 0
+ backendValue: backendValues.bottomInset
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Horizontal")
+ }
+ SecondColumnLayout {
+ Label {
+ text: qsTr("Left")
+ tooltip: qsTr("Left inset for the background.")
+ width: 42
+ }
+ SpinBox {
+ maximumValue: 10000
+ minimumValue: -10000
+ realDragRange: 5000
+ decimals: 0
+ backendValue: backendValues.leftInset
+ Layout.fillWidth: true
+ }
+ Item {
+ width: 4
+ height: 4
+ }
+
+ Label {
+ text: qsTr("Right")
+ tooltip: qsTr("Right inset for the background.")
+ width: 42
+ }
+ SpinBox {
+ maximumValue: 10000
+ minimumValue: -10000
+ realDragRange: 5000
+ decimals: 0
+ backendValue: backendValues.rightInset
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ItemDelegateSection.qml b/src/quickcontrols2/designer/ItemDelegateSection.qml
new file mode 100644
index 0000000000..448a20d99d
--- /dev/null
+++ b/src/quickcontrols2/designer/ItemDelegateSection.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ id: section
+ caption: qsTr("ItemDelegate")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Highlighted")
+ tooltip: qsTr("Whether the delegate is highlighted.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.highlighted.valueToString
+ backendValue: backendValues.highlighted
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/ItemDelegateSpecifics.qml b/src/quickcontrols2/designer/ItemDelegateSpecifics.qml
new file mode 100644
index 0000000000..1757521dd8
--- /dev/null
+++ b/src/quickcontrols2/designer/ItemDelegateSpecifics.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ItemDelegateSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/LabelSpecifics.qml b/src/quickcontrols2/designer/LabelSpecifics.qml
new file mode 100644
index 0000000000..569b44c8da
--- /dev/null
+++ b/src/quickcontrols2/designer/LabelSpecifics.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ StandardTextSection {
+ width: parent.width
+ showIsWrapping: true
+ showFormatProperty: true
+ showVerticalAlignment: true
+ }
+
+ Section {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ caption: qsTr("Text Color")
+
+ ColorEditor {
+ caption: qsTr("Text Color")
+ backendValue: backendValues.color
+ supportGradient: false
+ }
+ }
+
+ Section {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ caption: qsTr("Style Color")
+
+ ColorEditor {
+ caption: qsTr("Style Color")
+ backendValue: backendValues.styleColor
+ supportGradient: false
+ }
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+
+ InsetSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/PaddingSection.qml b/src/quickcontrols2/designer/PaddingSection.qml
new file mode 100644
index 0000000000..325c5698e0
--- /dev/null
+++ b/src/quickcontrols2/designer/PaddingSection.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("Padding")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Top")
+ tooltip: qsTr("Padding between the content and the top edge of the control.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.topPadding
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Left")
+ tooltip: qsTr("Padding between the content and the left edge of the control.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.leftPadding
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Right")
+ tooltip: qsTr("Padding between the content and the right edge of the control.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.rightPadding
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Bottom")
+ tooltip: qsTr("Padding between the content and the bottom edge of the control.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.bottomPadding
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/PageIndicatorSpecifics.qml b/src/quickcontrols2/designer/PageIndicatorSpecifics.qml
new file mode 100644
index 0000000000..c73652e951
--- /dev/null
+++ b/src/quickcontrols2/designer/PageIndicatorSpecifics.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("PageIndicator")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Count")
+ tooltip: qsTr("The number of pages.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.count
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Current")
+ tooltip: qsTr("The index of the current page.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.currentIndex
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Interactive")
+ tooltip: qsTr("Whether the control is interactive.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.interactive.valueToString
+ backendValue: backendValues.interactive
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/PageSpecifics.qml b/src/quickcontrols2/designer/PageSpecifics.qml
new file mode 100644
index 0000000000..965ed655e7
--- /dev/null
+++ b/src/quickcontrols2/designer/PageSpecifics.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("Page")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Title")
+ tooltip: qsTr("Title of the page.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.title
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Width")
+ tooltip: qsTr("Content height used for calculating the total implicit width.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentWidth
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Height")
+ tooltip: qsTr("Content height used for calculating the total implicit height.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentHeight
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/PaneSection.qml b/src/quickcontrols2/designer/PaneSection.qml
new file mode 100644
index 0000000000..9dcc2097a9
--- /dev/null
+++ b/src/quickcontrols2/designer/PaneSection.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Section {
+ caption: qsTr("Pane")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Content Width")
+ tooltip: qsTr("Content height used for calculating the total implicit width.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentWidth
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Height")
+ tooltip: qsTr("Content height used for calculating the total implicit height.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentHeight
+ Layout.fillWidth: true
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/designer/PaneSpecifics.qml b/src/quickcontrols2/designer/PaneSpecifics.qml
new file mode 100644
index 0000000000..3673995659
--- /dev/null
+++ b/src/quickcontrols2/designer/PaneSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ PaneSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ProgressBarSpecifics.qml b/src/quickcontrols2/designer/ProgressBarSpecifics.qml
new file mode 100644
index 0000000000..14f879255c
--- /dev/null
+++ b/src/quickcontrols2/designer/ProgressBarSpecifics.qml
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("ProgressBar")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Indeterminate")
+ tooltip: qsTr("Whether the progress is indeterminate.")
+ disabledState: !backendValues.indeterminate.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.indeterminate.valueToString
+ backendValue: backendValues.indeterminate
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Value")
+ tooltip: qsTr("The current value of the progress.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("From")
+ tooltip: qsTr("The starting value for the progress.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.from
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("To")
+ tooltip: qsTr("The ending value for the progress.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.to
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/RadioButtonSpecifics.qml b/src/quickcontrols2/designer/RadioButtonSpecifics.qml
new file mode 100644
index 0000000000..df0af7e748
--- /dev/null
+++ b/src/quickcontrols2/designer/RadioButtonSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/RadioDelegateSpecifics.qml b/src/quickcontrols2/designer/RadioDelegateSpecifics.qml
new file mode 100644
index 0000000000..1757521dd8
--- /dev/null
+++ b/src/quickcontrols2/designer/RadioDelegateSpecifics.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ItemDelegateSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/RangeSliderSpecifics.qml b/src/quickcontrols2/designer/RangeSliderSpecifics.qml
new file mode 100644
index 0000000000..577033ed80
--- /dev/null
+++ b/src/quickcontrols2/designer/RangeSliderSpecifics.qml
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("RangeSlider")
+
+ SectionLayout {
+ Label {
+ text: qsTr("First Value")
+ tooltip: qsTr("The value of the first range slider handle.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.first_value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Second Value")
+ tooltip: qsTr("The value of the second range slider handle.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.second_value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("From")
+ tooltip: qsTr("The starting value of the range slider range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.from
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("To")
+ tooltip: qsTr("The ending value of the range slider range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.to
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Step Size")
+ tooltip: qsTr("The step size of the range slider.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.stepSize
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Snap Mode")
+ tooltip: qsTr("The snap mode of the range slider.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.snapMode
+ model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ]
+ scope: "RangeSlider"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Orientation")
+ tooltip: qsTr("The orientation of the range slider.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.orientation
+ model: [ "Horizontal", "Vertical" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Live")
+ tooltip: qsTr("Whether the range slider provides live value updates.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.live.valueToString
+ backendValue: backendValues.live
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Touch drag threshold")
+ tooltip: qsTr("The threshold (in logical pixels) at which a touch drag event will be initiated.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 10000
+ decimals: 0
+ backendValue: backendValues.touchDragThreshold
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/RoundButtonSpecifics.qml b/src/quickcontrols2/designer/RoundButtonSpecifics.qml
new file mode 100644
index 0000000000..58d3468952
--- /dev/null
+++ b/src/quickcontrols2/designer/RoundButtonSpecifics.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("RoundButton")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Radius")
+ tooltip: qsTr("Radius of the button.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 10000
+ decimals: 0
+ backendValue: backendValues.radius
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ButtonSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ScrollViewSpecifics.qml b/src/quickcontrols2/designer/ScrollViewSpecifics.qml
new file mode 100644
index 0000000000..ae525b747c
--- /dev/null
+++ b/src/quickcontrols2/designer/ScrollViewSpecifics.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("ScrollView")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Content Width")
+ tooltip: qsTr("Content height used for calculating the total implicit width.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentWidth
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Height")
+ tooltip: qsTr("Content height used for calculating the total implicit height.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentHeight
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SliderSpecifics.qml b/src/quickcontrols2/designer/SliderSpecifics.qml
new file mode 100644
index 0000000000..3af2054025
--- /dev/null
+++ b/src/quickcontrols2/designer/SliderSpecifics.qml
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("Slider")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Value")
+ tooltip: qsTr("The current value of the slider.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("From")
+ tooltip: qsTr("The starting value of the slider range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.from
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("To")
+ tooltip: qsTr("The ending value of the slider range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.to
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Step Size")
+ tooltip: qsTr("The step size of the slider.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ stepSize: 0.1
+ backendValue: backendValues.stepSize
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Snap Mode")
+ tooltip: qsTr("The snap mode of the slider.")
+ disabledState: !backendValues.snapMode.isAvailable
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.snapMode
+ model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ]
+ scope: "Slider"
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Orientation")
+ tooltip: qsTr("The orientation of the slider.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.orientation
+ model: [ "Horizontal", "Vertical" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Live")
+ tooltip: qsTr("Whether the slider provides live value updates.")
+ disabledState: !backendValues.live.isAvailable
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.live.valueToString
+ backendValue: backendValues.live
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+
+ Label {
+ text: qsTr("Touch drag threshold")
+ tooltip: qsTr("The threshold (in logical pixels) at which a touch drag event will be initiated.")
+ disabledState: !backendValues.touchDragThreshold.isAvailable
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: 0
+ maximumValue: 10000
+ decimals: 0
+ backendValue: backendValues.touchDragThreshold
+ Layout.fillWidth: true
+ enabled: backendValue.isAvailable
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SpinBoxSpecifics.qml b/src/quickcontrols2/designer/SpinBoxSpecifics.qml
new file mode 100644
index 0000000000..9c07e8c524
--- /dev/null
+++ b/src/quickcontrols2/designer/SpinBoxSpecifics.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("SpinBox")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Value")
+ tooltip: qsTr("The current value of the spinbox.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ minimumValue: Math.min(backendValues.from.value, backendValues.to.value)
+ maximumValue: Math.max(backendValues.from.value, backendValues.to.value)
+ decimals: 2
+ backendValue: backendValues.value
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("From")
+ tooltip: qsTr("The starting value of the spinbox range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ backendValue: backendValues.from
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("To")
+ tooltip: qsTr("The ending value of the spinbox range.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ backendValue: backendValues.to
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Step Size")
+ tooltip: qsTr("The step size of the spinbox.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 2
+ backendValue: backendValues.stepSize
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Editable")
+ tooltip: qsTr("Whether the spinbox is editable.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.editable.valueToString
+ backendValue: backendValues.editable
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Wrap")
+ tooltip: qsTr("Whether the spinbox wraps.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.wrap.valueToString
+ backendValue: backendValues.wrap
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/StackViewSpecifics.qml b/src/quickcontrols2/designer/StackViewSpecifics.qml
new file mode 100644
index 0000000000..3937437b5e
--- /dev/null
+++ b/src/quickcontrols2/designer/StackViewSpecifics.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SwipeDelegateSpecifics.qml b/src/quickcontrols2/designer/SwipeDelegateSpecifics.qml
new file mode 100644
index 0000000000..1757521dd8
--- /dev/null
+++ b/src/quickcontrols2/designer/SwipeDelegateSpecifics.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ItemDelegateSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SwipeViewSpecifics.qml b/src/quickcontrols2/designer/SwipeViewSpecifics.qml
new file mode 100644
index 0000000000..a28a291781
--- /dev/null
+++ b/src/quickcontrols2/designer/SwipeViewSpecifics.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("SwipeView")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Interactive")
+ tooltip: qsTr("Whether the view is interactive.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.interactive.valueToString
+ backendValue: backendValues.interactive
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Orientation")
+ tooltip: qsTr("Orientation of the view.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.orientation
+ model: [ "Horizontal", "Vertical" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ContainerSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SwitchDelegateSpecifics.qml b/src/quickcontrols2/designer/SwitchDelegateSpecifics.qml
new file mode 100644
index 0000000000..4236de6772
--- /dev/null
+++ b/src/quickcontrols2/designer/SwitchDelegateSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ItemDelegateSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/SwitchSpecifics.qml b/src/quickcontrols2/designer/SwitchSpecifics.qml
new file mode 100644
index 0000000000..df0af7e748
--- /dev/null
+++ b/src/quickcontrols2/designer/SwitchSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/TabBarSpecifics.qml b/src/quickcontrols2/designer/TabBarSpecifics.qml
new file mode 100644
index 0000000000..6f02cdaac2
--- /dev/null
+++ b/src/quickcontrols2/designer/TabBarSpecifics.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("TabBar")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Position")
+ tooltip: qsTr("Position of the tabbar.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.position
+ model: [ "Header", "Footer" ]
+ scope: "TabBar"
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Width")
+ tooltip: qsTr("Content height used for calculating the total implicit width.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentWidth
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Content Height")
+ tooltip: qsTr("Content height used for calculating the total implicit height.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.contentHeight
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ContainerSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/TabButtonSpecifics.qml b/src/quickcontrols2/designer/TabButtonSpecifics.qml
new file mode 100644
index 0000000000..df0af7e748
--- /dev/null
+++ b/src/quickcontrols2/designer/TabButtonSpecifics.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/TextAreaSpecifics.qml b/src/quickcontrols2/designer/TextAreaSpecifics.qml
new file mode 100644
index 0000000000..785d7a5017
--- /dev/null
+++ b/src/quickcontrols2/designer/TextAreaSpecifics.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("TextArea")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Placeholder")
+ tooltip: qsTr("Placeholder text displayed when the editor is empty.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.placeholderText
+ Layout.fillWidth: true
+ }
+
+ }
+
+ Label {
+ text: qsTr("Hover")
+ tooltip: qsTr("Whether text area accepts hover events.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.hoverEnabled.valueToString
+ backendValue: backendValues.hoverEnabled
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ Section {
+ width: parent.width
+ caption: qsTr("Placeholder Text Color")
+
+ ColorEditor {
+ caption: qsTr("Placeholder Text Color")
+ backendValue: backendValues.placeholderTextColor
+ supportGradient: false
+ }
+ }
+
+ StandardTextSection {
+ width: parent.width
+ showIsWrapping: true
+ showFormatProperty: true
+ showVerticalAlignment: true
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+
+ InsetSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/TextFieldSpecifics.qml b/src/quickcontrols2/designer/TextFieldSpecifics.qml
new file mode 100644
index 0000000000..33a90f2ae8
--- /dev/null
+++ b/src/quickcontrols2/designer/TextFieldSpecifics.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("TextField")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Placeholder")
+ tooltip: qsTr("Placeholder text displayed when the editor is empty.")
+ }
+ SecondColumnLayout {
+ LineEdit {
+ backendValue: backendValues.placeholderText
+ Layout.fillWidth: true
+ }
+
+ }
+
+ Label {
+ text: qsTr("Hover")
+ tooltip: qsTr("Whether text field accepts hover events.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.hoverEnabled.valueToString
+ backendValue: backendValues.hoverEnabled
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ Section {
+ width: parent.width
+ caption: qsTr("Placeholder Text Color")
+
+ ColorEditor {
+ caption: qsTr("Placeholder Text Color")
+ backendValue: backendValues.placeholderTextColor
+ supportGradient: false
+ }
+ }
+
+ StandardTextSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+
+ InsetSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ToolBarSpecifics.qml b/src/quickcontrols2/designer/ToolBarSpecifics.qml
new file mode 100644
index 0000000000..2b1b17d2bb
--- /dev/null
+++ b/src/quickcontrols2/designer/ToolBarSpecifics.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("ToolBar")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Position")
+ tooltip: qsTr("Position of the toolbar.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.position
+ model: [ "Header", "Footer" ]
+ scope: "ToolBar"
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ PaneSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ToolButtonSpecifics.qml b/src/quickcontrols2/designer/ToolButtonSpecifics.qml
new file mode 100644
index 0000000000..5a46e72aff
--- /dev/null
+++ b/src/quickcontrols2/designer/ToolButtonSpecifics.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ ButtonSection {
+ width: parent.width
+ }
+
+ AbstractButtonSection {
+ width: parent.width
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/ToolSeparatorSpecifics.qml b/src/quickcontrols2/designer/ToolSeparatorSpecifics.qml
new file mode 100644
index 0000000000..a62147ecaf
--- /dev/null
+++ b/src/quickcontrols2/designer/ToolSeparatorSpecifics.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("ToolSeparator")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Orientation")
+ tooltip: qsTr("The orientation of the separator.")
+ }
+ SecondColumnLayout {
+ ComboBox {
+ backendValue: backendValues.orientation
+ model: [ "Horizontal", "Vertical" ]
+ scope: "Qt"
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/TumblerSpecifics.qml b/src/quickcontrols2/designer/TumblerSpecifics.qml
new file mode 100644
index 0000000000..25fb927581
--- /dev/null
+++ b/src/quickcontrols2/designer/TumblerSpecifics.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import HelperWidgets
+import QtQuick.Layouts
+
+Column {
+ width: parent.width
+
+ Section {
+ width: parent.width
+ caption: qsTr("Tumbler")
+
+ SectionLayout {
+ Label {
+ text: qsTr("Visible Count")
+ tooltip: qsTr("The count of visible items.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.visibleItemCount
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Current")
+ tooltip: qsTr("The index of the current item.")
+ }
+ SecondColumnLayout {
+ SpinBox {
+ maximumValue: 9999999
+ minimumValue: -9999999
+ decimals: 0
+ backendValue: backendValues.currentIndex
+ Layout.fillWidth: true
+ }
+ }
+
+ Label {
+ text: qsTr("Wrap")
+ tooltip: qsTr("Whether the tumbler wrap.")
+ }
+ SecondColumnLayout {
+ CheckBox {
+ text: backendValues.wrap.valueToString
+ backendValue: backendValues.wrap
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ ControlSection {
+ width: parent.width
+ }
+
+ FontSection {
+ width: parent.width
+ }
+
+ PaddingSection {
+ width: parent.width
+ }
+}
diff --git a/src/quickcontrols2/designer/designer.pri b/src/quickcontrols2/designer/designer.pri
new file mode 100644
index 0000000000..6692b20316
--- /dev/null
+++ b/src/quickcontrols2/designer/designer.pri
@@ -0,0 +1,52 @@
+AUX_QML_FILES += \
+ $$PWD/qtquickcontrols2.metainfo
+
+AUX_QML_FILES += \
+ $$PWD/AbstractButtonSection.qml \
+ $$PWD/BusyIndicatorSpecifics.qml \
+ $$PWD/ButtonSection.qml \
+ $$PWD/ButtonSpecifics.qml \
+ $$PWD/CheckBoxSpecifics.qml \
+ $$PWD/CheckDelegateSpecifics.qml \
+ $$PWD/CheckSection.qml \
+ $$PWD/ComboBoxSpecifics.qml \
+ $$PWD/ContainerSection.qml \
+ $$PWD/ControlSection.qml \
+ $$PWD/ControlSpecifics.qml \
+ $$PWD/DelayButtonSpecifics.qml \
+ $$PWD/DialSpecifics.qml \
+ $$PWD/FrameSpecifics.qml \
+ $$PWD/GroupBoxSpecifics.qml \
+ $$PWD/InsetSection.qml \
+ $$PWD/ItemDelegateSection.qml \
+ $$PWD/ItemDelegateSpecifics.qml \
+ $$PWD/LabelSpecifics.qml \
+ $$PWD/PaddingSection.qml \
+ $$PWD/PageSpecifics.qml \
+ $$PWD/PageIndicatorSpecifics.qml \
+ $$PWD/PaneSection.qml \
+ $$PWD/PaneSpecifics.qml \
+ $$PWD/ProgressBarSpecifics.qml \
+ $$PWD/RadioButtonSpecifics.qml \
+ $$PWD/RadioDelegateSpecifics.qml \
+ $$PWD/RangeSliderSpecifics.qml \
+ $$PWD/RoundButtonSpecifics.qml \
+ $$PWD/ScrollViewSpecifics.qml \
+ $$PWD/SliderSpecifics.qml \
+ $$PWD/SpinBoxSpecifics.qml \
+ $$PWD/StackViewSpecifics.qml \
+ $$PWD/SwipeDelegateSpecifics.qml \
+ $$PWD/SwipeViewSpecifics.qml \
+ $$PWD/SwitchSpecifics.qml \
+ $$PWD/SwitchDelegateSpecifics.qml \
+ $$PWD/TabBarSpecifics.qml \
+ $$PWD/TabButtonSpecifics.qml \
+ $$PWD/TextAreaSpecifics.qml \
+ $$PWD/TextFieldSpecifics.qml \
+ $$PWD/ToolBarSpecifics.qml \
+ $$PWD/ToolButtonSpecifics.qml \
+ $$PWD/ToolSeparatorSpecifics.qml \
+ $$PWD/TumblerSpecifics.qml
+
+AUX_QML_FILES += \
+ $$files($$PWD/images/*.png)
diff --git a/src/quickcontrols2/designer/images/busyindicator-icon.png b/src/quickcontrols2/designer/images/busyindicator-icon.png
new file mode 100644
index 0000000000..666d1ed93f
--- /dev/null
+++ b/src/quickcontrols2/designer/images/busyindicator-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/busyindicator-icon16.png b/src/quickcontrols2/designer/images/busyindicator-icon16.png
new file mode 100644
index 0000000000..5aa57d7f48
--- /dev/null
+++ b/src/quickcontrols2/designer/images/busyindicator-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/busyindicator-icon@2x.png b/src/quickcontrols2/designer/images/busyindicator-icon@2x.png
new file mode 100644
index 0000000000..bb2278ff89
--- /dev/null
+++ b/src/quickcontrols2/designer/images/busyindicator-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/button-icon.png b/src/quickcontrols2/designer/images/button-icon.png
new file mode 100644
index 0000000000..c44909f6dd
--- /dev/null
+++ b/src/quickcontrols2/designer/images/button-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/button-icon16.png b/src/quickcontrols2/designer/images/button-icon16.png
new file mode 100644
index 0000000000..5c921deb13
--- /dev/null
+++ b/src/quickcontrols2/designer/images/button-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/button-icon@2x.png b/src/quickcontrols2/designer/images/button-icon@2x.png
new file mode 100644
index 0000000000..f90a1ba7dc
--- /dev/null
+++ b/src/quickcontrols2/designer/images/button-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/checkbox-icon.png b/src/quickcontrols2/designer/images/checkbox-icon.png
new file mode 100644
index 0000000000..ee669b3a88
--- /dev/null
+++ b/src/quickcontrols2/designer/images/checkbox-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/checkbox-icon16.png b/src/quickcontrols2/designer/images/checkbox-icon16.png
new file mode 100644
index 0000000000..8d89eab841
--- /dev/null
+++ b/src/quickcontrols2/designer/images/checkbox-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/checkbox-icon@2x.png b/src/quickcontrols2/designer/images/checkbox-icon@2x.png
new file mode 100644
index 0000000000..51c5601de0
--- /dev/null
+++ b/src/quickcontrols2/designer/images/checkbox-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/combobox-icon.png b/src/quickcontrols2/designer/images/combobox-icon.png
new file mode 100644
index 0000000000..2d31b17c65
--- /dev/null
+++ b/src/quickcontrols2/designer/images/combobox-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/combobox-icon16.png b/src/quickcontrols2/designer/images/combobox-icon16.png
new file mode 100644
index 0000000000..15fc3505ba
--- /dev/null
+++ b/src/quickcontrols2/designer/images/combobox-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/combobox-icon@2x.png b/src/quickcontrols2/designer/images/combobox-icon@2x.png
new file mode 100644
index 0000000000..5f82390596
--- /dev/null
+++ b/src/quickcontrols2/designer/images/combobox-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/delaybutton-icon.png b/src/quickcontrols2/designer/images/delaybutton-icon.png
new file mode 100644
index 0000000000..5a55bd9f77
--- /dev/null
+++ b/src/quickcontrols2/designer/images/delaybutton-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/delaybutton-icon16.png b/src/quickcontrols2/designer/images/delaybutton-icon16.png
new file mode 100644
index 0000000000..cd21394e46
--- /dev/null
+++ b/src/quickcontrols2/designer/images/delaybutton-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/delaybutton-icon@2x.png b/src/quickcontrols2/designer/images/delaybutton-icon@2x.png
new file mode 100644
index 0000000000..7beee2fab0
--- /dev/null
+++ b/src/quickcontrols2/designer/images/delaybutton-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/dial-icon.png b/src/quickcontrols2/designer/images/dial-icon.png
new file mode 100644
index 0000000000..b3b63e3523
--- /dev/null
+++ b/src/quickcontrols2/designer/images/dial-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/dial-icon16.png b/src/quickcontrols2/designer/images/dial-icon16.png
new file mode 100644
index 0000000000..8d8c7c09b0
--- /dev/null
+++ b/src/quickcontrols2/designer/images/dial-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/dial-icon@2x.png b/src/quickcontrols2/designer/images/dial-icon@2x.png
new file mode 100644
index 0000000000..22547a16b8
--- /dev/null
+++ b/src/quickcontrols2/designer/images/dial-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/frame-icon.png b/src/quickcontrols2/designer/images/frame-icon.png
new file mode 100644
index 0000000000..32abc8bf1e
--- /dev/null
+++ b/src/quickcontrols2/designer/images/frame-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/frame-icon16.png b/src/quickcontrols2/designer/images/frame-icon16.png
new file mode 100644
index 0000000000..e5b65ad53b
--- /dev/null
+++ b/src/quickcontrols2/designer/images/frame-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/frame-icon@2x.png b/src/quickcontrols2/designer/images/frame-icon@2x.png
new file mode 100644
index 0000000000..8b876f38ec
--- /dev/null
+++ b/src/quickcontrols2/designer/images/frame-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/groupbox-icon.png b/src/quickcontrols2/designer/images/groupbox-icon.png
new file mode 100644
index 0000000000..5542ecf8bf
--- /dev/null
+++ b/src/quickcontrols2/designer/images/groupbox-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/groupbox-icon16.png b/src/quickcontrols2/designer/images/groupbox-icon16.png
new file mode 100644
index 0000000000..9cf4324819
--- /dev/null
+++ b/src/quickcontrols2/designer/images/groupbox-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/groupbox-icon@2x.png b/src/quickcontrols2/designer/images/groupbox-icon@2x.png
new file mode 100644
index 0000000000..80dab3c716
--- /dev/null
+++ b/src/quickcontrols2/designer/images/groupbox-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/itemdelegate-icon.png b/src/quickcontrols2/designer/images/itemdelegate-icon.png
new file mode 100644
index 0000000000..822cf3e7b8
--- /dev/null
+++ b/src/quickcontrols2/designer/images/itemdelegate-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/itemdelegate-icon16.png b/src/quickcontrols2/designer/images/itemdelegate-icon16.png
new file mode 100644
index 0000000000..b3ed007a0e
--- /dev/null
+++ b/src/quickcontrols2/designer/images/itemdelegate-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/itemdelegate-icon@2x.png b/src/quickcontrols2/designer/images/itemdelegate-icon@2x.png
new file mode 100644
index 0000000000..cb81308ff8
--- /dev/null
+++ b/src/quickcontrols2/designer/images/itemdelegate-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/label-icon.png b/src/quickcontrols2/designer/images/label-icon.png
new file mode 100644
index 0000000000..788bef078c
--- /dev/null
+++ b/src/quickcontrols2/designer/images/label-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/label-icon16.png b/src/quickcontrols2/designer/images/label-icon16.png
new file mode 100644
index 0000000000..b68d384568
--- /dev/null
+++ b/src/quickcontrols2/designer/images/label-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/label-icon@2x.png b/src/quickcontrols2/designer/images/label-icon@2x.png
new file mode 100644
index 0000000000..7001413d3b
--- /dev/null
+++ b/src/quickcontrols2/designer/images/label-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/page-icon.png b/src/quickcontrols2/designer/images/page-icon.png
new file mode 100644
index 0000000000..b5ac87e899
--- /dev/null
+++ b/src/quickcontrols2/designer/images/page-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/page-icon16.png b/src/quickcontrols2/designer/images/page-icon16.png
new file mode 100644
index 0000000000..bc6810b605
--- /dev/null
+++ b/src/quickcontrols2/designer/images/page-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/page-icon@2x.png b/src/quickcontrols2/designer/images/page-icon@2x.png
new file mode 100644
index 0000000000..23db032f4a
--- /dev/null
+++ b/src/quickcontrols2/designer/images/page-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pageindicator-icon.png b/src/quickcontrols2/designer/images/pageindicator-icon.png
new file mode 100644
index 0000000000..edb6b377bb
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pageindicator-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pageindicator-icon16.png b/src/quickcontrols2/designer/images/pageindicator-icon16.png
new file mode 100644
index 0000000000..0fb8967564
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pageindicator-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pageindicator-icon@2x.png b/src/quickcontrols2/designer/images/pageindicator-icon@2x.png
new file mode 100644
index 0000000000..7be0ee813b
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pageindicator-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pane-icon.png b/src/quickcontrols2/designer/images/pane-icon.png
new file mode 100644
index 0000000000..62ebe487ff
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pane-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pane-icon16.png b/src/quickcontrols2/designer/images/pane-icon16.png
new file mode 100644
index 0000000000..2b8048441c
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pane-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/pane-icon@2x.png b/src/quickcontrols2/designer/images/pane-icon@2x.png
new file mode 100644
index 0000000000..55bb116a69
--- /dev/null
+++ b/src/quickcontrols2/designer/images/pane-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/progressbar-icon.png b/src/quickcontrols2/designer/images/progressbar-icon.png
new file mode 100644
index 0000000000..a023f73c30
--- /dev/null
+++ b/src/quickcontrols2/designer/images/progressbar-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/progressbar-icon16.png b/src/quickcontrols2/designer/images/progressbar-icon16.png
new file mode 100644
index 0000000000..6fede21d8c
--- /dev/null
+++ b/src/quickcontrols2/designer/images/progressbar-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/progressbar-icon@2x.png b/src/quickcontrols2/designer/images/progressbar-icon@2x.png
new file mode 100644
index 0000000000..0069400335
--- /dev/null
+++ b/src/quickcontrols2/designer/images/progressbar-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/radiobutton-icon.png b/src/quickcontrols2/designer/images/radiobutton-icon.png
new file mode 100644
index 0000000000..d38170e22f
--- /dev/null
+++ b/src/quickcontrols2/designer/images/radiobutton-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/radiobutton-icon16.png b/src/quickcontrols2/designer/images/radiobutton-icon16.png
new file mode 100644
index 0000000000..07b46a8ab0
--- /dev/null
+++ b/src/quickcontrols2/designer/images/radiobutton-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/radiobutton-icon@2x.png b/src/quickcontrols2/designer/images/radiobutton-icon@2x.png
new file mode 100644
index 0000000000..4bbddda4b2
--- /dev/null
+++ b/src/quickcontrols2/designer/images/radiobutton-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/rangeslider-icon.png b/src/quickcontrols2/designer/images/rangeslider-icon.png
new file mode 100644
index 0000000000..1c4c7b2948
--- /dev/null
+++ b/src/quickcontrols2/designer/images/rangeslider-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/rangeslider-icon16.png b/src/quickcontrols2/designer/images/rangeslider-icon16.png
new file mode 100644
index 0000000000..3be4624ddd
--- /dev/null
+++ b/src/quickcontrols2/designer/images/rangeslider-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/rangeslider-icon@2x.png b/src/quickcontrols2/designer/images/rangeslider-icon@2x.png
new file mode 100644
index 0000000000..aee69b3302
--- /dev/null
+++ b/src/quickcontrols2/designer/images/rangeslider-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/roundbutton-icon.png b/src/quickcontrols2/designer/images/roundbutton-icon.png
new file mode 100644
index 0000000000..d4b470dc25
--- /dev/null
+++ b/src/quickcontrols2/designer/images/roundbutton-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/roundbutton-icon16.png b/src/quickcontrols2/designer/images/roundbutton-icon16.png
new file mode 100644
index 0000000000..f6f3666639
--- /dev/null
+++ b/src/quickcontrols2/designer/images/roundbutton-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/roundbutton-icon@2x.png b/src/quickcontrols2/designer/images/roundbutton-icon@2x.png
new file mode 100644
index 0000000000..4553e165e7
--- /dev/null
+++ b/src/quickcontrols2/designer/images/roundbutton-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/scrollview-icon.png b/src/quickcontrols2/designer/images/scrollview-icon.png
new file mode 100644
index 0000000000..5ef73ff19f
--- /dev/null
+++ b/src/quickcontrols2/designer/images/scrollview-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/scrollview-icon16.png b/src/quickcontrols2/designer/images/scrollview-icon16.png
new file mode 100644
index 0000000000..f8ca7a3685
--- /dev/null
+++ b/src/quickcontrols2/designer/images/scrollview-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/scrollview-icon@2x.png b/src/quickcontrols2/designer/images/scrollview-icon@2x.png
new file mode 100644
index 0000000000..0eb7f9665e
--- /dev/null
+++ b/src/quickcontrols2/designer/images/scrollview-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/slider-icon.png b/src/quickcontrols2/designer/images/slider-icon.png
new file mode 100644
index 0000000000..bd0a9729be
--- /dev/null
+++ b/src/quickcontrols2/designer/images/slider-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/slider-icon16.png b/src/quickcontrols2/designer/images/slider-icon16.png
new file mode 100644
index 0000000000..a08622df89
--- /dev/null
+++ b/src/quickcontrols2/designer/images/slider-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/slider-icon@2x.png b/src/quickcontrols2/designer/images/slider-icon@2x.png
new file mode 100644
index 0000000000..93842e4cdd
--- /dev/null
+++ b/src/quickcontrols2/designer/images/slider-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/spinbox-icon.png b/src/quickcontrols2/designer/images/spinbox-icon.png
new file mode 100644
index 0000000000..37277c5e43
--- /dev/null
+++ b/src/quickcontrols2/designer/images/spinbox-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/spinbox-icon16.png b/src/quickcontrols2/designer/images/spinbox-icon16.png
new file mode 100644
index 0000000000..f88711dd25
--- /dev/null
+++ b/src/quickcontrols2/designer/images/spinbox-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/spinbox-icon@2x.png b/src/quickcontrols2/designer/images/spinbox-icon@2x.png
new file mode 100644
index 0000000000..b62a3bad51
--- /dev/null
+++ b/src/quickcontrols2/designer/images/spinbox-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/stackview-icon.png b/src/quickcontrols2/designer/images/stackview-icon.png
new file mode 100644
index 0000000000..a6ced34925
--- /dev/null
+++ b/src/quickcontrols2/designer/images/stackview-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/stackview-icon16.png b/src/quickcontrols2/designer/images/stackview-icon16.png
new file mode 100644
index 0000000000..0f19d0efa3
--- /dev/null
+++ b/src/quickcontrols2/designer/images/stackview-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/stackview-icon@2x.png b/src/quickcontrols2/designer/images/stackview-icon@2x.png
new file mode 100644
index 0000000000..9b5ef9517b
--- /dev/null
+++ b/src/quickcontrols2/designer/images/stackview-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/swipeview-icon.png b/src/quickcontrols2/designer/images/swipeview-icon.png
new file mode 100644
index 0000000000..031cb27c36
--- /dev/null
+++ b/src/quickcontrols2/designer/images/swipeview-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/swipeview-icon16.png b/src/quickcontrols2/designer/images/swipeview-icon16.png
new file mode 100644
index 0000000000..446c469690
--- /dev/null
+++ b/src/quickcontrols2/designer/images/swipeview-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/swipeview-icon@2x.png b/src/quickcontrols2/designer/images/swipeview-icon@2x.png
new file mode 100644
index 0000000000..0ccb978c46
--- /dev/null
+++ b/src/quickcontrols2/designer/images/swipeview-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/switch-icon.png b/src/quickcontrols2/designer/images/switch-icon.png
new file mode 100644
index 0000000000..e018159286
--- /dev/null
+++ b/src/quickcontrols2/designer/images/switch-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/switch-icon16.png b/src/quickcontrols2/designer/images/switch-icon16.png
new file mode 100644
index 0000000000..9abd275659
--- /dev/null
+++ b/src/quickcontrols2/designer/images/switch-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/switch-icon@2x.png b/src/quickcontrols2/designer/images/switch-icon@2x.png
new file mode 100644
index 0000000000..787f54ca41
--- /dev/null
+++ b/src/quickcontrols2/designer/images/switch-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textarea-icon.png b/src/quickcontrols2/designer/images/textarea-icon.png
new file mode 100644
index 0000000000..f1b2dc0f84
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textarea-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textarea-icon16.png b/src/quickcontrols2/designer/images/textarea-icon16.png
new file mode 100644
index 0000000000..4afc1fbab5
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textarea-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textarea-icon@2x.png b/src/quickcontrols2/designer/images/textarea-icon@2x.png
new file mode 100644
index 0000000000..c32ecc71a9
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textarea-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textfield-icon.png b/src/quickcontrols2/designer/images/textfield-icon.png
new file mode 100644
index 0000000000..ba5537acef
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textfield-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textfield-icon16.png b/src/quickcontrols2/designer/images/textfield-icon16.png
new file mode 100644
index 0000000000..c4a62a6582
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textfield-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/textfield-icon@2x.png b/src/quickcontrols2/designer/images/textfield-icon@2x.png
new file mode 100644
index 0000000000..e05fd41b9a
--- /dev/null
+++ b/src/quickcontrols2/designer/images/textfield-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbar-icon.png b/src/quickcontrols2/designer/images/toolbar-icon.png
new file mode 100644
index 0000000000..5cb5b2e1af
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbar-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbar-icon16.png b/src/quickcontrols2/designer/images/toolbar-icon16.png
new file mode 100644
index 0000000000..569373afa1
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbar-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbar-icon@2x.png b/src/quickcontrols2/designer/images/toolbar-icon@2x.png
new file mode 100644
index 0000000000..fd9e6ceebc
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbar-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbutton-icon.png b/src/quickcontrols2/designer/images/toolbutton-icon.png
new file mode 100644
index 0000000000..3298f69519
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbutton-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbutton-icon16.png b/src/quickcontrols2/designer/images/toolbutton-icon16.png
new file mode 100644
index 0000000000..9ab7861c25
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbutton-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolbutton-icon@2x.png b/src/quickcontrols2/designer/images/toolbutton-icon@2x.png
new file mode 100644
index 0000000000..e5958cded3
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolbutton-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolseparator-icon.png b/src/quickcontrols2/designer/images/toolseparator-icon.png
new file mode 100644
index 0000000000..5e99f06f2e
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolseparator-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolseparator-icon16.png b/src/quickcontrols2/designer/images/toolseparator-icon16.png
new file mode 100644
index 0000000000..68f22c5df1
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolseparator-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/toolseparator-icon@2x.png b/src/quickcontrols2/designer/images/toolseparator-icon@2x.png
new file mode 100644
index 0000000000..549c11c67c
--- /dev/null
+++ b/src/quickcontrols2/designer/images/toolseparator-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/tumbler-icon.png b/src/quickcontrols2/designer/images/tumbler-icon.png
new file mode 100644
index 0000000000..98eb8232a2
--- /dev/null
+++ b/src/quickcontrols2/designer/images/tumbler-icon.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/tumbler-icon16.png b/src/quickcontrols2/designer/images/tumbler-icon16.png
new file mode 100644
index 0000000000..ff5f95cf32
--- /dev/null
+++ b/src/quickcontrols2/designer/images/tumbler-icon16.png
Binary files differ
diff --git a/src/quickcontrols2/designer/images/tumbler-icon@2x.png b/src/quickcontrols2/designer/images/tumbler-icon@2x.png
new file mode 100644
index 0000000000..236abf0cfe
--- /dev/null
+++ b/src/quickcontrols2/designer/images/tumbler-icon@2x.png
Binary files differ
diff --git a/src/quickcontrols2/designer/qtquickcontrols2.metainfo b/src/quickcontrols2/designer/qtquickcontrols2.metainfo
new file mode 100644
index 0000000000..d27f1b9004
--- /dev/null
+++ b/src/quickcontrols2/designer/qtquickcontrols2.metainfo
@@ -0,0 +1,522 @@
+MetaInfo {
+ Type {
+ name: "QtQuick.Controls.BusyIndicator"
+ icon: "images/busyindicator-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Busy Indicator"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/busyindicator-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Button"
+ icon: "images/button-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/button-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Button\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.CheckBox"
+ icon: "images/checkbox-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Check Box"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/checkbox-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Check Box\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.CheckDelegate"
+ icon: "images/checkbox-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Check Delegate"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/checkbox-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Check Delegate\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ComboBox"
+ icon: "images/combobox-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Combo Box"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/combobox-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.DelayButton"
+ icon: "images/button-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Delay Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/delaybutton-icon.png"
+ version: "2.2"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Delay Button\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Dial"
+ icon: "images/dial-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Dial"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/dial-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Frame"
+ icon: "images/frame-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Frame"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/frame-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.GroupBox"
+ icon: "images/groupbox-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Group Box"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/groupbox-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ Property { name: "title"; type: "binding"; value: "qsTr(\"Group Box\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ItemDelegate"
+ icon: "images/itemdelegate-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Item Delegate"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/itemdelegate-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Item Delegate\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Label"
+ icon: "images/label-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Label"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/label-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Label\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Page"
+ icon: "images/page-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Page"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/page-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.PageIndicator"
+ icon: "images/pageindicator-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Page Indicator"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/pageindicator-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "count"; type: "int"; value: 3 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Pane"
+ icon: "images/pane-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Pane"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/pane-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ProgressBar"
+ icon: "images/progressbar-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Progress Bar"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/progressbar-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "value"; type: "real"; value: 0.5 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.RadioButton"
+ icon: "images/radiobutton-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Radio Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/radiobutton-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Radio Button\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.RadioDelegate"
+ icon: "images/radiobutton-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Radio Delegate"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/radiobutton-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Radio Delegate\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.RangeSlider"
+ icon: "images/rangeslider-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Range Slider"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/rangeslider-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "first.value"; type: "real"; value: 0.25 }
+ Property { name: "second.value"; type: "real"; value: 0.75 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.RoundButton"
+ icon: "images/roundbutton-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Round Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/roundbutton-icon.png"
+ version: "2.1"
+ requiredImport: "QtQuick.Controls"
+ Property { name: "text"; type: "string"; value: "+" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Slider"
+ icon: "images/slider-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Slider"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/slider-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "value"; type: "real"; value: 0.5 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.SpinBox"
+ icon: "images/spinbox-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Spin Box"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/spinbox-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ScrollView"
+ icon: "images/scrollview-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Scroll View"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/scrollview-icon.png"
+ version: "2.2"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.StackView"
+ icon: "images/stackview-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Stack View"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/stackview-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.SwipeDelegate"
+ icon: "images/itemdelegate-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Swipe Delegate"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/itemdelegate-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Swipe Delegate\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.SwipeView"
+ icon: "images/swipeview-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Swipe View"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/swipeview-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 200 }
+ Property { name: "height"; type: "int"; value: 200 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Switch"
+ icon: "images/switch-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Switch"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/switch-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Switch\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.SwitchDelegate"
+ icon: "images/switch-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Switch Delegate"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/switch-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Switch Delegate\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.TabBar"
+ icon: "images/toolbar-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tab Bar"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/toolbar-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ Property { name: "width"; type: "int"; value: 240 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.TabButton"
+ icon: "images/toolbutton-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tab Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/toolbutton-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Tab Button\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.TextArea"
+ icon: "images/textarea-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Text Area"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/textarea-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "placeholderText"; type: "binding"; value: "qsTr(\"Text Area\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.TextField"
+ icon: "images/textfield-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Text Field"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/textfield-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "placeholderText"; type: "binding"; value: "qsTr(\"Text Field\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ToolBar"
+ icon: "images/toolbar-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tool Bar"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/toolbar-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "width"; type: "int"; value: 360 }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ToolButton"
+ icon: "images/toolbutton-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tool Button"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/toolbutton-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "text"; type: "binding"; value: "qsTr(\"Tool Button\")" }
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.ToolSeparator"
+ icon: "images/toolseparator-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tool Separator"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/toolseparator-icon.png"
+ version: "2.1"
+ requiredImport: "QtQuick.Controls"
+ }
+ }
+
+ Type {
+ name: "QtQuick.Controls.Tumbler"
+ icon: "images/tumbler-icon16.png"
+
+ ItemLibraryEntry {
+ name: "Tumbler"
+ category: "Qt Quick - Controls 2"
+ libraryIcon: "images/tumbler-icon.png"
+ version: "2.0"
+ requiredImport: "QtQuick.Controls"
+
+ Property { name: "model"; type: "int"; value: "10" }
+ }
+ }
+}
diff --git a/src/quickcontrols2/doc/doc.pri b/src/quickcontrols2/doc/doc.pri
new file mode 100644
index 0000000000..4bd8bd95df
--- /dev/null
+++ b/src/quickcontrols2/doc/doc.pri
@@ -0,0 +1,6 @@
+QMAKE_DOCS = $$PWD/qtquickcontrols.qdocconf
+
+OTHER_FILES += \
+ $$files($$PWD/snippets/*.qml) \
+ $$files($$PWD/src/*.qdoc) \
+ $$files($$PWD/src/templates/*.qdoc)
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-applicationwindow-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-applicationwindow-wireframe.png
new file mode 100644
index 0000000000..f31378004a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-applicationwindow-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-basic-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-basic-thumbnail.png
new file mode 100644
index 0000000000..e971a7aaec
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-basic-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-basic.png b/src/quickcontrols2/doc/images/qtquickcontrols2-basic.png
new file mode 100644
index 0000000000..099db17038
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-basic.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator-custom.png
new file mode 100644
index 0000000000..fefae223ef
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.gif
new file mode 100644
index 0000000000..653d200f3c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.png b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.png
new file mode 100644
index 0000000000..4be09579bb
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-busyindicator.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-button-custom.png
new file mode 100644
index 0000000000..46d3e3eb5e
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-flat.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-button-flat.gif
new file mode 100644
index 0000000000..e2bd8b6fcf
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-flat.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-highlighted.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-button-highlighted.gif
new file mode 100644
index 0000000000..7de076d3d0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-highlighted.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-icononly.png b/src/quickcontrols2/doc/images/qtquickcontrols2-button-icononly.png
new file mode 100644
index 0000000000..9c8dd0f43f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-icononly.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-textbesideicon.png b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textbesideicon.png
new file mode 100644
index 0000000000..3dc64fb92b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textbesideicon.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-textonly.png b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textonly.png
new file mode 100644
index 0000000000..737beb165f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textonly.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button-textundericon.png b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textundericon.png
new file mode 100644
index 0000000000..37c40c7c66
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button-textundericon.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-button.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-button.gif
new file mode 100644
index 0000000000..10d626a331
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-button.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-custom.png
new file mode 100644
index 0000000000..c6c3d1bcbd
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-group.png b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-group.png
new file mode 100644
index 0000000000..d5a0d51be6
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-group.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-tristate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-tristate.gif
new file mode 100644
index 0000000000..56a1586795
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox-tristate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox.gif
new file mode 100644
index 0000000000..d70c0ee4b9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkbox.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-custom.png
new file mode 100644
index 0000000000..c0dd06892c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-tristate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-tristate.gif
new file mode 100644
index 0000000000..8d058d6c54
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate-tristate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate.gif
new file mode 100644
index 0000000000..da3fab98a4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-checkdelegate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-custom.png
new file mode 100644
index 0000000000..4f7206dc78
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-delegate.png b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-delegate.png
new file mode 100644
index 0000000000..cf31064895
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-delegate.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-popup.png b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-popup.png
new file mode 100644
index 0000000000..cf31064895
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox-popup.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-combobox.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox.gif
new file mode 100644
index 0000000000..966a2d4ae5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-combobox.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-control.png b/src/quickcontrols2/doc/images/qtquickcontrols2-control.png
new file mode 100644
index 0000000000..0f004a89dd
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-control.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-control.svg b/src/quickcontrols2/doc/images/qtquickcontrols2-control.svg
new file mode 100644
index 0000000000..4b2057d197
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-control.svg
@@ -0,0 +1,936 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="760"
+ height="580"
+ viewBox="0 0 759.99997 579.99999"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
+ sodipodi:docname="qtquickcontrols2-control.svg"
+ inkscape:export-filename="/home/jpnurmi/Projects/qt-dev/qtquickcontrols2/src/imports/controls/doc/images/qtquickcontrols2-control.png"
+ inkscape:export-xdpi="192"
+ inkscape:export-ydpi="192">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mstart"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4191"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Mend"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4212"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="scale(-0.6)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-3"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-0"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-5"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9-6-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2-2-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1-1-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2-7-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1-7"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96-7"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4-0"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8-3"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96-3"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4-46"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9-5"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1-9-7"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8-3-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96-3-2"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4-46-3"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9-5-8"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6-6-1"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4-1-3"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8-7-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.4142136"
+ inkscape:cx="138.75529"
+ inkscape:cy="425.28174"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="3840"
+ inkscape:window-height="2031"
+ inkscape:window-x="0"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="px" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(91.482322,-32.9581)">
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.05102265;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4136"
+ width="518.94897"
+ height="298.94897"
+ x="29.043194"
+ y="193.48361" />
+ <rect
+ style="fill:#ffd5d5;fill-opacity:1;stroke:none;stroke-width:0.83021182;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4136-3"
+ width="440"
+ height="220"
+ x="68.517685"
+ y="232.9581" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(1.1690183,0,0,1.1690183,115.80023,-231.31953)"><flowRegion
+ id="flowRegion4140"
+ style="fill:#ff2a2a"><rect
+ id="rect4142"
+ width="129.78784"
+ height="31.668232"
+ x="-34.519978"
+ y="400.22751"
+ style="font-size:15.41801071px;fill:#ff2a2a" /></flowRegion><flowPara
+ id="flowPara4144"
+ style="font-size:20.55734825px;line-height:1.25;fill:#ff2a2a">Background</flowPara><flowPara
+ id="flowPara4146"
+ style="font-size:20.55734825px;line-height:1.25;fill:#ff2a2a"> </flowPara></flowRoot> <rect
+ style="fill:#d7e3f4;fill-opacity:1;stroke:none;stroke-width:22.32431984;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.58381503"
+ id="rect4148"
+ width="360"
+ height="140"
+ x="108.51768"
+ y="272.95813" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,184.57261,41.294224)"><flowRegion
+ id="flowRegion4140-6"
+ style="fill:#0055d4"><rect
+ id="rect4142-6"
+ width="334.36047"
+ height="80.812172"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:40px;fill:#0055d4" /></flowRegion><flowPara
+ id="flowPara4146-6"
+ style="font-size:40px;line-height:1.25;fill:#0055d4">Content item</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-1"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,247.75903,220.21488)"><flowRegion
+ id="flowRegion4140-6-9"><rect
+ id="rect4142-6-0"
+ width="270.72089"
+ height="68.690361"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:25px;fill:#000000" /></flowRegion><flowPara
+ id="flowPara4146-6-2"
+ style="font-size:17.5px;line-height:1.25">Width</flowPara></flowRoot> <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93053311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-3);marker-end:url(#TriangleOutL-0)"
+ d="M 33.168982,505.52033 H 543.32948"
+ id="path4179-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9);marker-end:url(#TriangleOutL-1)"
+ d="M 16.517683,487.33858 V 198.57762"
+ id="path4179-9"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-1-7"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-50.003525,47.195824)"><flowRegion
+ id="flowRegion4140-6-9-7"><rect
+ id="rect4142-6-0-5"
+ width="270.72089"
+ height="68.690361"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ id="flowPara4146-6-2-9"
+ style="font-size:17.5px;line-height:1.25;fill:#000000">Height</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-3"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,206.65956,-144.78636)"><flowRegion
+ id="flowRegion4140-6-67"><rect
+ id="rect4142-6-5"
+ width="334.36047"
+ height="80.812172"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:60px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:60px;line-height:1.25"
+ id="flowPara14323">Popup</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,41.217752,149.93493)"><flowRegion
+ id="flowRegion4140-6-6-4-6"
+ style="text-align:center;text-anchor:middle;fill:#0055d4"><rect
+ id="rect4142-6-1-4-2"
+ width="252.53812"
+ height="61.619293"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;text-align:center;text-anchor:middle;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara10048-9">Bottom</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara5290">padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,384.82399,-69.046412)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-7"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara10048-9-0">Top</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara4830">padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,458.14041,-0.80935844)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-6"
+ width="81.109558"
+ height="93.762154"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#0055d4"
+ id="flowPara4386">Right padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,19.173452,87.133114)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-6-4"
+ width="81.109558"
+ height="93.762154"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#0055d4"
+ id="flowPara4386-0">Left padding</flowPara></flowRoot> <path
+ style="fill:#ff2a2a;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87824047;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9-6);marker-end:url(#TriangleOutL-1-1)"
+ d="M 72.916183,227.96278 V 198.98852"
+ id="path4179-9-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87323481;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5);marker-end:url(#TriangleOutL-9-4)"
+ d="M 34.529058,238.58445 H 63.562954"
+ id="path4179-7-8"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-5"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,47.895402,-88.000508)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-9"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-7-7"
+ width="66.476036"
+ height="55.080368"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara11237">Top inset</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2-3"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,0.4414194,-43.952242)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5-8"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-6-4-8"
+ width="75.759529"
+ height="93.167732"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara4386-0-3">Left inset</flowPara></flowRoot> <path
+ style="fill:#0055d4;fill-rule:evenodd;stroke:#0055d4;stroke-width:0.97500122;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1);marker-end:url(#TriangleOutL-96)"
+ d="M 462.28757,267.38769 V 199.50991"
+ id="path4179-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ff2a2a;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87794411;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9-6-4);marker-end:url(#TriangleOutL-1-1-6)"
+ d="M 504.22784,486.94146 V 457.98675"
+ id="path4179-9-8-9"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-5-0"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,424.36985,170.98794)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-9-6"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-7-7-8"
+ width="91.442841"
+ height="44.974762"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara11237-7">Bottom inset</flowPara></flowRoot> <path
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87314719;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6);marker-end:url(#TriangleOutL-9-4-8)"
+ d="M 513.47562,448.6218 H 542.5037"
+ id="path4179-7-8-6"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2-3-0"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,479.24023,126.32002)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5-8-7"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-6-4-8-0"
+ width="75.759529"
+ height="93.167732"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara3807">Right inset</flowPara></flowRoot> <path
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.05938387;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9);marker-end:url(#TriangleOutL-9-4-8-4)"
+ d="m 474.52523,278.31524 h 66.93934"
+ id="path4179-7-8-6-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#0055d4;fill-rule:evenodd;stroke:#0055d4;stroke-width:0.97513783;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1-7);marker-end:url(#TriangleOutL-96-7)"
+ d="M 114.58911,486.37854 V 418.48175"
+ id="path4179-3-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.05900466;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9-1);marker-end:url(#TriangleOutL-9-4-8-4-0)"
+ d="M 35.582232,406.88667 H 102.47366"
+ id="path4179-7-8-6-0-0"
+ inkscape:connector-curvature="0" />
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.38;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4136-9"
+ width="638.62036"
+ height="418.6203"
+ x="-30.792475"
+ y="133.64795" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-3-8"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,192.12072,-213.92909)"><flowRegion
+ id="flowRegion4140-6-67-1"><rect
+ id="rect4142-6-5-6"
+ width="334.36047"
+ height="80.812172"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:60px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:60px;line-height:1.25"
+ id="flowPara14323-3">Window</flowPara></flowRoot> <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.83036995;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1-9);marker-end:url(#TriangleOutL-96-3)"
+ d="M 16.507747,188.209 V 138.97553"
+ id="path4179-3-1"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.90094262;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9-5);marker-end:url(#TriangleOutL-9-4-8-4-1)"
+ d="m 553.67227,505.52244 h 48.41379"
+ id="path4179-7-8-6-0-2"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-2"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-53.285062,-138.90295)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-92"
+ style="fill:#000000"><rect
+ id="rect4142-6-1-4-2-7-8"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara10048-9-0-1">Top</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara4830-2">margin</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-2-4"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,530.78767,225.71855)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-92-7"
+ style="fill:#000000"><rect
+ id="rect4142-6-1-4-2-7-8-8"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara10048-9-0-1-6">Right</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara4830-2-3">margin</flowPara></flowRoot> <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.83036995;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1-9-7);marker-end:url(#TriangleOutL-96-3-2)"
+ d="M 16.459117,546.78218 V 497.54871"
+ id="path4179-3-1-7"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-2-2"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-0.06072146,225.50386)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-92-5"
+ style="fill:#000000"><rect
+ id="rect4142-6-1-4-2-7-8-3"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara10048-9-0-1-7">Bottom</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara4830-2-6">margin</flowPara></flowRoot> <path
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.89733517;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9-5-8);marker-end:url(#TriangleOutL-9-4-8-4-1-3)"
+ d="M -25.075855,505.54405 H 22.951007"
+ id="path4179-7-8-6-0-2-4"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-2-2-0"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-55.529842,180.17847)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-92-5-3"
+ style="fill:#000000"><rect
+ id="rect4142-6-1-4-2-7-8-3-5"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara10048-9-0-1-7-8">Left</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#000000"
+ id="flowPara4830-2-6-5">margin</flowPara></flowRoot> </g>
+</svg>
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-customize-buttons.png b/src/quickcontrols2/doc/images/qtquickcontrols2-customize-buttons.png
new file mode 100644
index 0000000000..551e8a0cf7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-customize-buttons.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton-custom.png
new file mode 100644
index 0000000000..a7bd7c19d8
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton.gif
new file mode 100644
index 0000000000..16a198f9cb
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-delaybutton.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-custom.png
new file mode 100644
index 0000000000..6312c99933
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-handle.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-handle.png
new file mode 100644
index 0000000000..9e22b2e709
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-handle.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputMode.svgz b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputMode.svgz
new file mode 100644
index 0000000000..005ab7b331
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputMode.svgz
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputmode.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputmode.png
new file mode 100644
index 0000000000..5bbc41a49c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-inputmode.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-no-wrap.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-no-wrap.gif
new file mode 100644
index 0000000000..24f6790b6d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-no-wrap.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial-wrap.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-wrap.gif
new file mode 100644
index 0000000000..cfb1fb5b10
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial-wrap.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dial.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dial.png
new file mode 100644
index 0000000000..71c54113b7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dial.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox-attached.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox-attached.png
new file mode 100644
index 0000000000..c17f38ac0c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox-attached.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox.png b/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox.png
new file mode 100644
index 0000000000..33b5f45f4f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-dialogbuttonbox.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-expanded-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-expanded-wireframe.png
new file mode 100644
index 0000000000..0c92f86587
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-expanded-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-wireframe.png
new file mode 100644
index 0000000000..74806f17b7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-drawer.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer.gif
new file mode 100644
index 0000000000..736f34f66f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-drawer.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-frame-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-frame-custom.png
new file mode 100644
index 0000000000..f628b20c20
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-frame-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-frame.png b/src/quickcontrols2/doc/images/qtquickcontrols2-frame.png
new file mode 100644
index 0000000000..e3cb31dc71
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-frame.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-palettes.png b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-palettes.png
new file mode 100644
index 0000000000..d806116167
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-palettes.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-thumbnail.png
new file mode 100644
index 0000000000..c270c6efba
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-violet.png b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-violet.png
new file mode 100644
index 0000000000..99e5b59786
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion-violet.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-fusion.png b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion.png
new file mode 100644
index 0000000000..7119ef225d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-fusion.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-checkable.png b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-checkable.png
new file mode 100644
index 0000000000..820ad79c80
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-checkable.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-custom.png
new file mode 100644
index 0000000000..029679ced0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-label.png b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-label.png
new file mode 100644
index 0000000000..c26795a7a7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox-label.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox.png b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox.png
new file mode 100644
index 0000000000..ea2f9ea5c5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-groupbox.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-4x.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-4x.png
new file mode 100644
index 0000000000..bab99a5e55
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-4x.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset-boundaries.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset-boundaries.png
new file mode 100644
index 0000000000..c42df81edc
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset-boundaries.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset.png
new file mode 100644
index 0000000000..0627d08590
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-inset.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-padding.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-padding.png
new file mode 100644
index 0000000000..0a606c9926
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-padding.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-stretchable.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-stretchable.png
new file mode 100644
index 0000000000..9598b13a1c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-resized-stretchable.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-size.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-size.png
new file mode 100644
index 0000000000..db6453758f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch-size.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch.svgz b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch.svgz
new file mode 100644
index 0000000000..5a1a1094d1
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-9-patch.svgz
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization-dark.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization-dark.png
new file mode 100644
index 0000000000..144ac97c87
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization-dark.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization.svgz b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization.svgz
new file mode 100644
index 0000000000..fb8305638b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-customization.svgz
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-thumbnail.png
new file mode 100644
index 0000000000..ecf2bb163d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-imagine.png b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine.png
new file mode 100644
index 0000000000..ffe2c267b2
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-imagine.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate-custom.png
new file mode 100644
index 0000000000..35f8892f16
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.gif
new file mode 100644
index 0000000000..dccb6efcdb
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.png b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.png
new file mode 100644
index 0000000000..7242f343a0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-itemdelegate.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-label-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-label-custom.png
new file mode 100644
index 0000000000..5730ff23bf
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-label-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-label.png b/src/quickcontrols2/doc/images/qtquickcontrols2-label.png
new file mode 100644
index 0000000000..0bafcf8602
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-label.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-macos-dark.png b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-dark.png
new file mode 100644
index 0000000000..97d8a5a4e7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-dark.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-macos-light.png b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-light.png
new file mode 100644
index 0000000000..4a598ad498
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-light.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-macos-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-thumbnail.png
new file mode 100644
index 0000000000..57fd98d63a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-macos-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-accent.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-accent.png
new file mode 100644
index 0000000000..a85afc68ed
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-accent.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-attributes.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-attributes.png
new file mode 100644
index 0000000000..bb54071d79
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-attributes.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-background.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-background.png
new file mode 100644
index 0000000000..62028f523c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-background.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-dark.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-dark.png
new file mode 100644
index 0000000000..f6e45b3b1c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-dark.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-elevation.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-elevation.png
new file mode 100644
index 0000000000..d152f14529
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-elevation.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-foreground.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-foreground.png
new file mode 100644
index 0000000000..0d0e1b651a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-foreground.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-light.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-light.png
new file mode 100644
index 0000000000..c9abe2cb8b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-light.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-purple.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-purple.png
new file mode 100644
index 0000000000..b955736b0b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-purple.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-theme.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-theme.png
new file mode 100644
index 0000000000..1d09a82580
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-theme.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-thumbnail.png
new file mode 100644
index 0000000000..d758ff1803
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-dense.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-dense.png
new file mode 100644
index 0000000000..02f39b7885
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-dense.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-normal.png b/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-normal.png
new file mode 100644
index 0000000000..c1e366c531
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-material-variant-normal.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menu-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menu-custom.png
new file mode 100644
index 0000000000..922bf591b5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menu-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menu.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-menu.gif
new file mode 100644
index 0000000000..93a873a33a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menu.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menu.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menu.png
new file mode 100644
index 0000000000..926c33eed2
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menu.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menubar-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menubar-custom.png
new file mode 100644
index 0000000000..b6007e466d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menubar-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menubar.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menubar.png
new file mode 100644
index 0000000000..873b7a1960
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menubar.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator-custom.png
new file mode 100644
index 0000000000..78635b9c88
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator.png b/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator.png
new file mode 100644
index 0000000000..35307817f6
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-menuseparator.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-page-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-page-wireframe.png
new file mode 100644
index 0000000000..f612c243c4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-page-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-custom.png
new file mode 100644
index 0000000000..a767a51aa0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-delegate.png b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-delegate.png
new file mode 100644
index 0000000000..95acde70cf
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator-delegate.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator.png b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator.png
new file mode 100644
index 0000000000..e2a0a157f6
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-pageindicator.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-pane-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-pane-custom.png
new file mode 100644
index 0000000000..03a0369f56
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-pane-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-pane.png b/src/quickcontrols2/doc/images/qtquickcontrols2-pane.png
new file mode 100644
index 0000000000..3801cc3efb
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-pane.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-popup-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-custom.png
new file mode 100644
index 0000000000..cb7813d387
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-popup-settings.png b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-settings.png
new file mode 100644
index 0000000000..5122158ef4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-settings.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-popup-transformorigin.png b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-transformorigin.png
new file mode 100644
index 0000000000..16d2617786
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-popup-transformorigin.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-popup.png b/src/quickcontrols2/doc/images/qtquickcontrols2-popup.png
new file mode 100644
index 0000000000..8fc424a854
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-popup.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-popup.svg b/src/quickcontrols2/doc/images/qtquickcontrols2-popup.svg
new file mode 100644
index 0000000000..e39f3dce21
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-popup.svg
@@ -0,0 +1,712 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="640"
+ height="420"
+ viewBox="0 0 639.99997 419.99999"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.92.3 (2405546, 2018-03-11)"
+ sodipodi:docname="qtquickcontrols2-control.svg"
+ inkscape:export-filename="/home/jpnurmi/Projects/qt-dev/qtquickcontrols2/src/imports/controls/doc/images/qtquickcontrols2-control.png"
+ inkscape:export-xdpi="192"
+ inkscape:export-ydpi="192">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Mstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Mstart"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4191"
+ d="M 0,0 5,-5 -12.5,0 5,5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="matrix(0.4,0,0,0.4,4,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Mend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Mend"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4212"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="scale(-0.6)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-3"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-0"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-5"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-9-6-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-2-2-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-1-1-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-2-7-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-1-7"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4318-8-9"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-96-7"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ id="path4327-4-4"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleInL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleInL-2-5-6-9-1"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4318-4-7-2-6-7"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(-0.8)" />
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="TriangleOutL-9-4-8-4-0"
+ style="overflow:visible"
+ inkscape:isstock="true">
+ <path
+ inkscape:connector-curvature="0"
+ id="path4327-1-1-9-8-6"
+ d="M 5.77,0 -2.88,5 V -5 Z"
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.00000003pt;stroke-opacity:1"
+ transform="scale(0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.8284271"
+ inkscape:cx="328.65009"
+ inkscape:cy="205.42326"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="3840"
+ inkscape:window-height="2031"
+ inkscape:window-x="0"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ units="px" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(91.482322,-192.9581)">
+ <rect
+ style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1.05102265;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4136"
+ width="518.94897"
+ height="298.94897"
+ x="-30.956812"
+ y="253.48361" />
+ <rect
+ style="fill:#ffd5d5;fill-opacity:1;stroke:none;stroke-width:0.83021182;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect4136-3"
+ width="440"
+ height="220"
+ x="8.5176783"
+ y="292.9581" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(1.1690183,0,0,1.1690183,55.80022,-171.31953)"><flowRegion
+ id="flowRegion4140"
+ style="fill:#ff2a2a"><rect
+ id="rect4142"
+ width="129.78784"
+ height="31.668232"
+ x="-34.519978"
+ y="400.22751"
+ style="font-size:15.41801071px;fill:#ff2a2a" /></flowRegion><flowPara
+ id="flowPara4144"
+ style="font-size:20.55734825px;line-height:1.25;fill:#ff2a2a">Background</flowPara><flowPara
+ id="flowPara4146"
+ style="font-size:20.55734825px;line-height:1.25;fill:#ff2a2a"> </flowPara></flowRoot> <rect
+ style="fill:#d7e3f4;fill-opacity:1;stroke:none;stroke-width:22.32431984;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.58381503"
+ id="rect4148"
+ width="360"
+ height="140"
+ x="48.517677"
+ y="332.95813" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,124.5726,101.29422)"><flowRegion
+ id="flowRegion4140-6"
+ style="fill:#0055d4"><rect
+ id="rect4142-6"
+ width="334.36047"
+ height="80.812172"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:40px;fill:#0055d4" /></flowRegion><flowPara
+ id="flowPara4146-6"
+ style="font-size:40px;line-height:1.25;fill:#0055d4">Content item</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-1"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,187.75902,280.21488)"><flowRegion
+ id="flowRegion4140-6-9"><rect
+ id="rect4142-6-0"
+ width="270.72089"
+ height="68.690361"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:25px;fill:#000000" /></flowRegion><flowPara
+ id="flowPara4146-6-2"
+ style="font-size:17.5px;line-height:1.25">Width</flowPara></flowRoot> <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.93053311;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-3);marker-end:url(#TriangleOutL-0)"
+ d="M -26.831023,563.52033 H 483.32947"
+ id="path4179-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9);marker-end:url(#TriangleOutL-1)"
+ d="M -41.482322,547.33858 V 258.57762"
+ id="path4179-9"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-1-7"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-110.00353,107.19582)"><flowRegion
+ id="flowRegion4140-6-9-7"><rect
+ id="rect4142-6-0-5"
+ width="270.72089"
+ height="68.690361"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#000000" /></flowRegion><flowPara
+ id="flowPara4146-6-2-9"
+ style="font-size:17.5px;line-height:1.25;fill:#000000">Height</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-3"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,138.50125,-84.786365)"><flowRegion
+ id="flowRegion4140-6-67"><rect
+ id="rect4142-6-5"
+ width="334.36047"
+ height="80.812172"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:60px;fill:#000000" /></flowRegion><flowPara
+ id="flowPara4146-6-3"
+ style="font-size:60px;line-height:1.25">Control</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-18.782253,209.93493)"><flowRegion
+ id="flowRegion4140-6-6-4-6"
+ style="text-align:center;text-anchor:middle;fill:#0055d4"><rect
+ id="rect4142-6-1-4-2"
+ width="252.53812"
+ height="61.619293"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;text-align:center;text-anchor:middle;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara10048-9">Bottom</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara5290">padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,324.82398,-9.0464154)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-7"
+ width="71.826065"
+ height="43.785866"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara10048-9-0">Top</flowPara><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#0055d4"
+ id="flowPara4830">padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,398.1404,59.190638)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-6"
+ width="81.109558"
+ height="93.762154"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#0055d4"
+ id="flowPara4386">Right padding</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#0055d4;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-40.826553,147.13311)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5"
+ style="fill:#0055d4"><rect
+ id="rect4142-6-1-4-2-6-4"
+ width="81.109558"
+ height="93.762154"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#0055d4" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#0055d4"
+ id="flowPara4386-0">Left padding</flowPara></flowRoot> <path
+ style="fill:#ff2a2a;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87824047;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9-6);marker-end:url(#TriangleOutL-1-1)"
+ d="M 12.916178,287.96278 V 258.98852"
+ id="path4179-9-8"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87323481;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5);marker-end:url(#TriangleOutL-9-4)"
+ d="M -25.470947,298.58445 H 3.5629489"
+ id="path4179-7-8"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-5"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-12.104603,-28.000512)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-9"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-7-7"
+ width="66.476036"
+ height="55.080368"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara11237">Top inset</flowPara></flowRoot> <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2-3"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,-59.558586,16.047754)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5-8"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-6-4-8"
+ width="75.759529"
+ height="93.167732"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara4386-0-3">Left inset</flowPara></flowRoot> <path
+ style="fill:#0055d4;fill-rule:evenodd;stroke:#0055d4;stroke-width:0.97500122;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1);marker-end:url(#TriangleOutL-96)"
+ d="M 402.28756,327.38769 V 259.50991"
+ id="path4179-3"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ff2a2a;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87794411;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-9-6-4);marker-end:url(#TriangleOutL-1-1-6)"
+ d="M 444.22783,546.94146 V 517.98675"
+ id="path4179-9-8-9"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-1-5-0"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,364.36984,230.98794)"><flowRegion
+ id="flowRegion4140-6-6-4-6-2-9-6"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-7-7-8"
+ width="91.442841"
+ height="44.974762"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.5px;line-height:1.25;text-align:center;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara11237-7">Bottom inset</flowPara></flowRoot> <path
+ style="fill:#ff2a2a;fill-opacity:1;fill-rule:evenodd;stroke:#ff2a2a;stroke-width:0.87314719;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6);marker-end:url(#TriangleOutL-9-4-8)"
+ d="m 453.47561,508.6218 h 29.02808"
+ id="path4179-7-8-6"
+ inkscape:connector-curvature="0" />
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4138-6-2-7-5-9-2-3-0"
+ style="font-style:normal;font-weight:normal;line-height:0.01%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#ff2a2a;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.6007979,0,0,0.6007979,419.24022,186.32002)"><flowRegion
+ id="flowRegion4140-6-6-4-6-3-5-8-7"
+ style="fill:#ff2a2a"><rect
+ id="rect4142-6-1-4-2-6-4-8-0"
+ width="75.759529"
+ height="93.167732"
+ x="42.426407"
+ y="481.62601"
+ style="font-size:17.5px;fill:#ff2a2a" /></flowRegion><flowPara
+ style="font-size:17.02554321px;line-height:125%;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#ff2a2a"
+ id="flowPara3807">Right inset</flowPara></flowRoot> <path
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.05938387;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9);marker-end:url(#TriangleOutL-9-4-8-4)"
+ d="m 414.52522,338.31524 h 66.93934"
+ id="path4179-7-8-6-0"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#0055d4;fill-rule:evenodd;stroke:#0055d4;stroke-width:0.97513783;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-1-7);marker-end:url(#TriangleOutL-96-7)"
+ d="M 54.589106,546.37854 V 478.48175"
+ id="path4179-3-9"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#0055d4;fill-opacity:1;fill-rule:evenodd;stroke:#0055d4;stroke-width:1.05900466;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#TriangleInL-2-5-6-9-1);marker-end:url(#TriangleOutL-9-4-8-4-0)"
+ d="M -24.417773,466.88667 H 42.473651"
+ id="path4179-7-8-6-0-0"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-custom.png
new file mode 100644
index 0000000000..9d73df2c25
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-indeterminate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-indeterminate.gif
new file mode 100644
index 0000000000..d6756d16fd
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar-indeterminate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar.gif
new file mode 100644
index 0000000000..49af5f45a1
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-progressbar.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton-custom.png
new file mode 100644
index 0000000000..5c85179f70
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton.gif
new file mode 100644
index 0000000000..4cbf3ed9d6
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-radiobutton.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate-custom.png
new file mode 100644
index 0000000000..7d32699bf9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate.gif
new file mode 100644
index 0000000000..b6afd6fe6a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-radiodelegate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider-custom.png
new file mode 100644
index 0000000000..47379a300d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider.gif
new file mode 100644
index 0000000000..db565b0a93
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-rangeslider.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-roundbutton.png b/src/quickcontrols2/doc/images/qtquickcontrols2-roundbutton.png
new file mode 100644
index 0000000000..4dce37f239
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-roundbutton.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-custom.png
new file mode 100644
index 0000000000..690bc8beef
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-non-attached.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-non-attached.png
new file mode 100644
index 0000000000..eba363dda2
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-non-attached.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-nosnap.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-nosnap.gif
new file mode 100644
index 0000000000..f61ac5b46a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-nosnap.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snapalways.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snapalways.gif
new file mode 100644
index 0000000000..438d4a3318
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snapalways.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snaponrelease.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snaponrelease.gif
new file mode 100644
index 0000000000..c2fa67b027
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar-snaponrelease.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar.gif
new file mode 100644
index 0000000000..ed3ab607d9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollbar.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-custom.png
new file mode 100644
index 0000000000..b1183bc52a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-non-attached.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-non-attached.png
new file mode 100644
index 0000000000..a61e048743
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator-non-attached.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator.gif
new file mode 100644
index 0000000000..73007820f8
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollindicator.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-custom.png
new file mode 100644
index 0000000000..8f4bd92863
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-wireframe.png
new file mode 100644
index 0000000000..8a39056aa9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview.png b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview.png
new file mode 100644
index 0000000000..1a4039e1fd
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-scrollview.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-selectionrectangle.png b/src/quickcontrols2/doc/images/qtquickcontrols2-selectionrectangle.png
new file mode 100644
index 0000000000..69e47b2909
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-selectionrectangle.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-custom.png
new file mode 100644
index 0000000000..dbbacb343f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider-handle.png b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-handle.png
new file mode 100644
index 0000000000..5450d57480
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-handle.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider-nosnap.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-nosnap.gif
new file mode 100644
index 0000000000..ab233c5b93
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-nosnap.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snapalways.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snapalways.gif
new file mode 100644
index 0000000000..8eb4011fb5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snapalways.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snaponrelease.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snaponrelease.gif
new file mode 100644
index 0000000000..f3b1d5c7a9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider-snaponrelease.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-slider.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-slider.gif
new file mode 100644
index 0000000000..2ee56334e0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-slider.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-custom.png
new file mode 100644
index 0000000000..d1e883fc56
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-double.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-double.png
new file mode 100644
index 0000000000..d3f5876c4a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-double.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-down.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-down.png
new file mode 100644
index 0000000000..1d5dcf7b44
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-down.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-textual.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-textual.png
new file mode 100644
index 0000000000..5513d6e67d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-textual.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-up.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-up.png
new file mode 100644
index 0000000000..1ee1c4798e
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox-up.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox.png b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox.png
new file mode 100644
index 0000000000..835bb1d67d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-spinbox.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-splitview-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-splitview-custom.png
new file mode 100644
index 0000000000..da820ccafe
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-splitview-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-custom.png
new file mode 100644
index 0000000000..5ee6049e74
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-pop.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-pop.gif
new file mode 100644
index 0000000000..1971c2e004
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-pop.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-push.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-push.gif
new file mode 100644
index 0000000000..0218cc0f2f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-push.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-replace.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-replace.gif
new file mode 100644
index 0000000000..63a6b2b4b5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-replace.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-unwind.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-unwind.gif
new file mode 100644
index 0000000000..28c051d866
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-unwind.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-visible.png b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-visible.png
new file mode 100644
index 0000000000..d937b417e6
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-visible.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-wireframe.png
new file mode 100644
index 0000000000..f28b5c67de
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-stackview-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-styles.png b/src/quickcontrols2/doc/images/qtquickcontrols2-styles.png
new file mode 100644
index 0000000000..992dd47eba
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-styles.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-behind.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-behind.gif
new file mode 100644
index 0000000000..97d6a59277
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-behind.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-custom.png
new file mode 100644
index 0000000000..5813b73cf4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-leading-trailing.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-leading-trailing.gif
new file mode 100644
index 0000000000..0641bd1400
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate-leading-trailing.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate.gif
new file mode 100644
index 0000000000..86c380b7b3
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipedelegate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-indicator.png b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-indicator.png
new file mode 100644
index 0000000000..998ec9f7c9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-wireframe.png
new file mode 100644
index 0000000000..3cc2b83c4b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview.gif
new file mode 100644
index 0000000000..4af26c1058
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-swipeview.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switch-checked.png b/src/quickcontrols2/doc/images/qtquickcontrols2-switch-checked.png
new file mode 100644
index 0000000000..7a0cde1bad
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switch-checked.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switch-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-switch-custom.png
new file mode 100644
index 0000000000..6d535ef96f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switch-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switch.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-switch.gif
new file mode 100644
index 0000000000..5f956304a0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switch.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switch.png b/src/quickcontrols2/doc/images/qtquickcontrols2-switch.png
new file mode 100644
index 0000000000..7f613f3343
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switch.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate-custom.png
new file mode 100644
index 0000000000..f5337e2c83
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate.gif
new file mode 100644
index 0000000000..950b10731f
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-switchdelegate.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-custom.png
new file mode 100644
index 0000000000..8c8e4accd8
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-explicit.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-explicit.png
new file mode 100644
index 0000000000..b1de5f715e
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-explicit.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-flickable.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-flickable.png
new file mode 100644
index 0000000000..0c253f82d5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-flickable.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-wireframe.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-wireframe.png
new file mode 100644
index 0000000000..35a64ae285
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar-wireframe.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.gif
new file mode 100644
index 0000000000..31db1f9e7c
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.png
new file mode 100644
index 0000000000..9f113497db
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbar.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tabbutton.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbutton.png
new file mode 100644
index 0000000000..3df2f53147
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tabbutton.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-custom.png
new file mode 100644
index 0000000000..6220a13f39
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-scrollable.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-scrollable.png
new file mode 100644
index 0000000000..ae868a27da
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea-scrollable.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textarea.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea.png
new file mode 100644
index 0000000000..fc221bd757
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textarea.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-custom.png
new file mode 100644
index 0000000000..9102317065
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-disabled.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-disabled.png
new file mode 100644
index 0000000000..b143d21053
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-focused.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-focused.png
new file mode 100644
index 0000000000..de7f9599c9
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-focused.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-normal.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-normal.png
new file mode 100644
index 0000000000..4229c706ad
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield-normal.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-textfield.png b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield.png
new file mode 100644
index 0000000000..a008383a00
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-textfield.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar-custom.png
new file mode 100644
index 0000000000..425e5f8c64
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar.png
new file mode 100644
index 0000000000..e5a33eee9a
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbar.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton-custom.png
new file mode 100644
index 0000000000..b78269d087
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton.png
new file mode 100644
index 0000000000..610c1a7cb4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolbutton.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator-custom.png
new file mode 100644
index 0000000000..6703eeba53
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator.png b/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator.png
new file mode 100644
index 0000000000..88ced12361
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-toolseparator.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-delay.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-delay.png
new file mode 100644
index 0000000000..59813835b4
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-delay.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-hover.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-hover.png
new file mode 100644
index 0000000000..62a9cf844b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-hover.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-pressandhold.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-pressandhold.png
new file mode 100644
index 0000000000..62a9cf844b
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-pressandhold.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-slider.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-slider.png
new file mode 100644
index 0000000000..a15e723a02
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip-slider.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip.png
new file mode 100644
index 0000000000..4238d52a77
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tooltip.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-custom.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-custom.png
new file mode 100644
index 0000000000..bbfa9b0cef
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-custom.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-delegate.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-delegate.png
new file mode 100644
index 0000000000..a28da93e46
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-delegate.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-wrap.gif b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-wrap.gif
new file mode 100644
index 0000000000..8f59eedcc7
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler-wrap.gif
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler.png b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler.png
new file mode 100644
index 0000000000..38339dfa25
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-tumbler.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-accent.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-accent.png
new file mode 100644
index 0000000000..e1d74f7a91
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-accent.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-attributes.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-attributes.png
new file mode 100644
index 0000000000..7a7ef347fc
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-attributes.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-background.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-background.png
new file mode 100644
index 0000000000..4f1bfbd284
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-background.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-button.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-button.png
new file mode 100644
index 0000000000..6c764ec97e
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-button.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-dark.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-dark.png
new file mode 100644
index 0000000000..952651dca0
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-dark.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-foreground.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-foreground.png
new file mode 100644
index 0000000000..b0ecf23a9e
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-foreground.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-light.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-light.png
new file mode 100644
index 0000000000..e65447a4c5
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-light.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-theme.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-theme.png
new file mode 100644
index 0000000000..d128134636
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-theme.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-thumbnail.png
new file mode 100644
index 0000000000..db7fe5b076
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-universal-violet.png b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-violet.png
new file mode 100644
index 0000000000..ec459457a8
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-universal-violet.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-windows-thumbnail.png b/src/quickcontrols2/doc/images/qtquickcontrols2-windows-thumbnail.png
new file mode 100644
index 0000000000..15408d3bba
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-windows-thumbnail.png
Binary files differ
diff --git a/src/quickcontrols2/doc/images/qtquickcontrols2-windows.png b/src/quickcontrols2/doc/images/qtquickcontrols2-windows.png
new file mode 100644
index 0000000000..324a03412d
--- /dev/null
+++ b/src/quickcontrols2/doc/images/qtquickcontrols2-windows.png
Binary files differ
diff --git a/src/quickcontrols2/doc/manifest-meta.qdocconf b/src/quickcontrols2/doc/manifest-meta.qdocconf
new file mode 100644
index 0000000000..5626aca067
--- /dev/null
+++ b/src/quickcontrols2/doc/manifest-meta.qdocconf
@@ -0,0 +1,32 @@
+# Additional meta information (attributes for matched entries, as well as tags)
+# to be added to manifest.xml files.
+#
+# manifestmeta.filters = <filter1>,<filter2>,...
+#
+# manifestmeta.<filter>.names = <Module1>/<name1>,<Module2>/<name2>,..
+# manifestmeta.<filter>.attributes = <attribute1:value1>,<attribute2:value2>,..
+# manifestmeta.<filter>.tags = <tag1>,<tag2>,..
+#
+# <filter>.names specify all the module/name combinations to apply the
+# attributes/tags to. You can use simple wildcard matching by appending
+# '*' at the end of name.
+#
+# Note: You cannot use operators (+, =, -) in the names.
+#
+# Examples: add a 'isHighlighted' attribute for two 'Analog Clock' examples,
+# add a 'database' tag for QtSql examples, and a 'qt5' tag for all examples
+#
+# manifestmeta.filters = highlighted sql global
+#
+# manifestmeta.highlighted.names = "QtGui/Analog Clock Window Example" \
+# "QtWidgets/Analog Clock Example"
+# manifestmeta.highlighted.attributes = isHighlighted:true
+#
+# manifestmeta.sql.names = "QtSql/*"
+# manifestmeta.sql.tags = database
+#
+# manifestmeta.global.names = *
+# manifestmeta.global.tags = qt5
+
+manifestmeta.highlighted.names = "QtQuickControls/Qt Quick Controls - Gallery" \
+ "QtQuickControls/Qt Quick Controls - Text Editor"
diff --git a/src/quickcontrols2/doc/qtquickcontrols.qdocconf b/src/quickcontrols2/doc/qtquickcontrols.qdocconf
new file mode 100644
index 0000000000..3078730cbb
--- /dev/null
+++ b/src/quickcontrols2/doc/qtquickcontrols.qdocconf
@@ -0,0 +1,104 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtquickcontrols2.qdocconf)
+include(manifest-meta.qdocconf)
+
+moduleheader = QtQuickControls2
+
+project = QtQuickControls
+description = Qt Quick Controls Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtQuickControls
+
+qhp.QtQuickControls.file = qtquickcontrols.qhp
+qhp.QtQuickControls.namespace = org.qt-project.qtquickcontrols.$QT_VERSION_TAG
+qhp.QtQuickControls.virtualFolder = qtquickcontrols
+qhp.QtQuickControls.indexTitle = Qt Quick Controls
+qhp.QtQuickControls.indexRoot =
+
+qhp.QtQuickControls.filterAttributes = qtquickcontrols $QT_VERSION qtrefdoc
+qhp.QtQuickControls.customFilters.Qt.name = QtQuickControls $QT_VERSION
+qhp.QtQuickControls.customFilters.Qt.filterAttributes = qtquickcontrols $QT_VERSION
+
+qhp.QtQuickControls.subprojects = qmltypes classes examples
+qhp.QtQuickControls.subprojects.qmltypes.title = QML Types
+qhp.QtQuickControls.subprojects.qmltypes.indexTitle = Qt Quick Controls QML Types
+qhp.QtQuickControls.subprojects.qmltypes.selectors = qmlclass
+qhp.QtQuickControls.subprojects.qmltypes.sortPages = true
+qhp.QtQuickControls.subprojects.classes.title = C++ Classes
+qhp.QtQuickControls.subprojects.classes.indexTitle = Qt Quick Controls C++ Classes
+qhp.QtQuickControls.subprojects.classes.selectors = class fake:headerfile
+qhp.QtQuickControls.subprojects.classes.sortPages = true
+qhp.QtQuickControls.subprojects.examples.title = Examples
+qhp.QtQuickControls.subprojects.examples.indexTitle = Qt Quick Controls Examples
+qhp.QtQuickControls.subprojects.examples.selectors = fake:example
+
+depends = qtcore qtgui qtdoc qtqml qtqmlmodels qtquick qtsql qtwidgets qtlabsplatform qmake qtcmake
+
+# Specify the install path under QT_INSTALL_EXAMPLES
+# Note: paths passed to \example command must contain the parent directory, e.g.
+# \example controls/tabs
+exampledirs += ../../../examples/quickcontrols2 \
+ ../../quicktemplates2 \
+ snippets
+
+examples.fileextensions += "*.conf"
+
+examplesinstallpath = quickcontrols2
+
+headerdirs += ../../quicktemplates2 \
+ ..
+
+sourcedirs += ../../quicktemplates2 \
+ .. \
+ ../../quicktemplates2/doc/src \
+ src
+
+# Exclude .qml files from the doc build to prevent conflicts with .qml files
+# in style-specific directories; all types are documented in .cpp/.qdoc files
+sources.fileextensions = "*.c++ *.cc *.cpp *.cxx *.mm *.qdoc"
+
+imagedirs += images \
+ ..
+
+navigation.landingpage = "Qt Quick Controls"
+navigation.qmltypespage = "Qt Quick Controls QML Types"
+navigation.cppclassespage = "Qt Quick Controls C++ Classes"
+
+tagfile = qtquickcontrols.tags
+
+# \styleimport {QtQuick.Controls.Universal 2.0}
+macro.styleimport.HTML = "<table class=\"alignedsummary\"><tbody><tr><td class=\"memItemLeft rightAlign topAlign\"> Import Statement:</td><td class=\"memItemRight bottomAlign\"> import \1</td></tr><tr><td class=\"memItemLeft rightAlign topAlign\"> Since:</td><td class=\"memItemRight bottomAlign\"> \2</td></tr></tbody></table>"
+
+# \styleproperty {Universal.accent} {enumeration} {html-target-id}
+# \target html-target-id
+# This property holds ...
+# (empty line)
+# \endstyleproperty
+macro.styleproperty.HTML = "<div class=\"qmlproto\"><table class=\"qmlname\"><tbody><tr valign=\"top\" class=\"odd\" id=\"\3\"><td class=\"tblQmlPropNode\"><p><span class=\"name\">\1</span> : <span class=\"type\">\2</span></p></td></tr></tbody></table></div>"
+macro.endstyleproperty = "\\br"
+
+# \stylemethod {returntype} {methodname} {argtype} {argname} {html-target-id}
+# \target html-target-id
+# This property holds ...
+# (empty line)
+# \endstylemethod
+macro.stylemethod.HTML = "<div class=\"qmlproto\"><table class=\"qmlname\"><tbody><tr valign=\"top\" class=\"odd\" id=\"\5\"><td class=\"tblQmlFuncNode\"><p><span class=\"type\">\1</span> <span class=\"name\">\2</span>(<span class="type">\3</span> <i>\4</i>)</p></td></tr></tbody></table></div>"
+macro.endstylemethod = "\\br"
+
+# \stylemethod2 {returntype} {methodname} {arg1type} {arg1name} {arg2type} {arg2name} {html-target-id}
+# \target html-target-id
+# This method returns ...
+# (empty line)
+# \endstylemethod2
+macro.stylemethod2.HTML = "<div class=\"qmlproto\"><table class=\"qmlname\"><tbody><tr valign=\"top\" class=\"odd\" id=\"\7\"><td class=\"tblQmlFuncNode\"><p><span class=\"type\">\1</span> <span class=\"name\">\2</span>(<span class="type">\3</span> <i>\4</i>, <span class="type">\5</span> <i>\6</i>)</p></td></tr></tbody></table></div>"
+macro.endstylemethod2 = "\\br"
+
+# \stylecolor {#6A00FF} {(default)}
+macro.stylecolor.HTML = "<div style=\"padding:10px;color:#fff;background:\1;\">\1 \2</div>"
+
+macro.nbsp.HTML = "&nbsp;"
+
+#Add output suffix to the html filenames
+outputsuffixes = QML
+outputsuffixes.QML = 2
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-action.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-action.qml
new file mode 100644
index 0000000000..1b65a824b0
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-action.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ //! [action]
+ Action {
+ id: copyAction
+ text: qsTr("&Copy")
+ icon.name: "edit-copy"
+ shortcut: StandardKey.Copy
+ onTriggered: window.activeFocusItem.copy()
+ }
+ //! [action]
+
+ //! [toolbutton]
+ ToolButton {
+ id: toolButton
+ action: copyAction
+ }
+ //! [toolbutton]
+
+ //! [menuitem]
+ MenuItem {
+ id: menuItem
+ action: copyAction
+ text: qsTr("&Copy selected Text")
+ }
+ //! [menuitem]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-busyindicator-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-busyindicator-custom.qml
new file mode 100644
index 0000000000..8a654deb54
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-busyindicator-custom.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+BusyIndicator {
+ id: control
+
+ contentItem: Item {
+ implicitWidth: 64
+ implicitHeight: 64
+
+ Item {
+ id: item
+ x: parent.width / 2 - 32
+ y: parent.height / 2 - 32
+ width: 64
+ height: 64
+ opacity: control.running ? 1 : 0
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 250
+ }
+ }
+
+ RotationAnimator {
+ target: item
+ running: control.visible && control.running
+ from: 0
+ to: 360
+ loops: Animation.Infinite
+ duration: 1250
+ }
+
+ Repeater {
+ id: repeater
+ model: 6
+
+ Rectangle {
+ id: delegate
+ x: item.width / 2 - width / 2
+ y: item.height / 2 - height / 2
+ implicitWidth: 10
+ implicitHeight: 10
+ radius: 5
+ color: "#21be2b"
+
+ required property int index
+
+ transform: [
+ Translate {
+ y: -Math.min(item.width, item.height) * 0.5 + 5
+ },
+ Rotation {
+ angle: delegate.index / repeater.count * 360
+ origin.x: 5
+ origin.y: 5
+ }
+ ]
+ }
+ }
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-custom.qml
new file mode 100644
index 0000000000..095657b5a6
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-custom.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ id: control
+ text: qsTr("Button")
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: enabled ? 1 : 0.3
+ border.color: control.down ? "#17a81a" : "#21be2b"
+ border.width: 1
+ radius: 2
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-icononly.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-icononly.qml
new file mode 100644
index 0000000000..d74000052b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-icononly.qml
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/check.png"
+ display: Button.IconOnly
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textbesideicon.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textbesideicon.qml
new file mode 100644
index 0000000000..3e2aa619d0
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textbesideicon.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ text: "Button"
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Controls/Basic/images/check.png"
+ display: Button.TextBesideIcon
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textonly.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textonly.qml
new file mode 100644
index 0000000000..59054f7714
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-button-textonly.qml
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Button {
+ text: "Button"
+ display: Button.TextOnly
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-custom.qml
new file mode 100644
index 0000000000..93ebe46dca
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-custom.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+CheckBox {
+ id: control
+ text: qsTr("CheckBox")
+ checked: true
+
+ indicator: Rectangle {
+ implicitWidth: 26
+ implicitHeight: 26
+ x: control.leftPadding
+ y: parent.height / 2 - height / 2
+ radius: 3
+ border.color: control.down ? "#17a81a" : "#21be2b"
+
+ Rectangle {
+ width: 14
+ height: 14
+ x: 6
+ y: 6
+ radius: 2
+ color: control.down ? "#17a81a" : "#21be2b"
+ visible: control.checked
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: control.indicator.width + control.spacing
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-group.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-group.qml
new file mode 100644
index 0000000000..c503216586
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkbox-group.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+Column {
+ ButtonGroup {
+ id: childGroup
+ exclusive: false
+ checkState: parentBox.checkState
+ }
+
+ CheckBox {
+ id: parentBox
+ text: qsTr("Parent")
+ checkState: childGroup.checkState
+ }
+
+ CheckBox {
+ checked: true
+ text: qsTr("Child 1")
+ leftPadding: indicator.width
+ ButtonGroup.group: childGroup
+ }
+
+ CheckBox {
+ text: qsTr("Child 2")
+ leftPadding: indicator.width
+ ButtonGroup.group: childGroup
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkdelegate-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkdelegate-custom.qml
new file mode 100644
index 0000000000..91970f529f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-checkdelegate-custom.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+CheckDelegate {
+ id: control
+ text: qsTr("CheckDelegate")
+ checked: true
+
+ contentItem: Text {
+ rightPadding: control.indicator.width + control.spacing
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ indicator: Rectangle {
+ implicitWidth: 26
+ implicitHeight: 26
+ x: control.width - width - control.rightPadding
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ radius: 3
+ color: "transparent"
+ border.color: control.down ? "#17a81a" : "#21be2b"
+
+ Rectangle {
+ width: 14
+ height: 14
+ x: 6
+ y: 6
+ radius: 2
+ color: control.down ? "#17a81a" : "#21be2b"
+ visible: control.checked
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? "#bdbebf" : "#eeeeee"
+ }
+}
+//! [file]
diff --git a/src/quick/doc/src/cmake-macros.qdoc b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-accepted.qml
index b643a9e4e4..b420e3a572 100644
--- a/src/quick/doc/src/cmake-macros.qdoc
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-accepted.qml
@@ -25,32 +25,21 @@
**
****************************************************************************/
-/*!
-\page qtqml-cmake-qt5-import-qml-plugins.html
-\ingroup cmake-macros-qtqml
-
-\title qt5_import_qml_plugins
-
-\brief Scans \c{.qml} files and imports required QML static plugins
-
-\section1 Overview
-
-\badcode
-find_package(Qt5QmlImportScanner REQUIRED)
-qt5_import_qml_plugins(<TARGET>)
-\endcode
-
-\section1 Description
-
-Runs \c{qmlimportscanner} at configure time to find the static QML plugins
-used and links them to the given target.
-
-\note When used with a non-static Qt build, this function does nothing.
-
-This CMake command was introduced in Qt 5.14.
-
-\section1 Example
-
-\snippet cmake-macros/examples.cmake qt5_import_qml_plugins
-
-*/
+import QtQuick
+import QtQuick.Controls
+
+//! [combobox]
+ComboBox {
+ editable: true
+ model: ListModel {
+ id: model
+ ListElement { text: "Banana" }
+ ListElement { text: "Apple" }
+ ListElement { text: "Coconut" }
+ }
+ onAccepted: {
+ if (find(editText) === -1)
+ model.append({text: editText})
+ }
+}
+//! [combobox]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-custom.qml
new file mode 100644
index 0000000000..08eeae905e
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-custom.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ComboBox {
+ id: control
+ model: ["First", "Second", "Third"]
+
+ delegate: ItemDelegate {
+ width: control.width
+ contentItem: Text {
+ text: control.textRole
+ ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole])
+ : modelData
+ color: "#21be2b"
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ highlighted: control.highlightedIndex === index
+ }
+
+ indicator: Canvas {
+ id: canvas
+ x: control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: 12
+ height: 8
+ contextType: "2d"
+
+ Connections {
+ target: control
+ function onPressedChanged() { canvas.requestPaint(); }
+ }
+
+ onPaint: {
+ context.reset();
+ context.moveTo(0, 0);
+ context.lineTo(width, 0);
+ context.lineTo(width / 2, height);
+ context.closePath();
+ context.fillStyle = control.pressed ? "#17a81a" : "#21be2b";
+ context.fill();
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: 0
+ rightPadding: control.indicator.width + control.spacing
+
+ text: control.displayText
+ font: control.font
+ color: control.pressed ? "#17a81a" : "#21be2b"
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 40
+ border.color: control.pressed ? "#17a81a" : "#21be2b"
+ border.width: control.visualFocus ? 2 : 1
+ radius: 2
+ }
+
+ popup: Popup {
+ y: control.height - 1
+ width: control.width
+ implicitHeight: contentItem.implicitHeight
+ padding: 1
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.popup.visible ? control.delegateModel : null
+ currentIndex: control.highlightedIndex
+
+ ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ border.color: "#21be2b"
+ radius: 2
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-find.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-find.qml
new file mode 100644
index 0000000000..c14ebbbe1f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-find.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [find]
+ComboBox {
+ model: ListModel {
+ ListElement { text: "Banana" }
+ ListElement { text: "Apple" }
+ ListElement { text: "Coconut" }
+ }
+ Component.onCompleted: currentIndex = find("Coconut")
+}
+//! [find]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-popup.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-popup.qml
new file mode 100644
index 0000000000..4aea1888be
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-popup.qml
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick.Controls
+
+ComboBox {
+//! [closePolicy]
+ popup.closePolicy: Popup.CloseOnEscape
+//! [closePolicy]
+//! [modal]
+ popup.modal: true
+//! [modal]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-textat.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-textat.qml
new file mode 100644
index 0000000000..524886d06b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-textat.qml
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [textat]
+ComboBox {
+ model: ListModel {
+ ListElement { text: "Banana" }
+ ListElement { text: "Apple" }
+ ListElement { text: "Coconut" }
+ }
+ onActivated: (index) => { print(textAt(index)) }
+}
+//! [textat]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-valuerole.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-valuerole.qml
new file mode 100644
index 0000000000..a4c40c0f0b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-combobox-valuerole.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [file]
+ApplicationWindow {
+ width: 640
+ height: 480
+ visible: true
+
+ // Used as an example of a backend - this would usually be
+ // e.g. a C++ type exposed to QML.
+ QtObject {
+ id: backend
+ property int modifier
+ }
+
+ ComboBox {
+ textRole: "text"
+ valueRole: "value"
+ // When an item is selected, update the backend.
+ onActivated: backend.modifier = currentValue
+ // Set the initial currentIndex to the value stored in the backend.
+ Component.onCompleted: currentIndex = indexOfValue(backend.modifier)
+ model: [
+ { value: Qt.NoModifier, text: qsTr("No modifier") },
+ { value: Qt.ShiftModifier, text: qsTr("Shift") },
+ { value: Qt.ControlModifier, text: qsTr("Control") }
+ ]
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-delaybutton-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-delaybutton-custom.qml
new file mode 100644
index 0000000000..0b86f1d002
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-delaybutton-custom.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+DelayButton {
+ id: control
+ checked: true
+ text: qsTr("Delay\nButton")
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: "white"
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+ opacity: enabled ? 1 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ radius: size / 2
+
+ readonly property real size: Math.min(control.width, control.height)
+ width: size
+ height: size
+ anchors.centerIn: parent
+
+ Canvas {
+ id: canvas
+ anchors.fill: parent
+
+ Connections {
+ target: control
+ function onProgressChanged() { canvas.requestPaint(); }
+ }
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.clearRect(0, 0, width, height)
+ ctx.strokeStyle = "white"
+ ctx.lineWidth = parent.size / 20
+ ctx.beginPath()
+ var startAngle = Math.PI / 5 * 3
+ var endAngle = startAngle + control.progress * Math.PI / 5 * 9
+ ctx.arc(width / 2, height / 2, width / 2 - ctx.lineWidth / 2 - 2, startAngle, endAngle)
+ ctx.stroke()
+ }
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dial-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dial-custom.qml
new file mode 100644
index 0000000000..170e9ccf09
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dial-custom.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Dial {
+ id: control
+ background: Rectangle {
+ x: control.width / 2 - width / 2
+ y: control.height / 2 - height / 2
+ width: Math.max(64, Math.min(control.width, control.height))
+ height: width
+ color: "transparent"
+ radius: width / 2
+ border.color: control.pressed ? "#17a81a" : "#21be2b"
+ opacity: control.enabled ? 1 : 0.3
+ }
+
+ handle: Rectangle {
+ id: handleItem
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+ width: 16
+ height: 16
+ color: control.pressed ? "#17a81a" : "#21be2b"
+ radius: 8
+ antialiasing: true
+ opacity: control.enabled ? 1 : 0.3
+ transform: [
+ Translate {
+ y: -Math.min(control.background.width, control.background.height) * 0.4 + handleItem.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: handleItem.width / 2
+ origin.y: handleItem.height / 2
+ }
+ ]
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modal.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modal.qml
new file mode 100644
index 0000000000..d60e4e309b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modal.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: dialog.implicitWidth
+ height: dialog.implicitHeight
+//! [1]
+Dialog {
+ id: dialog
+ modal: true
+ standardButtons: Dialog.Ok
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modeless.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modeless.qml
new file mode 100644
index 0000000000..6acb74e59c
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog-modeless.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: dialog.implicitWidth
+ height: dialog.implicitHeight
+//! [1]
+Dialog {
+ id: dialog
+ modal: false
+ standardButtons: Dialog.Ok
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog.qml
new file mode 100644
index 0000000000..13fbb0e843
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialog.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: dialog.implicitWidth
+ height: dialog.implicitHeight
+//! [1]
+Dialog {
+ id: dialog
+ title: "Title"
+ standardButtons: Dialog.Ok | Dialog.Cancel
+
+ onAccepted: console.log("Ok clicked")
+ onRejected: console.log("Cancel clicked")
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox-attached.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox-attached.qml
new file mode 100644
index 0000000000..45a0b9e920
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox-attached.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+DialogButtonBox {
+ Button {
+ text: qsTr("Save")
+ DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
+ }
+ Button {
+ text: qsTr("Close")
+ DialogButtonBox.buttonRole: DialogButtonBox.DestructiveRole
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox.qml
new file mode 100644
index 0000000000..bcfd405b12
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-dialogbuttonbox.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+DialogButtonBox {
+ standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
+
+ onAccepted: console.log("Ok clicked")
+ onRejected: console.log("Cancel clicked")
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame-custom.qml
new file mode 100644
index 0000000000..798f95da13
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame-custom.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Frame {
+ background: Rectangle {
+ color: "transparent"
+ border.color: "#21be2b"
+ radius: 2
+ }
+
+ Label {
+ text: qsTr("Content goes here!")
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame.qml
new file mode 100644
index 0000000000..71b9b310d4
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-frame.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+//! [1]
+Frame {
+ ColumnLayout {
+ anchors.fill: parent
+ CheckBox { text: qsTr("E-mail") }
+ CheckBox { text: qsTr("Calendar") }
+ CheckBox { text: qsTr("Contacts") }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-checkable.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-checkable.qml
new file mode 100644
index 0000000000..91689d9fae
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-checkable.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+//! [1]
+GroupBox {
+ label: CheckBox {
+ id: checkBox
+ checked: true
+ text: qsTr("Synchronize")
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ enabled: checkBox.checked
+ CheckBox { text: qsTr("E-mail") }
+ CheckBox { text: qsTr("Calendar") }
+ CheckBox { text: qsTr("Contacts") }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-custom.qml
new file mode 100644
index 0000000000..e3355b2337
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox-custom.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+GroupBox {
+ id: control
+ title: qsTr("GroupBox")
+
+ background: Rectangle {
+ y: control.topPadding - control.bottomPadding
+ width: parent.width
+ height: parent.height - control.topPadding + control.bottomPadding
+ color: "transparent"
+ border.color: "#21be2b"
+ radius: 2
+ }
+
+ label: Label {
+ x: control.leftPadding
+ width: control.availableWidth
+ text: control.title
+ color: "#21be2b"
+ elide: Text.ElideRight
+ }
+
+ Label {
+ text: qsTr("Content goes here!")
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox.qml
new file mode 100644
index 0000000000..e9f1c7dcc0
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-groupbox.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+//! [1]
+GroupBox {
+ title: qsTr("Synchronize")
+ ColumnLayout {
+ anchors.fill: parent
+ CheckBox { text: qsTr("E-mail") }
+ CheckBox { text: qsTr("Calendar") }
+ CheckBox { text: qsTr("Contacts") }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-headerview-simple.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-headerview-simple.qml
new file mode 100644
index 0000000000..6878904f3c
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-headerview-simple.qml
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//![file]
+import QtQuick
+import QtQuick.Controls
+import Qt.labs.qmlmodels
+
+ApplicationWindow {
+ visible: true
+ width: 640
+ height: 480
+
+ //! [horizontal]
+ HorizontalHeaderView {
+ id: horizontalHeader
+ syncView: tableView
+ anchors.left: tableView.left
+ }
+ //! [horizontal]
+
+ //! [vertical]
+ VerticalHeaderView {
+ id: verticalHeader
+ syncView: tableView
+ anchors.top: tableView.top
+ }
+ //! [vertical]
+
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ anchors.topMargin: horizontalHeader.height
+ anchors.leftMargin: verticalHeader.width
+ columnSpacing: 1
+ rowSpacing: 1
+ clip: true
+
+ model: TableModel {
+ TableModelColumn { display: "name" }
+ TableModelColumn { display: "color" }
+
+ rows: [
+ {
+ "name": "cat",
+ "color": "black"
+ },
+ {
+ "name": "dog",
+ "color": "brown"
+ },
+ {
+ "name": "bird",
+ "color": "white"
+ }
+ ]
+ }
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 50
+ border.width: 1
+
+ Text {
+ text: display
+ anchors.centerIn: parent
+ }
+ }
+ }
+}
+
+//![file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate-custom.qml
new file mode 100644
index 0000000000..fd52b46f32
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate-custom.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ItemDelegate {
+ id: control
+ text: qsTr("ItemDelegate")
+
+ contentItem: Text {
+ rightPadding: control.spacing
+ text: control.text
+ font: control.font
+ color: control.enabled ? (control.down ? "#17a81a" : "#21be2b") : "#bdbebf"
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: enabled ? 1 : 0.3
+ color: control.down ? "#dddedf" : "#eeeeee"
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: control.down ? "#17a81a" : "#21be2b"
+ anchors.bottom: parent.bottom
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate.qml
new file mode 100644
index 0000000000..dbc108e7ab
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-itemdelegate.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+ListView {
+ width: 160
+ height: 240
+
+ model: Qt.fontFamilies()
+
+ delegate: ItemDelegate {
+ text: modelData
+ width: parent.width
+ onClicked: console.log("clicked:", modelData)
+
+ required property string modelData
+ }
+
+ ScrollIndicator.vertical: ScrollIndicator { }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-label-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-label-custom.qml
new file mode 100644
index 0000000000..cc88d00f42
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-label-custom.qml
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Label {
+ text: qsTr("Label")
+ color: "#21be2b"
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-label.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-label.qml
new file mode 100644
index 0000000000..c492af50d4
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-label.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+Label {
+ text: "Label"
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-accent.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-accent.qml
new file mode 100644
index 0000000000..aa4c62b8e5
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-accent.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+Pane {
+ padding: 4
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ highlighted: true
+ Material.accent: Material.Orange
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-background.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-background.qml
new file mode 100644
index 0000000000..f64e48d225
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-background.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+Pane {
+ padding: 4
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ highlighted: true
+ Material.background: Material.Teal
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-elevation.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-elevation.qml
new file mode 100644
index 0000000000..f9e189f17a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-elevation.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+Pane {
+ contentWidth: 120
+ contentHeight: 120
+ padding: 10
+ bottomPadding: 20
+
+//! [1]
+Pane {
+ width: 120
+ height: 120
+
+ Material.elevation: 6
+
+ Label {
+ text: qsTr("I'm a card!")
+ anchors.centerIn: parent
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-foreground.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-foreground.qml
new file mode 100644
index 0000000000..070576f541
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-foreground.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+Pane {
+ padding: 4
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ Material.foreground: Material.Pink
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-theme.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-theme.qml
new file mode 100644
index 0000000000..586433c369
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-theme.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Material
+
+Pane {
+ padding: 10
+
+//! [1]
+Pane {
+ Material.theme: Material.Dark
+
+ Button {
+ text: qsTr("Button")
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-variant.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-variant.qml
new file mode 100644
index 0000000000..df0a617f05
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-material-variant.qml
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Material
+import QtQuick.Layouts
+
+Pane {
+ id: root
+ implicitWidth: 400
+ implicitHeight: 600
+ padding: 10
+
+ readonly property color measurementColor: "darkorange"
+ readonly property int barLeftMargin: 10
+ readonly property int textTopMargin: 12
+
+ Component {
+ id: measurementComponent
+
+ Rectangle {
+ color: root.measurementColor
+ width: 1
+ height: parent.height
+
+ Rectangle {
+ width: 5
+ height: 1
+ color: root.measurementColor
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ Rectangle {
+ width: 5
+ height: 1
+ color: root.measurementColor
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ }
+
+ Text {
+ x: 8
+ text: parent.height
+ height: parent.height
+ color: root.measurementColor
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 20
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ Button {
+ id: button
+ text: qsTr("Button")
+
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+
+ }
+ Text {
+ text: "Roboto " + button.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ ItemDelegate {
+ id: itemDelegate
+ text: qsTr("ItemDelegate")
+
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+
+ }
+ Text {
+ text: "Roboto " + itemDelegate.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ CheckDelegate {
+ id: checkDelegate
+ text: qsTr("CheckDelegate")
+
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+
+ }
+ Text {
+ text: "Roboto " + checkDelegate.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ RadioDelegate {
+ id: radioDelegate
+ text: qsTr("RadioDelegate")
+
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+
+ }
+ Text {
+ text: "Roboto " + radioDelegate.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ ComboBox {
+ id: comboBox
+ model: [ qsTr("ComboBox") ]
+
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+
+ }
+ Text {
+ text: "Roboto " + comboBox.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ ColumnLayout {
+ spacing: root.textTopMargin
+
+ Item {
+ implicitWidth: groupBox.implicitWidth
+ implicitHeight: groupBox.implicitHeight
+
+ GroupBox {
+ id: groupBox
+ title: qsTr("GroupBox")
+ }
+ Loader {
+ sourceComponent: measurementComponent
+ height: parent.height
+ anchors.left: parent.right
+ anchors.leftMargin: root.barLeftMargin
+ }
+ }
+ Text {
+ text: "Roboto " + groupBox.font.pixelSize
+ color: root.measurementColor
+ }
+ }
+
+ Item {
+ Layout.fillHeight: true
+ }
+ }
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-menu-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menu-custom.qml
new file mode 100644
index 0000000000..3e766e8a7a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menu-custom.qml
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+ width: menu.width
+ height: menu.height
+ visible: true
+
+ Component.onCompleted: menu.popup(menu.itemAt(1))
+
+// Indent it like this so that the indenting in the generated doc is normal.
+Menu {
+ id: menu
+
+ Action { text: qsTr("Tool Bar"); checkable: true }
+ Action { text: qsTr("Side Bar"); checkable: true; checked: true }
+ Action { text: qsTr("Status Bar"); checkable: true; checked: true }
+
+ MenuSeparator {
+ contentItem: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 1
+ color: "#21be2b"
+ }
+ }
+
+ Menu {
+ title: qsTr("Advanced")
+ // ...
+ }
+
+ topPadding: 2
+ bottomPadding: 2
+
+ delegate: MenuItem {
+ id: menuItem
+ implicitWidth: 200
+ implicitHeight: 40
+
+ arrow: Canvas {
+ x: parent.width - width
+ implicitWidth: 40
+ implicitHeight: 40
+ visible: menuItem.subMenu
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.fillStyle = menuItem.highlighted ? "#ffffff" : "#21be2b"
+ ctx.moveTo(15, 15)
+ ctx.lineTo(width - 15, height / 2)
+ ctx.lineTo(15, height - 15)
+ ctx.closePath()
+ ctx.fill()
+ }
+ }
+
+ indicator: Item {
+ implicitWidth: 40
+ implicitHeight: 40
+ Rectangle {
+ width: 26
+ height: 26
+ anchors.centerIn: parent
+ visible: menuItem.checkable
+ border.color: "#21be2b"
+ radius: 3
+ Rectangle {
+ width: 14
+ height: 14
+ anchors.centerIn: parent
+ visible: menuItem.checked
+ color: "#21be2b"
+ radius: 2
+ }
+ }
+ }
+
+ contentItem: Text {
+ leftPadding: menuItem.indicator.width
+ rightPadding: menuItem.arrow.width
+ text: menuItem.text
+ font: menuItem.font
+ opacity: enabled ? 1.0 : 0.3
+ color: menuItem.highlighted ? "#ffffff" : "#21be2b"
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ opacity: enabled ? 1 : 0.3
+ color: menuItem.highlighted ? "#21be2b" : "transparent"
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ color: "#ffffff"
+ border.color: "#21be2b"
+ radius: 2
+ }
+}
+} //! [eof]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar-custom.qml
new file mode 100644
index 0000000000..4b3d641e21
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar-custom.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ id: window
+ visible: true
+ width: menuBar.implicitWidth
+ height: menuBar.height
+
+ Component.onCompleted: menuBar.itemAt(1).highlighted = true
+
+ header:
+
+// Indent it like this so that the indenting in the generated doc is normal.
+MenuBar {
+ id: menuBar
+
+ Menu { title: qsTr("File") }
+ Menu { title: qsTr("Edit") }
+ Menu { title: qsTr("View") }
+ Menu { title: qsTr("Help") }
+
+ delegate: MenuBarItem {
+ id: menuBarItem
+
+ contentItem: Text {
+ text: menuBarItem.text
+ font: menuBarItem.font
+ opacity: enabled ? 1.0 : 0.3
+ color: menuBarItem.highlighted ? "#ffffff" : "#21be2b"
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ opacity: enabled ? 1 : 0.3
+ color: menuBarItem.highlighted ? "#21be2b" : "transparent"
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ color: "#ffffff"
+
+ Rectangle {
+ color: "#21be2b"
+ width: parent.width
+ height: 1
+ anchors.bottom: parent.bottom
+ }
+ }
+}
+} //! [eof]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar.qml
new file mode 100644
index 0000000000..7ae22ae8c2
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menubar.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [begin]
+ApplicationWindow {
+ id: window
+ width: 320
+ height: 260
+ visible: true
+
+ //! [skipfrom]
+ Component.onCompleted: {
+ menuBar.itemAt(0).triggered()
+ menuBar.itemAt(0).menu.itemAt(2).highlighted = true
+ }
+ //! [skipto]
+
+ menuBar: MenuBar {
+ Menu {
+ title: qsTr("&File")
+ Action { text: qsTr("&New...") }
+ Action { text: qsTr("&Open...") }
+ Action { text: qsTr("&Save") }
+ Action { text: qsTr("Save &As...") }
+ MenuSeparator { }
+ Action { text: qsTr("&Quit") }
+ }
+ Menu {
+ title: qsTr("&Edit")
+ Action { text: qsTr("Cu&t") }
+ Action { text: qsTr("&Copy") }
+ Action { text: qsTr("&Paste") }
+ }
+ Menu {
+ title: qsTr("&Help")
+ Action { text: qsTr("&About") }
+ }
+ }
+}
+//! [end]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator-custom.qml
new file mode 100644
index 0000000000..fa7fa14a44
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator-custom.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: window
+ width: menu.contentItem.width
+ height: menu.contentItem.height
+ visible: true
+
+// Indent it like this so that the indenting in the generated doc is normal.
+Menu {
+ id: menu
+ contentItem.parent: window
+
+ MenuItem {
+ text: qsTr("New...")
+ }
+ MenuItem {
+ text: qsTr("Open...")
+ }
+ MenuItem {
+ text: qsTr("Save")
+ }
+
+ MenuSeparator {
+ padding: 0
+ topPadding: 12
+ bottomPadding: 12
+ contentItem: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 1
+ color: "#1E000000"
+ }
+ }
+
+ MenuItem {
+ text: qsTr("Exit")
+ }
+}
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator.qml
new file mode 100644
index 0000000000..cd5d544155
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-menuseparator.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: window
+ width: menu.contentItem.width
+ height: menu.contentItem.height
+ visible: true
+
+// Indent it like this so that the indenting in the generated doc is normal.
+Menu {
+ id: menu
+ contentItem.parent: window
+
+ MenuItem {
+ text: qsTr("New...")
+ }
+ MenuItem {
+ text: qsTr("Open...")
+ }
+ MenuItem {
+ text: qsTr("Save")
+ }
+
+ MenuSeparator {}
+
+ MenuItem {
+ text: qsTr("Exit")
+ }
+}
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modal.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modal.qml
new file mode 100644
index 0000000000..9751f05781
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modal.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Window
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ Binding {
+ target: popup
+ property: "visible"
+ value: root.Window.active
+ }
+//! [1]
+Popup {
+ id: popup
+ width: 400
+ height: 400
+ modal: true
+ visible: true
+
+ Overlay.modal: Rectangle {
+ color: "#aacfdbe7"
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modeless.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modeless.qml
new file mode 100644
index 0000000000..a4951d1386
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overlay-modeless.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Window
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ Binding {
+ target: popup
+ property: "visible"
+ value: root.Window.active
+ }
+//! [1]
+Popup {
+ id: popup
+ width: 400
+ height: 400
+ dim: true
+ visible: true
+
+ Overlay.modeless: Rectangle {
+ color: "#aacfdbe7"
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-overview.cmake b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overview.cmake
new file mode 100644
index 0000000000..b643e2c21d
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-overview.cmake
@@ -0,0 +1,4 @@
+#! [0]
+find_package(Qt6 REQUIRED COMPONENTS QuickControls2)
+target_link_libraries(mytarget PRIVATE Qt6::QuickControls2)
+#! [0]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-custom.qml
new file mode 100644
index 0000000000..2ca92cb427
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-custom.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+PageIndicator {
+ id: control
+ count: 5
+ currentIndex: 2
+
+ delegate: Rectangle {
+ implicitWidth: 8
+ implicitHeight: 8
+
+ radius: width / 2
+ color: "#21be2b"
+
+ opacity: index === control.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
+
+ required property int index
+
+ Behavior on opacity {
+ OpacityAnimator {
+ duration: 100
+ }
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-interactive.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-interactive.qml
new file mode 100644
index 0000000000..8f2221ee4e
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator-interactive.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick.Controls
+
+Pane {
+//! [1]
+SwipeView {
+ id: view
+ currentIndex: pageIndicator.currentIndex
+ anchors.fill: parent
+
+ Page {
+ title: qsTr("Home")
+ }
+ Page {
+ title: qsTr("Discover")
+ }
+ Page {
+ title: qsTr("Activity")
+ }
+}
+
+PageIndicator {
+ id: pageIndicator
+ interactive: true
+ count: view.count
+ currentIndex: view.currentIndex
+
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator.qml
new file mode 100644
index 0000000000..b3912efe7a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pageindicator.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+PageIndicator {
+ count: 5
+ currentIndex: 2
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane-custom.qml
new file mode 100644
index 0000000000..855423c4c2
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane-custom.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Pane {
+ background: Rectangle {
+ color: "#eeeeee"
+ }
+
+ Label {
+ text: qsTr("Content goes here!")
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane.qml
new file mode 100644
index 0000000000..a8c8672e77
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-pane.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+//! [1]
+Pane {
+ ColumnLayout {
+ anchors.fill: parent
+ CheckBox { text: qsTr("E-mail") }
+ CheckBox { text: qsTr("Calendar") }
+ CheckBox { text: qsTr("Contacts") }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup-custom.qml
new file mode 100644
index 0000000000..ad5481e34d
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup-custom.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Window
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ Binding {
+ target: popup
+ property: "visible"
+ value: root.Window.active
+ }
+//! [1]
+Popup {
+ id: popup
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 200
+ border.color: "#444"
+ }
+ contentItem: Column {}
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup.qml
new file mode 100644
index 0000000000..76ec20cdb2
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-popup.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+//! [centerIn]
+ApplicationWindow {
+ id: window
+ // ...
+
+ Pane {
+ // ...
+
+ Popup {
+ anchors.centerIn: Overlay.overlay
+ }
+ }
+}
+//! [centerIn]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-progressbar-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-progressbar-custom.qml
new file mode 100644
index 0000000000..d96161577b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-progressbar-custom.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ProgressBar {
+ id: control
+ value: 0.5
+ padding: 2
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 6
+ color: "#e6e6e6"
+ radius: 3
+ }
+
+ contentItem: Item {
+ implicitWidth: 200
+ implicitHeight: 4
+
+ Rectangle {
+ width: control.visualPosition * parent.width
+ height: parent.height
+ radius: 2
+ color: "#17a81a"
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiobutton-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiobutton-custom.qml
new file mode 100644
index 0000000000..b33ce6b6d9
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiobutton-custom.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+RadioButton {
+ id: control
+ text: qsTr("RadioButton")
+ checked: true
+
+ indicator: Rectangle {
+ implicitWidth: 26
+ implicitHeight: 26
+ x: control.leftPadding
+ y: parent.height / 2 - height / 2
+ radius: 13
+ border.color: control.down ? "#17a81a" : "#21be2b"
+
+ Rectangle {
+ width: 14
+ height: 14
+ x: 6
+ y: 6
+ radius: 7
+ color: control.down ? "#17a81a" : "#21be2b"
+ visible: control.checked
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: control.indicator.width + control.spacing
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiodelegate-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiodelegate-custom.qml
new file mode 100644
index 0000000000..ed3dae678a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-radiodelegate-custom.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+RadioDelegate {
+ id: control
+ text: qsTr("RadioDelegate")
+ checked: true
+
+ contentItem: Text {
+ rightPadding: control.indicator.width + control.spacing
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ indicator: Rectangle {
+ implicitWidth: 26
+ implicitHeight: 26
+ x: control.width - width - control.rightPadding
+ y: parent.height / 2 - height / 2
+ radius: 13
+ color: "transparent"
+ border.color: control.down ? "#17a81a" : "#21be2b"
+
+ Rectangle {
+ width: 14
+ height: 14
+ x: 6
+ y: 6
+ radius: 7
+ color: control.down ? "#17a81a" : "#21be2b"
+ visible: control.checked
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? "#bdbebf" : "#eeeeee"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-rangeslider-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-rangeslider-custom.qml
new file mode 100644
index 0000000000..fcddc40067
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-rangeslider-custom.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+RangeSlider {
+ id: control
+ first.value: 0.25
+ second.value: 0.75
+
+ background: Rectangle {
+ x: control.leftPadding
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 200
+ implicitHeight: 4
+ width: control.availableWidth
+ height: implicitHeight
+ radius: 2
+ color: "#bdbebf"
+
+ Rectangle {
+ x: control.first.visualPosition * parent.width
+ width: control.second.visualPosition * parent.width - x
+ height: parent.height
+ color: "#21be2b"
+ radius: 2
+ }
+ }
+
+ first.handle: Rectangle {
+ x: control.leftPadding + control.first.visualPosition * (control.availableWidth - width)
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 26
+ implicitHeight: 26
+ radius: 13
+ color: control.first.pressed ? "#f0f0f0" : "#f6f6f6"
+ border.color: "#bdbebf"
+ }
+
+ second.handle: Rectangle {
+ x: control.leftPadding + control.second.visualPosition * (control.availableWidth - width)
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 26
+ implicitHeight: 26
+ radius: 13
+ color: control.second.pressed ? "#f0f0f0" : "#f6f6f6"
+ border.color: "#bdbebf"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-roundbutton.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-roundbutton.qml
new file mode 100644
index 0000000000..201ee24403
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-roundbutton.qml
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+RoundButton {
+ text: "\u2713" // Unicode Character 'CHECK MARK'
+ onClicked: textArea.readOnly = true
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-active.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-active.qml
new file mode 100644
index 0000000000..bd417955e4
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-active.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 100
+ height: 100
+
+ //! [1]
+ Flickable {
+ anchors.fill: parent
+
+ contentWidth: parent.width * 2
+ contentHeight: parent.height * 2
+
+ ScrollBar.horizontal: ScrollBar { id: hbar; active: vbar.active }
+ ScrollBar.vertical: ScrollBar { id: vbar; active: hbar.active }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-custom.qml
new file mode 100644
index 0000000000..50db35f97b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-custom.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ScrollBar {
+ id: control
+ size: 0.3
+ position: 0.2
+ active: true
+ orientation: Qt.Vertical
+
+ contentItem: Rectangle {
+ implicitWidth: 6
+ implicitHeight: 100
+ radius: width / 2
+ color: control.pressed ? "#81e889" : "#c2f4c6"
+ // Hide the ScrollBar when it's not needed.
+ opacity: control.policy === ScrollBar.AlwaysOn || (control.active && control.size < 1.0) ? 0.75 : 0
+
+ // Animate the changes in opacity (default duration is 250 ms).
+ Behavior on opacity {
+ NumberAnimation {}
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-non-attached.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-non-attached.qml
new file mode 100644
index 0000000000..7ca6661557
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-non-attached.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 200
+
+//! [1]
+Rectangle {
+ id: frame
+ clip: true
+ width: 160
+ height: 160
+ border.color: "black"
+ anchors.centerIn: parent
+
+ Text {
+ id: content
+ text: "ABC"
+ font.pixelSize: 160
+ x: -hbar.position * width
+ y: -vbar.position * height
+ }
+
+ ScrollBar {
+ id: vbar
+ hoverEnabled: true
+ active: hovered || pressed
+ orientation: Qt.Vertical
+ size: frame.height / content.height
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ }
+
+ ScrollBar {
+ id: hbar
+ hoverEnabled: true
+ active: hovered || pressed
+ orientation: Qt.Horizontal
+ size: frame.width / content.width
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ }
+}
+//! [1]
+
+Component.onCompleted: {
+ hbar.active = true
+ vbar.active = true
+}
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-policy.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-policy.qml
new file mode 100644
index 0000000000..c608dac44a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollbar-policy.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+Flickable {
+ contentHeight: 2000
+ ScrollBar.vertical: ScrollBar {
+ policy: ScrollBar.AlwaysOn
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-active.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-active.qml
new file mode 100644
index 0000000000..719b9393f1
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-active.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 100
+ height: 100
+
+ //! [1]
+ Flickable {
+ anchors.fill: parent
+
+ contentWidth: parent.width * 2
+ contentHeight: parent.height * 2
+
+ ScrollIndicator.horizontal: ScrollIndicator { id: hbar; active: vbar.active }
+ ScrollIndicator.vertical: ScrollIndicator { id: vbar; active: hbar.active }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-custom.qml
new file mode 100644
index 0000000000..b18d391c4d
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-custom.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ScrollIndicator {
+ id: control
+ size: 0.3
+ position: 0.2
+ active: true
+ orientation: Qt.Vertical
+
+ contentItem: Rectangle {
+ implicitWidth: 2
+ implicitHeight: 100
+ color: "#c2f4c6"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-non-attached.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-non-attached.qml
new file mode 100644
index 0000000000..0d6c4529dd
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollindicator-non-attached.qml
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 200
+
+//! [1]
+Rectangle {
+ id: frame
+ clip: true
+ width: 160
+ height: 160
+ border.color: "black"
+ anchors.centerIn: parent
+
+ Text {
+ id: content
+ text: "ABC"
+ font.pixelSize: 169
+
+ MouseArea {
+ id: mouseArea
+ drag.target: content
+ drag.minimumX: frame.width - width
+ drag.minimumY: frame.height - height
+ drag.maximumX: 0
+ drag.maximumY: 0
+ anchors.fill: content
+ }
+ }
+
+ ScrollIndicator {
+ id: verticalIndicator
+ active: mouseArea.pressed
+ orientation: Qt.Vertical
+ size: frame.height / content.height
+ position: -content.y / content.height
+ anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
+ }
+
+ ScrollIndicator {
+ id: horizontalIndicator
+ active: mouseArea.pressed
+ orientation: Qt.Horizontal
+ size: frame.width / content.width
+ position: -content.x / content.width
+ anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
+ }
+}
+//! [1]
+
+Component.onCompleted: {
+ horizontalIndicator.active = true;
+ verticalIndicator.active = true;
+}
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-custom.qml
new file mode 100644
index 0000000000..1a80d263b7
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-custom.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 200
+
+ Binding {
+ target: control.ScrollBar.horizontal
+ property: "active"
+ value: true
+ }
+
+ Binding {
+ target: control.ScrollBar.vertical
+ property: "active"
+ value: true
+ }
+
+//! [file]
+ScrollView {
+ id: control
+
+ width: 200
+ height: 200
+ focus: true
+
+ Label {
+ text: "ABC"
+ font.pixelSize: 224
+ }
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.ScrollBar.vertical.active
+ }
+
+ background: Rectangle {
+ border.color: control.activeFocus ? "#21be2b" : "#bdbebf"
+ }
+}
+//! [file]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-interactive.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-interactive.qml
new file mode 100644
index 0000000000..8386172035
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-interactive.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [file]
+ScrollView {
+ // ...
+ ScrollBar.horizontal.interactive: true
+ ScrollBar.vertical.interactive: true
+}
+//! [file]
+
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-listview.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-listview.qml
new file mode 100644
index 0000000000..bc1b11bd08
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-listview.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ id: root
+ width: 200
+ height: 200
+
+ Binding {
+ target: root.children[0].ScrollBar.horizontal
+ property: "active"
+ value: true
+ }
+
+ Binding {
+ target: root.children[0].ScrollBar.vertical
+ property: "active"
+ value: true
+ }
+
+//! [file]
+ScrollView {
+ width: 200
+ height: 200
+
+ ListView {
+ model: 20
+ delegate: ItemDelegate {
+ text: "Item " + index
+
+ required property int index
+ }
+ }
+}
+//! [file]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-policy.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-policy.qml
new file mode 100644
index 0000000000..78098eaaa6
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview-policy.qml
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [file]
+ScrollView {
+ // ...
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical.policy: ScrollBar.AlwaysOn
+}
+//! [file]
+
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview.qml
new file mode 100644
index 0000000000..c96ae1ed89
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-scrollview.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Rectangle {
+ id: root
+ width: 200
+ height: 200
+ border.color: "#ddd"
+
+ Binding {
+ target: root.children[0].ScrollBar.horizontal
+ property: "active"
+ value: true
+ }
+
+ Binding {
+ target: root.children[0].ScrollBar.vertical
+ property: "active"
+ value: true
+ }
+
+//! [file]
+ScrollView {
+ width: 200
+ height: 200
+
+ Label {
+ text: "ABC"
+ font.pixelSize: 224
+ }
+}
+//! [file]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-selectionrectangle.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-selectionrectangle.qml
new file mode 100644
index 0000000000..c866832432
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-selectionrectangle.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+import QtQml.Models
+import Qt.labs.qmlmodels
+
+Window {
+ width: 480
+ height: 640
+ visible: true
+ visibility: Window.AutomaticVisibility
+
+//![0]
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ clip: true
+
+ model: TableModel {
+ TableModelColumn { display: "name" }
+ rows: [ { "name": "Harry" }, { "name": "Hedwig" } ]
+ }
+
+ selectionModel: ItemSelectionModel {
+ model: tableView.model
+ }
+
+ delegate: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 30
+ color: selected ? "blue" : "lightgray"
+
+ required property bool selected
+
+ Text { text: display }
+ }
+ }
+
+ SelectionRectangle {
+ target: tableView
+ }
+//![0]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-slider-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-slider-custom.qml
new file mode 100644
index 0000000000..c3d7f4b2d1
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-slider-custom.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Slider {
+ id: control
+ value: 0.5
+
+ background: Rectangle {
+ x: control.leftPadding
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 200
+ implicitHeight: 4
+ width: control.availableWidth
+ height: implicitHeight
+ radius: 2
+ color: "#bdbebf"
+
+ Rectangle {
+ width: control.visualPosition * parent.width
+ height: parent.height
+ color: "#21be2b"
+ radius: 2
+ }
+ }
+
+ handle: Rectangle {
+ x: control.leftPadding + control.visualPosition * (control.availableWidth - width)
+ y: control.topPadding + control.availableHeight / 2 - height / 2
+ implicitWidth: 26
+ implicitHeight: 26
+ radius: 13
+ color: control.pressed ? "#f0f0f0" : "#f6f6f6"
+ border.color: "#bdbebf"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-custom.qml
new file mode 100644
index 0000000000..89f6244f70
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-custom.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+SpinBox {
+ id: control
+ value: 50
+ editable: true
+
+ contentItem: TextInput {
+ z: 2
+ text: control.textFromValue(control.value, control.locale)
+
+ font: control.font
+ color: "#21be2b"
+ selectionColor: "#21be2b"
+ selectedTextColor: "#ffffff"
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: Qt.ImhFormattedNumbersOnly
+ }
+
+ up.indicator: Rectangle {
+ x: control.mirrored ? 0 : parent.width - width
+ height: parent.height
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.up.pressed ? "#e4e4e4" : "#f6f6f6"
+ border.color: enabled ? "#21be2b" : "#bdbebf"
+
+ Text {
+ text: "+"
+ font.pixelSize: control.font.pixelSize * 2
+ color: "#21be2b"
+ anchors.fill: parent
+ fontSizeMode: Text.Fit
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ down.indicator: Rectangle {
+ x: control.mirrored ? parent.width - width : 0
+ height: parent.height
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.down.pressed ? "#e4e4e4" : "#f6f6f6"
+ border.color: enabled ? "#21be2b" : "#bdbebf"
+
+ Text {
+ text: "-"
+ font.pixelSize: control.font.pixelSize * 2
+ color: "#21be2b"
+ anchors.fill: parent
+ fontSizeMode: Text.Fit
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 140
+ border.color: "#bdbebf"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-double.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-double.qml
new file mode 100644
index 0000000000..852ee5be6f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-double.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+SpinBox {
+ id: spinbox
+ from: 0
+ value: 110
+ to: 100 * 100
+ stepSize: 100
+ anchors.centerIn: parent
+
+ property int decimals: 2
+ property real realValue: value / 100
+
+ validator: DoubleValidator {
+ bottom: Math.min(spinbox.from, spinbox.to)
+ top: Math.max(spinbox.from, spinbox.to)
+ }
+
+ textFromValue: function(value, locale) {
+ return Number(value / 100).toLocaleString(locale, 'f', spinbox.decimals)
+ }
+
+ valueFromText: function(text, locale) {
+ return Number.fromLocaleString(locale, text) * 100
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-textual.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-textual.qml
new file mode 100644
index 0000000000..ba3b133c14
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox-textual.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+SpinBox {
+ id: spinBox
+ from: 0
+ to: items.length - 1
+ value: 1 // "Medium"
+
+ property var items: ["Small", "Medium", "Large"]
+
+ validator: RegularExpressionValidator {
+ regularExpression: new RegExp("(Small|Medium|Large)", "i")
+ }
+
+ textFromValue: function(value) {
+ return items[value];
+ }
+
+ valueFromText: function(text) {
+ for (var i = 0; i < items.length; ++i) {
+ if (items[i].toLowerCase().indexOf(text.toLowerCase()) === 0)
+ return i
+ }
+ return spinBox.value
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox.qml
new file mode 100644
index 0000000000..8772274969
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-spinbox.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+SpinBox {
+ value: 50
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-custom.qml
new file mode 100644
index 0000000000..570c3acd33
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-custom.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 100
+
+ //! [1]
+ SplitView {
+ id: splitView
+ anchors.fill: parent
+
+ handle: Rectangle {
+ implicitWidth: 4
+ implicitHeight: 4
+ color: SplitHandle.pressed ? "#81e889"
+ : (SplitHandle.hovered ? Qt.lighter("#c2f4c6", 1.1) : "#c2f4c6")
+ }
+
+ Rectangle {
+ implicitWidth: 150
+ color: "#444"
+ }
+ Rectangle {
+ implicitWidth: 50
+ color: "#666"
+ }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-handle-containmentmask.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-handle-containmentmask.qml
new file mode 100644
index 0000000000..da410c02e0
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-splitview-handle-containmentmask.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 100
+
+ //! [1]
+ SplitView {
+ id: splitView
+ anchors.fill: parent
+
+ handle: Rectangle {
+ id: handleDelegate
+ implicitWidth: 4
+ implicitHeight: 4
+ color: SplitHandle.pressed ? "#81e889"
+ : (SplitHandle.hovered ? Qt.lighter("#c2f4c6", 1.1) : "#c2f4c6")
+
+ containmentMask: Item {
+ x: (handleDelegate.width - width) / 2
+ width: 64
+ height: splitView.height
+ }
+ }
+
+ Rectangle {
+ implicitWidth: 150
+ color: "#444"
+ }
+ Rectangle {
+ implicitWidth: 50
+ color: "#666"
+ }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-custom.qml
new file mode 100644
index 0000000000..64cdb3ceb9
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-custom.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+StackView {
+ id: control
+
+ popEnter: Transition {
+ XAnimator {
+ from: (control.mirrored ? -1 : 1) * -control.width
+ to: 0
+ duration: 400
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ popExit: Transition {
+ XAnimator {
+ from: 0
+ to: (control.mirrored ? -1 : 1) * control.width
+ duration: 400
+ easing.type: Easing.OutCubic
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-visible.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-visible.qml
new file mode 100644
index 0000000000..0e1a0dd495
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-stackview-visible.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+StackView {
+ id: stackView
+ property real offset: 10
+ width: 100; height: 100
+
+ initialItem: Component {
+ id: page
+ Rectangle {
+ property real pos: StackView.index * stackView.offset
+ property real hue: Math.random()
+ color: Qt.hsla(hue, 0.5, 0.8, 0.6)
+ border.color: Qt.hsla(hue, 0.5, 0.5, 0.9)
+ StackView.visible: true
+ }
+ }
+
+ pushEnter: Transition {
+ id: pushEnter
+ ParallelAnimation {
+ PropertyAction { property: "x"; value: pushEnter.ViewTransition.item.pos }
+ NumberAnimation { properties: "y"; from: pushEnter.ViewTransition.item.pos + stackView.offset; to: pushEnter.ViewTransition.item.pos; duration: 400; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+ popExit: Transition {
+ id: popExit
+ ParallelAnimation {
+ PropertyAction { property: "x"; value: popExit.ViewTransition.item.pos }
+ NumberAnimation { properties: "y"; from: popExit.ViewTransition.item.pos; to: popExit.ViewTransition.item.pos + stackView.offset; duration: 400; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+
+ pushExit: Transition {
+ id: pushExit
+ PropertyAction { property: "x"; value: pushExit.ViewTransition.item.pos }
+ PropertyAction { property: "y"; value: pushExit.ViewTransition.item.pos }
+ }
+ popEnter: Transition {
+ id: popEnter
+ PropertyAction { property: "x"; value: popEnter.ViewTransition.item.pos }
+ PropertyAction { property: "y"; value: popEnter.ViewTransition.item.pos }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml
new file mode 100644
index 0000000000..c89b96a42f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-custom.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+SwipeDelegate {
+ id: control
+ text: qsTr("SwipeDelegate")
+
+ Component {
+ id: component
+
+ Rectangle {
+ color: SwipeDelegate.pressed ? "#333" : "#444"
+ width: parent.width
+ height: parent.height
+ clip: true
+
+ Label {
+ text: qsTr("Press me!")
+ color: "#21be2b"
+ anchors.centerIn: parent
+ }
+ }
+ }
+
+ swipe.left: component
+ swipe.right: component
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ color: control.enabled ? (control.down ? "#17a81a" : "#21be2b") : "#bdbebf"
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ Behavior on x {
+ enabled: !control.down
+ NumberAnimation {
+ easing.type: Easing.InOutCubic
+ duration: 400
+ }
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-transition.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-transition.qml
new file mode 100644
index 0000000000..dc0d58a2ca
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate-transition.qml
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+SwipeDelegate {
+ swipe.transition: Transition {
+ SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml
new file mode 100644
index 0000000000..866e711481
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipedelegate.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+ListView {
+ id: listView
+ anchors.fill: parent
+ model: ListModel {
+ ListElement { sender: "Bob Bobbleton"; title: "How are you going?" }
+ ListElement { sender: "Rug Emporium"; title: "SALE! All rugs MUST go!" }
+ ListElement { sender: "Electric Co."; title: "Electricity bill 15/07/2016 overdue" }
+ ListElement { sender: "Tips"; title: "Five ways this tip will save your life" }
+ }
+ delegate: SwipeDelegate {
+ id: swipeDelegate
+ text: sender + " - " + title
+ width: listView.width
+
+ required property string sender
+ required property string title
+ required property int index
+
+ ListView.onRemove: SequentialAnimation {
+ PropertyAction {
+ target: swipeDelegate
+ property: "ListView.delayRemove"
+ value: true
+ }
+ NumberAnimation {
+ target: swipeDelegate
+ property: "height"
+ to: 0
+ easing.type: Easing.InOutQuad
+ }
+ PropertyAction {
+ target: swipeDelegate
+ property: "ListView.delayRemove"
+ value: false
+ }
+ }
+
+ swipe.right: Label {
+ id: deleteLabel
+ text: qsTr("Delete")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+ anchors.right: parent.right
+
+ SwipeDelegate.onClicked: listView.model.remove(index)
+
+ background: Rectangle {
+ color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-custom.qml
new file mode 100644
index 0000000000..b8cddb315a
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-custom.qml
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+SwipeView {
+ id: control
+
+ background: Rectangle {
+ color: "#eeeeee"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-indicator.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-indicator.qml
new file mode 100644
index 0000000000..98b381f14e
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-swipeview-indicator.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 200
+ height: 320
+
+ //! [1]
+ SwipeView {
+ id: view
+
+ currentIndex: 1
+ anchors.fill: parent
+
+ Item {
+ id: firstPage
+ }
+ Item {
+ id: secondPage
+ }
+ Item {
+ id: thirdPage
+ }
+ }
+
+ PageIndicator {
+ id: indicator
+
+ count: view.count
+ currentIndex: view.currentIndex
+
+ anchors.bottom: view.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-switch-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-switch-custom.qml
new file mode 100644
index 0000000000..9adccbed2f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-switch-custom.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Switch {
+ id: control
+ text: qsTr("Switch")
+
+ indicator: Rectangle {
+ implicitWidth: 48
+ implicitHeight: 26
+ x: control.leftPadding
+ y: parent.height / 2 - height / 2
+ radius: 13
+ color: control.checked ? "#17a81a" : "#ffffff"
+ border.color: control.checked ? "#17a81a" : "#cccccc"
+
+ Rectangle {
+ x: control.checked ? parent.width - width : 0
+ width: 26
+ height: 26
+ radius: 13
+ color: control.down ? "#cccccc" : "#ffffff"
+ border.color: control.checked ? (control.down ? "#17a81a" : "#21be2b") : "#999999"
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ verticalAlignment: Text.AlignVCenter
+ leftPadding: control.indicator.width + control.spacing
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-switchdelegate-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-switchdelegate-custom.qml
new file mode 100644
index 0000000000..bea35f29ea
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-switchdelegate-custom.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+SwitchDelegate {
+ id: control
+ text: qsTr("SwitchDelegate")
+ checked: true
+
+ contentItem: Text {
+ rightPadding: control.indicator.width + control.spacing
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ indicator: Rectangle {
+ implicitWidth: 48
+ implicitHeight: 26
+ x: control.width - width - control.rightPadding
+ y: parent.height / 2 - height / 2
+ radius: 13
+ color: control.checked ? "#17a81a" : "transparent"
+ border.color: control.checked ? "#17a81a" : "#cccccc"
+
+ Rectangle {
+ x: control.checked ? parent.width - width : 0
+ width: 26
+ height: 26
+ radius: 13
+ color: control.down ? "#cccccc" : "#ffffff"
+ border.color: control.checked ? (control.down ? "#17a81a" : "#21be2b") : "#999999"
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted
+ color: control.down ? "#bdbebf" : "#eeeeee"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-custom.qml
new file mode 100644
index 0000000000..eba4825632
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-custom.qml
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+TabBar {
+ id: control
+
+ background: Rectangle {
+ color: "#eeeeee"
+ }
+
+ TabButton {
+ text: qsTr("Home")
+ }
+ TabButton {
+ text: qsTr("Discover")
+ }
+ TabButton {
+ text: qsTr("Activity")
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-explicit.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-explicit.qml
new file mode 100644
index 0000000000..5f5482551f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-explicit.qml
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 360
+ height: childrenRect.height
+
+//! [1]
+TabBar {
+ width: parent.width
+ TabButton {
+ text: "First"
+ width: implicitWidth
+ }
+ TabButton {
+ text: "Second"
+ width: implicitWidth
+ }
+ TabButton {
+ text: "Third"
+ width: implicitWidth
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-flickable.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-flickable.qml
new file mode 100644
index 0000000000..8e41bbf0ca
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar-flickable.qml
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 360
+ height: bar.height
+
+//! [1]
+TabBar {
+ id: bar
+ width: parent.width
+
+ Repeater {
+ model: ["First", "Second", "Third", "Fourth", "Fifth"]
+
+ TabButton {
+ text: modelData
+ width: Math.max(100, bar.width / 5)
+ }
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar.qml
new file mode 100644
index 0000000000..7a02f37521
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbar.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+Column {
+ width: 300
+
+ //! [1]
+ TabBar {
+ id: bar
+ width: parent.width
+ TabButton {
+ text: qsTr("Home")
+ }
+ TabButton {
+ text: qsTr("Discover")
+ }
+ TabButton {
+ text: qsTr("Activity")
+ }
+ }
+
+ StackLayout {
+ width: parent.width
+ currentIndex: bar.currentIndex
+ Item {
+ id: homeTab
+ }
+ Item {
+ id: discoverTab
+ }
+ Item {
+ id: activityTab
+ }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbutton.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbutton.qml
new file mode 100644
index 0000000000..e7240db4dc
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tabbutton.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+TabBar {
+ TabButton {
+ text: qsTr("Home")
+ }
+ TabButton {
+ text: qsTr("Discover")
+ }
+ TabButton {
+ text: qsTr("Activity")
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-custom.qml
new file mode 100644
index 0000000000..e4f1b397d4
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-custom.qml
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+TextArea {
+ id: control
+ placeholderText: qsTr("Enter description")
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ border.color: control.enabled ? "#21be2b" : "transparent"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-scrollable.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-scrollable.qml
new file mode 100644
index 0000000000..52d9996e9b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textarea-scrollable.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ width: 100
+ height: 100
+
+ Binding { target: view.ScrollBar.vertical; property: "active"; value: true }
+
+ //! [1]
+ ScrollView {
+ id: view
+ anchors.fill: parent
+
+ TextArea {
+ text: "TextArea\n...\n...\n...\n...\n...\n...\n"
+ }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-custom.qml
new file mode 100644
index 0000000000..8f1aba233e
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-custom.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+TextField {
+ id: control
+ placeholderText: qsTr("Enter description")
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ color: control.enabled ? "transparent" : "#353637"
+ border.color: control.enabled ? "#21be2b" : "transparent"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-disabled.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-disabled.qml
new file mode 100644
index 0000000000..3d92b64760
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-disabled.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+TextField {
+ width: 80
+ text: "Disabled"
+ enabled: false
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-focused.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-focused.qml
new file mode 100644
index 0000000000..f276198857
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-focused.qml
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+TextField {
+ width: 80
+ text: "Focused"
+ focus: true
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-normal.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-normal.qml
new file mode 100644
index 0000000000..c9208c0e8f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-textfield-normal.qml
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+TextField {
+ width: 80
+ text: "Normal"
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar-custom.qml
new file mode 100644
index 0000000000..2cb9d0c5c7
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar-custom.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+//! [file]
+ToolBar {
+ id: control
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: "#eeeeee"
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ anchors.bottom: parent.bottom
+ color: "transparent"
+ border.color: "#21be2b"
+ }
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ ToolButton {
+ text: qsTr("Undo")
+ }
+ ToolButton {
+ text: qsTr("Redo")
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar.qml
new file mode 100644
index 0000000000..52445d93d7
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbar.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+
+Item {
+ id: root
+ width: children[0].implicitWidth * 2
+ height: children[0].implicitHeight
+ Binding {
+ target: root.children[0]
+ property: "width"
+ value: root.width
+ }
+//! [1]
+ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ ToolButton {
+ text: qsTr("‹")
+ onClicked: stack.pop()
+ }
+ Label {
+ text: "Title"
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+ ToolButton {
+ text: qsTr("â‹®")
+ onClicked: menu.open()
+ }
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbutton-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbutton-custom.qml
new file mode 100644
index 0000000000..8eb27430da
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolbutton-custom.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+ToolButton {
+ id: control
+ text: qsTr("ToolButton")
+ width: 120
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ opacity: enabled ? 1.0 : 0.3
+ color: control.down ? "#17a81a" : "#21be2b"
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ color: Qt.darker("#33333333", control.enabled && (control.checked || control.highlighted) ? 1.5 : 1.0)
+ opacity: enabled ? 1 : 0.3
+ visible: control.down || (control.enabled && (control.checked || control.highlighted))
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator-custom.qml
new file mode 100644
index 0000000000..f630256dd9
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator-custom.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Window
+import QtQuick.Controls
+
+//! [file]
+ToolBar {
+ RowLayout {
+ anchors.fill: parent
+
+ ToolButton {
+ text: qsTr("Action 1")
+ }
+ ToolButton {
+ text: qsTr("Action 2")
+ }
+
+ ToolSeparator {
+ padding: vertical ? 10 : 2
+ topPadding: vertical ? 2 : 10
+ bottomPadding: vertical ? 2 : 10
+
+ contentItem: Rectangle {
+ implicitWidth: parent.vertical ? 1 : 24
+ implicitHeight: parent.vertical ? 24 : 1
+ color: "#c3c3c3"
+ }
+ }
+
+ ToolButton {
+ text: qsTr("Action 3")
+ }
+ ToolButton {
+ text: qsTr("Action 4")
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator.qml
new file mode 100644
index 0000000000..514b97fa68
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-toolseparator.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Window
+import QtQuick.Controls
+
+//! [1]
+ToolBar {
+ RowLayout {
+ anchors.fill: parent
+
+ ToolButton {
+ text: qsTr("Action 1")
+ }
+ ToolButton {
+ text: qsTr("Action 2")
+ }
+
+ ToolSeparator {}
+
+ ToolButton {
+ text: qsTr("Action 3")
+ }
+ ToolButton {
+ text: qsTr("Action 4")
+ }
+
+ ToolSeparator {}
+
+ ToolButton {
+ text: qsTr("Action 5")
+ }
+ ToolButton {
+ text: qsTr("Action 6")
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-custom.qml
new file mode 100644
index 0000000000..7b40c974b6
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-custom.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Item {
+ToolTip {
+ id: control
+ text: qsTr("A descriptive tool tip of what the button does")
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ color: "#21be2b"
+ }
+
+ background: Rectangle {
+ border.color: "#21be2b"
+ }
+}
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-hover.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-hover.qml
new file mode 100644
index 0000000000..6d1ee4c41b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-hover.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ hoverEnabled: true
+
+ ToolTip.delay: 1000
+ ToolTip.timeout: 5000
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("This tool tip is shown after hovering the button for a second.")
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-pressandhold.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-pressandhold.qml
new file mode 100644
index 0000000000..cea495538b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-pressandhold.qml
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [1]
+Button {
+ text: qsTr("Button")
+
+ ToolTip.visible: pressed
+ ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
+ ToolTip.text: qsTr("This tool tip is shown after pressing and holding the button down.")
+}
+//! [1]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-slider.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-slider.qml
new file mode 100644
index 0000000000..5f40822457
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip-slider.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+
+Item {
+ id: root
+ width: slider.width
+ height: slider.height * 2.0
+
+ Binding { target: slider.anchors; property: "centerIn"; value: root }
+ Binding { target: slider.anchors; property: "verticalCenterOffset"; value: slider.height / 2 }
+ Binding { target: slider; property: "pressed"; value: root.Window.active }
+
+ //! [1]
+ Slider {
+ id: slider
+ value: 0.5
+
+ ToolTip {
+ parent: slider.handle
+ visible: slider.pressed
+ text: slider.value.toFixed(1)
+ }
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip.qml
new file mode 100644
index 0000000000..72eaaba5fa
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tooltip.qml
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+
+Item {
+ id: root
+ width: 360
+ height: button.height * 2
+
+ property Button button: children[0]
+
+ Binding { target: root.button; property: "down"; value: root.Window.active }
+ Binding { target: root.button.anchors; property: "bottom"; value: root.bottom }
+ Binding { target: root.button.anchors; property: "horizontalCenter"; value: root.horizontalCenter }
+
+ //! [1]
+ Button {
+ text: qsTr("Save")
+
+ ToolTip.visible: down
+ ToolTip.text: qsTr("Save the active project")
+ }
+ //! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-custom.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-custom.qml
new file mode 100644
index 0000000000..ee637d23be
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-custom.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [file]
+import QtQuick
+import QtQuick.Controls
+
+Tumbler {
+ id: control
+ model: 15
+
+ background: Item {
+ Rectangle {
+ opacity: control.enabled ? 0.2 : 0.1
+ border.color: "#000000"
+ width: parent.width
+ height: 1
+ anchors.top: parent.top
+ }
+
+ Rectangle {
+ opacity: control.enabled ? 0.2 : 0.1
+ border.color: "#000000"
+ width: parent.width
+ height: 1
+ anchors.bottom: parent.bottom
+ }
+ }
+
+ delegate: Text {
+ text: qsTr("Item %1").arg(modelData + 1)
+ font: control.font
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ opacity: 1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)
+
+ required property var modelData
+ required property int index
+ }
+
+ Rectangle {
+ anchors.horizontalCenter: control.horizontalCenter
+ y: control.height * 0.4
+ width: 40
+ height: 1
+ color: "#21be2b"
+ }
+
+ Rectangle {
+ anchors.horizontalCenter: control.horizontalCenter
+ y: control.height * 0.6
+ width: 40
+ height: 1
+ color: "#21be2b"
+ }
+}
+//! [file]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-listView.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-listView.qml
new file mode 100644
index 0000000000..54ce78afd3
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-listView.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [contentItem]
+Tumbler {
+ id: tumbler
+
+ contentItem: ListView {
+ model: tumbler.model
+ delegate: tumbler.delegate
+
+ snapMode: ListView.SnapToItem
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: height / 2 - (height / tumbler.visibleItemCount / 2)
+ preferredHighlightEnd: height / 2 + (height / tumbler.visibleItemCount / 2)
+ clip: true
+ }
+}
+//! [contentItem]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-pathView.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-pathView.qml
new file mode 100644
index 0000000000..408b747920
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-pathView.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+
+//! [contentItem]
+Tumbler {
+ id: tumbler
+
+ contentItem: PathView {
+ id: pathView
+ model: tumbler.model
+ delegate: tumbler.delegate
+ clip: true
+ pathItemCount: tumbler.visibleItemCount + 1
+ preferredHighlightBegin: 0.5
+ preferredHighlightEnd: 0.5
+ dragMargin: width / 2
+
+ path: Path {
+ startX: pathView.width / 2
+ startY: -pathView.delegateHeight / 2
+ PathLine {
+ x: pathView.width / 2
+ y: pathView.pathItemCount * pathView.delegateHeight - pathView.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: tumbler.availableHeight / tumbler.visibleItemCount
+ }
+}
+//! [contentItem]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-timePicker.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-timePicker.qml
new file mode 100644
index 0000000000..d9edb2cb00
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-tumbler-timePicker.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [tumbler]
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+
+Rectangle {
+ width: frame.implicitWidth + 10
+ height: frame.implicitHeight + 10
+
+ function formatText(count, modelData) {
+ var data = count === 12 ? modelData + 1 : modelData;
+ return data.toString().length < 2 ? "0" + data : data;
+ }
+
+ FontMetrics {
+ id: fontMetrics
+ }
+
+ Component {
+ id: delegateComponent
+
+ Label {
+ text: formatText(Tumbler.tumbler.count, modelData)
+ opacity: 1.0 - Math.abs(Tumbler.displacement) / (Tumbler.tumbler.visibleItemCount / 2)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: fontMetrics.font.pixelSize * 1.25
+ }
+ }
+
+ Frame {
+ id: frame
+ padding: 0
+ anchors.centerIn: parent
+
+ Row {
+ id: row
+
+ Tumbler {
+ id: hoursTumbler
+ model: 12
+ delegate: delegateComponent
+ }
+
+ Tumbler {
+ id: minutesTumbler
+ model: 60
+ delegate: delegateComponent
+ }
+
+ Tumbler {
+ id: amPmTumbler
+ model: ["AM", "PM"]
+ delegate: delegateComponent
+ }
+ }
+ }
+}
+//! [tumbler]
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-accent.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-accent.qml
new file mode 100644
index 0000000000..f429359e4f
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-accent.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtQuick.Controls.Universal
+
+Pane {
+ padding: 10
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ highlighted: true
+ Universal.accent: Universal.Orange
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-background.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-background.qml
new file mode 100644
index 0000000000..558618e65e
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-background.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Universal
+
+Pane {
+ padding: 10
+
+//! [1]
+Pane {
+ Universal.background: Universal.Steel
+
+ Button {
+ text: qsTr("Button")
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-foreground.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-foreground.qml
new file mode 100644
index 0000000000..39a292d88b
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-foreground.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Universal
+
+Pane {
+ padding: 10
+
+//! [1]
+Button {
+ text: qsTr("Button")
+ Universal.foreground: Universal.Pink
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-theme.qml b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-theme.qml
new file mode 100644
index 0000000000..b55bf188bf
--- /dev/null
+++ b/src/quickcontrols2/doc/snippets/qtquickcontrols2-universal-theme.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Universal
+
+Pane {
+ padding: 10
+
+//! [1]
+Pane {
+ Universal.theme: Universal.Dark
+
+ Button {
+ text: qsTr("Button")
+ }
+}
+//! [1]
+}
diff --git a/src/quickcontrols2/doc/src/external-pages.qdoc b/src/quickcontrols2/doc/src/external-pages.qdoc
new file mode 100644
index 0000000000..0500579818
--- /dev/null
+++ b/src/quickcontrols2/doc/src/external-pages.qdoc
@@ -0,0 +1,36 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \externalpage https://doc.qt.io/qt-5/qtquickcontrols2-differences.html
+ \title Qt 5.15: Qt Quick Controls vs Qt Quick Controls 1
+*/
+
+/*!
+ \externalpage https://doc.qt.io/qtcreator/creator-project-creating.html#selecting-project-type
+ \title Qt Creator: Project Types
+*/
diff --git a/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc b/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc
new file mode 100644
index 0000000000..9fcf43e168
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/container-currentindex.qdocinc
@@ -0,0 +1,9 @@
+//! [file]
+When \1 is paired with another container such as \l \2, it is
+necessary to make a two-way binding between the
+\l {Container::}{currentIndex} property
+of each control. To do this without breaking bindings, avoid setting
+\c currentIndex directly, and instead use
+\l {Container::}{setCurrentIndex()}, for example.
+See \l {Managing the Current Index} for more information.
+//! [file]
diff --git a/src/quickcontrols2/doc/src/includes/customize-button-background.qdocinc b/src/quickcontrols2/doc/src/includes/customize-button-background.qdocinc
new file mode 100644
index 0000000000..0acad02d38
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/customize-button-background.qdocinc
@@ -0,0 +1,25 @@
+//! [file]
+\qml
+import QtQuick
+import QtQuick.Controls
+
+ApplicationWindow {
+ width: 400
+ height: 400
+ visible: true
+
+ Button {
+ id: button
+ text: "A Special Button"
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ color: button.down ? "#d6d6d6" : "#f6f6f6"
+ border.color: "#26282a"
+ border.width: 1
+ radius: 4
+ }
+ }
+}
+\endqml
+//! [file]
diff --git a/src/quickcontrols2/doc/src/includes/customizing-native-styles.qdocinc b/src/quickcontrols2/doc/src/includes/customizing-native-styles.qdocinc
new file mode 100644
index 0000000000..e1feacaa49
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/customizing-native-styles.qdocinc
@@ -0,0 +1,14 @@
+It is instead recommended to always base a customized control on top of a single style
+that is available on all platforms, e.g \l {Basic Style}, \l {Fusion Style}, \l {Imagine Style},
+\l {Material Style}, \l {Universal Style}. By doing so, you are guaranteed that it will
+always look the same, regardless of which style the application is run with. For example:
+
+\code
+ import QtQuick.Controls.Basic as Basic
+
+ Basic.SpinBox {
+ background: Rectangle { /* ... */ }
+ }
+\endcode
+
+\b {See also} \l {Styling Qt Quick Controls}
diff --git a/src/quickcontrols2/doc/src/includes/inputmethodhints.qdocinc b/src/quickcontrols2/doc/src/includes/inputmethodhints.qdocinc
new file mode 100644
index 0000000000..73710e1e15
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/inputmethodhints.qdocinc
@@ -0,0 +1,38 @@
+//! [flags]
+The value is a bit-wise combination of flags or \c Qt.ImhNone if no hints are set.
+
+Flags that alter behavior are:
+
+\list
+\li Qt.ImhHiddenText - Characters should be hidden, as is typically used when entering passwords.
+\li Qt.ImhSensitiveData - Typed text should not be stored by the active input method
+ in any persistent storage like predictive user dictionary.
+\li Qt.ImhNoAutoUppercase - The input method should not try to automatically switch to upper case
+ when a sentence ends.
+\li Qt.ImhPreferNumbers - Numbers are preferred (but not required).
+\li Qt.ImhPreferUppercase - Upper case letters are preferred (but not required).
+\li Qt.ImhPreferLowercase - Lower case letters are preferred (but not required).
+\li Qt.ImhNoPredictiveText - Do not use predictive text (i.e. dictionary lookup) while typing.
+
+\li Qt.ImhDate - The text editor functions as a date field.
+\li Qt.ImhTime - The text editor functions as a time field.
+\endlist
+
+Flags that restrict input (exclusive flags) are:
+
+\list
+\li Qt.ImhDigitsOnly - Only digits are allowed.
+\li Qt.ImhFormattedNumbersOnly - Only number input is allowed. This includes decimal point and minus sign.
+\li Qt.ImhUppercaseOnly - Only upper case letter input is allowed.
+\li Qt.ImhLowercaseOnly - Only lower case letter input is allowed.
+\li Qt.ImhDialableCharactersOnly - Only characters suitable for phone dialing are allowed.
+\li Qt.ImhEmailCharactersOnly - Only characters suitable for email addresses are allowed.
+\li Qt.ImhUrlCharactersOnly - Only characters suitable for URLs are allowed.
+\endlist
+
+Masks:
+
+\list
+\li Qt.ImhExclusiveInputMask - This mask yields nonzero if any of the exclusive flags are used.
+\endlist
+//! [flags]
diff --git a/src/quickcontrols2/doc/src/includes/qquickcombobox.qdocinc b/src/quickcontrols2/doc/src/includes/qquickcombobox.qdocinc
new file mode 100644
index 0000000000..5e19f5f1f4
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickcombobox.qdocinc
@@ -0,0 +1,6 @@
+//! [functions-after-component-completion]
+
+\note This function can only be used after
+\l {Component::completed()}{Component.completed()} is emitted for the ComboBox.
+
+//! [functions-after-component-completion]
diff --git a/src/quickcontrols2/doc/src/includes/qquickcontrol-background.qdocinc b/src/quickcontrols2/doc/src/includes/qquickcontrol-background.qdocinc
new file mode 100644
index 0000000000..02d92de07c
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickcontrol-background.qdocinc
@@ -0,0 +1,13 @@
+//! [notes]
+
+\note If the background item has no explicit size specified, it automatically
+ follows the control's size. In most cases, there is no need to specify
+ width or height for a background item.
+
+\note Most controls use the implicit size of the background item to calculate
+the implicit size of the control itself. If you replace the background item
+with a custom one, you should also consider providing a sensible implicit
+size for it (unless it is an item like \l Image which has its own implicit
+size).
+
+//! [notes]
diff --git a/src/quickcontrols2/doc/src/includes/qquickcontrol-focusreason.qdocinc b/src/quickcontrols2/doc/src/includes/qquickcontrol-focusreason.qdocinc
new file mode 100644
index 0000000000..b69e9e60ec
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickcontrol-focusreason.qdocinc
@@ -0,0 +1,15 @@
+This property holds the reason of the last focus change.
+
+\note This property does not indicate whether the control has \l {Item::activeFocus}
+ {active focus}, but the reason why the control either gained or lost focus.
+
+\value Qt.MouseFocusReason A mouse action occurred.
+\value Qt.TabFocusReason The Tab key was pressed.
+\value Qt.BacktabFocusReason A Backtab occurred. The input for this may include the Shift or Control keys; e.g. Shift+Tab.
+\value Qt.ActiveWindowFocusReason The window system made this window either active or inactive.
+\value Qt.PopupFocusReason The application opened/closed a pop-up that grabbed/released the keyboard focus.
+\value Qt.ShortcutFocusReason The user typed a label's buddy shortcut
+\value Qt.MenuBarFocusReason The menu bar took focus.
+\value Qt.OtherFocusReason Another reason, usually application-specific.
+
+\sa Item::activeFocus
diff --git a/src/quickcontrols2/doc/src/includes/qquickdial.qdocinc b/src/quickcontrols2/doc/src/includes/qquickdial.qdocinc
new file mode 100644
index 0000000000..3370b3d8f3
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickdial.qdocinc
@@ -0,0 +1,13 @@
+//! [inputMode]
+Dial supports three \l {inputMode}{input modes}: \c Dial.Circular,
+\c Dial.Horizontal and \c Dial.Vertical. The circular input mode operates on an
+absolute input system, where the position of the cursor within the dial
+directly reflects its value. The horizontal and vertical input modes use a
+relative input system, where changes in the cursor's position are "added" to
+the value of the dial.
+
+The following image illustrates the directions in which the various input modes
+track movement:
+
+\image qtquickcontrols2-dial-inputmode.png
+//! [inputMode]
diff --git a/src/quickcontrols2/doc/src/includes/qquickicon.qdocinc b/src/quickcontrols2/doc/src/includes/qquickicon.qdocinc
new file mode 100644
index 0000000000..eadaea5983
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickicon.qdocinc
@@ -0,0 +1,52 @@
+//! [grouped-properties]
+\table
+\header
+ \li Name
+ \li Description
+\row
+ \li name
+ \li This property holds the name of the icon to use.
+
+ The icon will be loaded from the platform theme. If the icon is found
+ in the theme, it will always be used; even if \l icon.source is also set.
+ If the icon is not found, \l icon.source will be used instead.
+
+ For more information on theme icons, see \l {QIcon::fromTheme()}.
+\row
+ \li source
+ \li This property holds the name of the icon to use.
+
+ The icon will be loaded as a regular image.
+
+ If \l icon.name is set and refers to a valid theme icon, it will always
+ be used instead of this property.
+\row
+ \li width
+ \li This property holds the width of the icon.
+
+ The icon's width will never exceed this value, though it will
+ shrink when necessary.
+\row
+ \li height
+ \li This property holds the height of the icon.
+
+ The icon's height will never exceed this value, though it will
+ shrink when necessary.
+\row
+ \li color
+ \li This property holds the color of the icon.
+
+ The icon is tinted with the specified color, unless the color is
+ set to \c "transparent".
+
+\row
+ \li cache
+ \li This property specifies whether the icon should be cached.
+
+ The default value is true.
+
+ For more information, see \l {Image::}{cache}.
+
+ This property was introduced in QtQuick.Controls 2.13.
+\endtable
+//! [grouped-properties]
diff --git a/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc b/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc
new file mode 100644
index 0000000000..36297e9080
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickimaginestyle.qdocinc
@@ -0,0 +1,59 @@
+//! [conf]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c Path
+ \li Specifies the \l {imagine-path-attached-prop}{path} to the directory that contains
+ the Imagine style assets. If not specified, the built-in assets are used.
+
+ For example, to specify a path to a directory stored in the
+ \l {The Qt Resource System}{resource system}:
+
+ \badcode
+ [Imagine]
+ Path=:/imagine-assets
+ \endcode
+
+ To specify a relative path to a local directory:
+
+ \badcode
+ [Imagine]
+ Path=imagine-assets
+ \endcode
+
+ \note Due to a technical limitation, the path should not be named
+ \e "imagine" if it is relative to the \c qtquickcontrols2.conf file.
+\endtable
+//! [conf]
+
+//! [env]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c QT_QUICK_CONTROLS_IMAGINE_PATH
+ \li Specifies the path to the directory that contains the Imagine style assets.
+ If not specified, the built-in assets are used.
+
+ For example, to specify a path to a directory stored in the
+ \l {The Qt Resource System}{resource system}:
+
+ \badcode
+ QT_QUICK_CONTROLS_IMAGINE_PATH=:/imagine-assets
+ \endcode
+
+ To specify a relative path to a local directory:
+
+ \badcode
+ QT_QUICK_CONTROLS_IMAGINE_PATH=imagine-assets
+ \endcode
+
+ \note Due to a technical limitation, the path should not be named
+ \e "imagine" if it is relative to the \c qtquickcontrols2.conf file.
+ \li \c QT_QUICK_CONTROLS_IMAGINE_SMOOTH
+ \li Set to \c 1 to enable smooth scaling for 9-patch images.
+\endtable
+//! [env]
diff --git a/src/quickcontrols2/doc/src/includes/qquickmaterialstyle.qdocinc b/src/quickcontrols2/doc/src/includes/qquickmaterialstyle.qdocinc
new file mode 100644
index 0000000000..72c97bb639
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickmaterialstyle.qdocinc
@@ -0,0 +1,79 @@
+//! [conf]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c Theme
+ \li Specifies the default \l {material-theme-attached-prop}{Material theme}.
+ The value can be one of the available themes, for example \c "Dark".
+ \row
+ \li \c Variant
+ \li Specifies the Material variant. The Material Design has two
+ variants: a normal variant designed for touch devices, and a dense
+ variant for desktop. The dense variant uses smaller sizes for
+ controls and their fonts.
+
+ The value can be \c "Normal" or \c "Dense".
+ \row
+ \li \c Accent
+ \li Specifies the default \l {material-accent-attached-prop}{Material accent color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Material colors}, for example \c "Teal".
+ \row
+ \li \c Primary
+ \li Specifies the default \l {material-primary-attached-prop}{Material primary color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Material colors}, for example \c "BlueGrey".
+ \row
+ \li \c Foreground
+ \li Specifies the default \l {material-foreground-attached-prop}{Material foreground color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Material colors},
+ for example \c "Brown".
+ \row
+ \li \c Background
+ \li Specifies the default \l {material-background-attached-prop}{Material background color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Material colors},
+ for example \c "Grey".
+\endtable
+//! [conf]
+
+//! [env]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_THEME
+ \li Specifies the default \l {material-theme-attached-prop}{Material theme}.
+ The value can be one of the available themes, for example \c "Dark".
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_VARIANT
+ \li Specifies the Material variant. The Material Design has two
+ variants: a normal variant designed for touch devices, and a dense
+ variant for desktop. The dense variant uses smaller sizes for
+ controls and their fonts.
+
+ The value can be \c "Normal" or \c "Dense".
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_ACCENT
+ \li Specifies the default \l {material-accent-attached-prop}{Material accent color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Material colors}, for example \c "Teal".
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_PRIMARY
+ \li Specifies the default \l {material-primary-attached-prop}{Material primary color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Material colors}, for example \c "BlueGrey".
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_FOREGROUND
+ \li Specifies the default \l {material-foreground-attached-prop}{Material foreground color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Material colors},
+ for example \c "Brown".
+ \row
+ \li \c QT_QUICK_CONTROLS_MATERIAL_BACKGROUND
+ \li Specifies the default \l {material-background-attached-prop}{Material background color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Material colors},
+ for example \c "Grey".
+\endtable
+//! [env]
diff --git a/src/quickcontrols2/doc/src/includes/qquickoverlay-popup-parent.qdocinc b/src/quickcontrols2/doc/src/includes/qquickoverlay-popup-parent.qdocinc
new file mode 100644
index 0000000000..5562f6a039
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickoverlay-popup-parent.qdocinc
@@ -0,0 +1,20 @@
+The following example uses the attached \l {Overlay::overlay}{Overlay.overlay}
+property to position a popup in the center of the window, despite the position
+of the button that opens the popup:
+
+\code
+Button {
+ onClicked: popup.open()
+
+ Popup {
+ id: popup
+
+ parent: Overlay.overlay
+
+ x: Math.round((parent.width - width) / 2)
+ y: Math.round((parent.height - height) / 2)
+ width: 100
+ height: 100
+ }
+}
+\endcode
diff --git a/src/quickcontrols2/doc/src/includes/qquickpopup-padding.qdocinc b/src/quickcontrols2/doc/src/includes/qquickpopup-padding.qdocinc
new file mode 100644
index 0000000000..31f5d2db02
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickpopup-padding.qdocinc
@@ -0,0 +1,10 @@
+//! [padding]
+
+The padding properties are used to control the geometry of the
+\l {contentItem}{content item}.
+
+Popup uses the same approach to padding as \l {Control::padding}{Control}.
+For a visual explanation of the padding system, see the \l {Control Layout}
+section of the documentation.
+
+//! [padding]
diff --git a/src/quickcontrols2/doc/src/includes/qquickstackview.qdocinc b/src/quickcontrols2/doc/src/includes/qquickstackview.qdocinc
new file mode 100644
index 0000000000..20c9bdc369
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickstackview.qdocinc
@@ -0,0 +1,5 @@
+//! [pop-ownership]
+Only items that StackView created itself (from a \l Component or \l [QML]
+url) will be destroyed when popped. See \l {Item Ownership} for more
+information.
+//! [pop-ownership]
diff --git a/src/quickcontrols2/doc/src/includes/qquickswipedelegate-interaction.qdocinc b/src/quickcontrols2/doc/src/includes/qquickswipedelegate-interaction.qdocinc
new file mode 100644
index 0000000000..05aeadb654
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickswipedelegate-interaction.qdocinc
@@ -0,0 +1,5 @@
+Both interactive and non-interactive items can be used here. Normal
+event handling rules apply; if an interactive control like \l Button
+is used, interaction signals of SwipeDelegate such as
+\l {AbstractButton::}{clicked()} will not get emitted if the button
+is clicked.
diff --git a/src/quickcontrols2/doc/src/includes/qquickswitch.qdocinc b/src/quickcontrols2/doc/src/includes/qquickswitch.qdocinc
new file mode 100644
index 0000000000..985f85d979
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickswitch.qdocinc
@@ -0,0 +1,28 @@
+//! [position]
+
+This property holds the logical position of the thumb indicator.
+
+The position is expressed as a fraction of the indicator's size, in the range
+\c 0.0 - \c 1.0. The position can be used for example to determine whether
+the thumb has been dragged past the halfway point. For visualizing a thumb
+indicator, the right-to-left aware \l visualPosition should be used instead.
+
+\sa visualPosition
+
+//! [position]
+
+
+//! [visualPosition]
+
+This property holds the visual position of the thumb indicator.
+
+The position is expressed as a fraction of the indicator's size, in the range
+\c 0.0 - \c 1.0. When the control is \l {Control::mirrored}{mirrored}, the
+value is equal to \c {1.0 - position}. This makes the value suitable for
+visualizing the thumb indicator taking right-to-left support into account.
+In order to for example determine whether the thumb has been dragged past
+the halfway point, the logical \l position should be used instead.
+
+\sa position
+
+//! [visualPosition]
diff --git a/src/quickcontrols2/doc/src/includes/qquicktooltip.qdocinc b/src/quickcontrols2/doc/src/includes/qquicktooltip.qdocinc
new file mode 100644
index 0000000000..0046a2d8b0
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquicktooltip.qdocinc
@@ -0,0 +1,6 @@
+//! [customize-note]
+\note to customize the \l {Attached Tool Tips}{attached ToolTip}, it
+must be provided as part of
+\l {Creating a Custom Style}{your own style}. To do a one-off
+customization of a \c ToolTip, see \l {Custom Tool Tips}.
+//! [customize-note]
diff --git a/src/quickcontrols2/doc/src/includes/qquickuniversalstyle.qdocinc b/src/quickcontrols2/doc/src/includes/qquickuniversalstyle.qdocinc
new file mode 100644
index 0000000000..a7ecbaef09
--- /dev/null
+++ b/src/quickcontrols2/doc/src/includes/qquickuniversalstyle.qdocinc
@@ -0,0 +1,53 @@
+//! [conf]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c Theme
+ \li Specifies the default \l {universal-theme-attached-prop}{Universal theme}.
+ The value can be one of the available themes, for example \c "Dark".
+ \row
+ \li \c Accent
+ \li Specifies the default \l {universal-accent-attached-prop}{Universal accent color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Universal colors}, for example \c "Violet".
+ \row
+ \li \c Foreground
+ \li Specifies the default \l {universal-foreground-attached-prop}{Universal foreground color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Universal colors},
+ for example \c "Brown".
+ \row
+ \li \c Background
+ \li Specifies the default \l {universal-background-attached-prop}{Universal background color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Universal colors},
+ for example \c "Steel".
+\endtable
+//! [conf]
+
+//! [env]
+\table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c QT_QUICK_CONTROLS_UNIVERSAL_THEME
+ \li Specifies the default \l {universal-theme-attached-prop}{Universal theme}.
+ The value can be one of the available themes, for example \c "Dark".
+ \row
+ \li \c QT_QUICK_CONTROLS_UNIVERSAL_ACCENT
+ \li Specifies the default \l {universal-accent-attached-prop}{Universal accent color}.
+ The value can be any \l {colorbasictypedocs}{color}, but it is recommended to use
+ one of the \l {pre-defined Universal colors}, for example \c "Violet".
+ \row
+ \li \c QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND
+ \li Specifies the default \l {universal-foreground-attached-prop}{Universal foreground color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Universal colors},
+ for example \c "Brown".
+ \row
+ \li \c QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND
+ \li Specifies the default \l {universal-background-attached-prop}{Universal background color}.
+ The value can be any \l {colorbasictypedocs}{color}, or one of the \l {pre-defined Universal colors},
+ for example \c "Steel".
+\endtable
+//! [env]
diff --git a/src/quickcontrols2/doc/src/qt6-changes.qdoc b/src/quickcontrols2/doc/src/qt6-changes.qdoc
new file mode 100644
index 0000000000..61b80b3839
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qt6-changes.qdoc
@@ -0,0 +1,305 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols-changes-qt6.html
+ \title Changes to Qt Quick Controls
+ \ingroup changes-qt-5-to-6
+ \brief Migrate Qt Quick Controls to Qt 6.
+
+ Qt 6 is a result of the conscious effort to make the framework more
+ efficient and easy to use.
+
+ We try to maintain compatibility for all the public APIs in each release.
+ Some changes were inevitable in an effort to make Qt a better framework.
+
+ In this topic we summarize those changes in Qt Quick Controls, and provide
+ guidance to handle them.
+
+ \section1 Migrating from Qt Quick Controls 1
+
+ Qt Quick Controls 1 was deprecated in Qt 5.11 and is removed from
+ Qt 6.0. Use Qt Quick Controls (previously known as Qt Quick Controls 2)
+ instead. For more information, refer to the
+ \l{Qt 5.15: Qt Quick Controls vs Qt Quick Controls 1} topic in the Qt 5
+ documentation.
+
+ \section1 Type registration changes
+
+ Qt Quick Controls has undergone some large, mostly internal changes in Qt
+ 6. By making use of the improved type registration introduced in Qt 5.15,
+ we pave the way for compilation of the module's QML files to C++ and enable
+ tooling to become more effective. In particular, Qt Creator's QML code
+ model should have a more complete picture of types, making its completion
+ and error checking of Qt Quick Controls code more reliable. Static analysis
+ tools like qmllint and qmlformat also benefit by becoming aware of the
+ types that are now declared at compile time in C++.
+
+ As a result of these changes, some things are done a little differently.
+
+ \section2 Custom styles are now proper QML modules
+
+ To enable compile time type registration, each Qt Quick Controls style is
+ now a proper QML module. Previously, a single \c Button.qml was sufficient
+ to create your own style. While convenient, this required some non-standard
+ API, which in turn required adaptation in tooling like Qt Designer.
+
+ Now, all QML types that a style implements must be declared in that style's
+ qmldir file:
+
+ \code
+ module MyStyle
+ Button 1.0 Button.qml
+ \endcode
+
+ \omit
+ TODO: Once we have documentation for the CMake function qt6_add_qml_module,
+ this would be a good place to link to it, stating that you don't have to
+ manually write the qmldir files.
+ \endomit
+
+ By unifying this with the rest of the QML world, styles become more
+ familiar to developers and hopefully easier to understand for beginners. As
+ a consequence, the following API had to be removed:
+
+ \list
+ \li QQuickStyle::addStylePath()
+ \li QQuickStyle::availableStyles()
+ \li QQuickStyle::path()
+ \li QQuickStyle::stylePathList()
+ \li QT_QUICK_CONTROLS_STYLE_PATH
+ \endlist
+
+ Now that the styles are required to be found in the QML engine's import
+ path like any other QML module, it is no longer necessary or possible to
+ support this API.
+
+ \section3 Style names
+
+ In addition, there is now only one valid, case-sensitive form for style
+ names: "Material", "MyStyle", and so on. That is: the style name must
+ exactly match the name of the QML module. This also applies to file
+ selectors, where previously, all style names were lower case. For example,
+ where the following was a valid structure for a Qt 5 project:
+
+ \badcode
+ MyProject
+ ├── main.qml
+ ├── HomePage.qml
+ └── +material
+ └───HomePage.qml
+ \endcode
+
+ In Qt 6, \c +material becomes \c +Material:
+
+ \badcode
+ MyProject
+ ├── main.qml
+ ├── HomePage.qml
+ └── +Material
+ └───HomePage.qml
+ \endcode
+
+ All of the existing ways to \l {Using Styles in Qt Quick Controls}{run an
+ application with a specific style} are still supported.
+
+ \section2 Runtime and compile time style selection
+
+ Importing a style now has extra meaning due to the way that imports work
+ internally. Previously, importing \c QtQuick.Controls would register the
+ control types from the current style with the QML engine:
+
+ \qml
+ import QtQuick.Controls
+ \endqml
+
+ We refer to this as runtime style selection, as the style is selected at
+ runtime.
+
+ Explicitly importing \c QtQuick.Controls.Material would then simply expose
+ any extra API provided by that style (for example, the attached Material
+ type):
+
+ \qml
+ import QtQuick.Controls.Material
+ \endqml
+
+ Now, explicitly importing a style does both.
+
+ This effectively means that the control types (like Button) from the last
+ imported style will be used. We refer to this as compile time style
+ selection.
+
+ This has implications for existing code. Namely, if your application
+ supports more than one style, move these imports into their own QML files
+ that are file-selected.
+
+ For example, if you have the following \c main.qml:
+
+ \qml
+ import QtQuick.Controls
+ import QtQuick.Controls.Material
+ import QtQuick.Controls.Universal
+
+ ApplicationWindow {
+ width: 600
+ height: 400
+ visible: true
+
+ Material.theme: darkMode ? Material.Dark : Material.Light
+ Universal.theme: darkMode ? Universal.Dark : Universal.Light
+
+ // Child items, etc.
+ }
+ \endqml
+
+ You can move the common code into a "base" component:
+
+ \qml
+ // MainWindow.qml
+
+ import QtQuick.Controls
+
+ ApplicationWindow {}
+ \endqml
+
+ Then, add a \c +Material subdirectory, and in it, add the Material-specific code into \c MainWindow.qml:
+
+ \qml
+ // +Material/MainWindow.qml
+
+ import QtQuick.Controls.Material
+
+ ApplicationWindow {
+ Material.theme: darkMode ? Material.Dark : Material.Light
+ }
+ \endqml
+
+ Do the same for Universal:
+
+ \qml
+ // +Universal/MainWindow.qml
+
+ import QtQuick.Controls.Universal
+
+ ApplicationWindow {
+ Universal.theme: darkMode ? Universal.Dark : Universal.Light
+ }
+ \endqml
+
+ Then, in \c main.qml:
+
+ \qml
+ import QtQuick.Controls
+
+ MainWindow {
+ width: 600
+ height: 400
+ visible: true
+
+ // Child items, etc.
+ }
+ \endqml
+
+ See also: \l {Using File Selectors with Qt Quick Controls}.
+
+ \section1 Default Style
+
+ The Default style was renamed to "Basic", as it is no longer the default
+ style. Instead, the default style is now chosen based on the platform
+ that Qt was built for:
+
+ \list
+ \li Android: \l {Material Style}
+ \li Linux: \l {Fusion Style}
+ \li macOS: \l {macos Style}
+ \li Windows: \l {Windows Style}
+ \li All other platforms: \l {Basic Style}
+ \endlist
+
+ Therefore, applications that didn't specify a style in Qt 5 and have customized
+ controls should \l {Using Styles in Qt Quick Controls}{explicitly specify}
+ the Basic style in Qt 6 to ensure that those controls look and behave as
+ they did with Qt 5.
+
+ \section1 Palette
+
+ The palette API was moved to QQuickItem. The various APIs that use palettes
+ in Qt Quick Controls are unchanged.
+
+ \section1 Controls
+
+ \section2 Changes to ApplicationWindow
+
+ The deprecated overlay properties and attached API were removed. Use the
+ \l Overlay attached type instead.
+
+ \section2 Changes to ComboBox
+
+ The \l {ComboBox::}{pressed} property is now read-only. To modify the
+ visual pressed state of a ComboBox, use the \l {ComboBox::}{down} property
+ instead.
+
+ \section2 Changes to Container
+
+ The deprecated \c removeItem(var) function was removed.
+ \l {Container::}{removeItem(Item)} or \l {Container::}{takeItem(int)} can
+ be used instead.
+
+ \section2 Changes to Dialog
+
+ \l {Dialog}'s \l {Dialog::}{accepted()} and \l {Dialog::}{rejected()}
+ signals are now emitted before \l {Popup::}{closed()} when calling
+ \l {Dialog::}{done()}, \l {Dialog::}{accept()} and \l {Dialog::}{reject()}.
+
+ \section2 Changes to Menu
+
+ The deprecated \c removeItem(var) function was removed.
+ \l {Menu::}{removeItem(Item)} or \l {Menu::}{takeItem(int)} can be used
+ instead.
+
+ \section2 Changes to ToolTip
+
+ \l {ToolTip}'s timeout now begins only after \l {Popup::}{opened()} has
+ been emitted. This results in tooltips with enter transitions being visible
+ for the entire duration of the timeout property. This means that they are
+ visible slightly longer than they were before, so it may be worthwhile to
+ visually check tooltips in your application and adjust timeouts if
+ necessary.
+
+ \section2 Changes to StackView
+
+ The StackView.Transition enum value was deprecated. The operation argument
+ can be omitted in order to use the default transition for any given
+ operation.
+
+ \section2 Changes to Tumbler
+
+ \l {Item::}{implicitWidth} and \l {Item::}{implicitHeight} must now be
+ provided for \l {Tumbler}'s \l {Control::}{contentItem}, making it
+ consistent with all other controls.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-basic.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-basic.qdoc
new file mode 100644
index 0000000000..ee8d3ce4dd
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-basic.qdoc
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-basic.html
+ \title Basic Style
+
+ The Basic style is a basic all-round style.
+
+ The Basic style is a simple and light-weight style that offers the maximum
+ performance for Qt Quick Controls. It is built with a minimal amount of Qt
+ Quick primitives, and keeps animations and transitions to the minimum.
+
+ \image qtquickcontrols2-basic.png
+
+ The style is selected by default when running Qt Quick Controls applications.
+ It is built into the module's resources, so by default it is shipped with
+ any application that depends on the Qt Quick Controls module
+
+ \note The Basic style is used as a fallback for other styles. If a style
+ does not implement a certain control, the Basic style implementation of
+ that control is selected.
+
+ \b {See also} \l {Material Style}, \l {Universal Style}
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-buttons.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-buttons.qdoc
new file mode 100644
index 0000000000..6a4c592609
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-buttons.qdoc
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-buttons.html
+ \title Button Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for button controls
+
+ Qt Quick Controls offers a selection of button-like controls.
+
+ \annotatedlist qtquickcontrols2-buttons
+
+ Each type of button has its own specific use case. The following
+ sections offer guidelines for choosing the appropriate type of button,
+ depending on the use case.
+
+ \section1 Button Control
+
+ \l Button is a clickable control that starts an action, or opens or
+ closes a popup. A button usually has a text label but it can also
+ contain an icon.
+
+ Button is a very suitable control when a popup or dialog needs
+ to perform an action. The most common examples are Apply, Cancel,
+ Save, Close and Help.
+
+ \image qtquickcontrols2-button.gif
+
+ Recommendations:
+
+ \list
+ \li The button's text should be a verb describing the action, or a noun matching
+ the title of the popup that will be opened.
+ \li Don't use a button to set state. \l Switch is more suitable for that.
+ \li Use the default font unless you have UI guidelines specifying otherwise.
+ \li If the text is localized, consider the influence of a longer text on the layout.
+ \endlist
+
+ \b {See also} \l Button and \l AbstractButton
+
+ \section1 CheckBox Control
+
+ \image qtquickcontrols2-checkbox.gif
+
+ \l CheckBox is used to build multi-selection option lists. Any number of
+ options can be selected, including none, but the options should
+ not be mutually exclusive.
+
+ Use a single CheckBox for a yes/no choice, such as when you have
+ to accept the terms of service agreement in a form.
+
+ For a single yes/no choice, it is also possible to use a switch. If the choice
+ concerns an option, it is best to use a CheckBox. If it concerns action to
+ be taken, a switch is recommended.
+
+ When options can be grouped, you can use a partially checked CheckBox to
+ represent the whole group. Use the checkbox's
+ \l {CheckBox::checkState}{partially checked state} when a user selects
+ some, but not all, sub-items in the group.
+
+ The three availables check states are: checked, partially checked and
+ unchecked.
+
+ The checkable options are often listed vertically.
+
+ Recommendations:
+ \list
+ \li The checkbox label should be a statement that the check mark makes true,
+ and that the absence of a check mark makes false.
+ \li The checkbox label should not contain a negative statement.
+ \li Use the default font, unless you have UI guidelines specifying otherwise.
+ \li If the text is localized, consider the influence of a longer text on the layout.
+ \endlist
+
+ \b {See also} \l CheckBox
+
+ \section1 DelayButton Control
+
+ \l DelayButton is a button that incorporates a delay before triggering an action.
+ This delay prevents accidental presses.
+
+ \image qtquickcontrols2-delaybutton.gif
+
+ Recommendations:
+ \list
+ \li Use in touch user interfaces.
+ \li Use for actions that must be triggered with care.
+ \endlist
+
+ \b {See also} \l Button and \l AbstractButton
+
+ \section1 RadioButton Control
+
+ \image qtquickcontrols2-radiobutton.gif
+
+ \l RadioButton is used to select only one option from a set of options.
+ Selecting one option automatically deselects the one selected before.
+
+ If there are only two mutually exclusive options, combine them into a
+ single checkbox or a switch.
+
+ Recommendations:
+
+ \list
+ \li Limit the label text to one line.
+ \li Ensure that a sensible default option is checked.
+ \li List RadioButton options vertically.
+ \li If the text is localized, consider the influence of a longer text on the layout.
+ \li Use the default font, unless you have UI guidelines that specify otherwise.
+ \li Just like with CheckBox, do not make the list too large.
+ \li In order to avoid confusion, do not put two groups of radio buttons next to each
+ other.
+ \endlist
+
+ \b {See also} \l RadioButton
+
+ \section1 RoundButton Control
+
+ \l RoundButton is a clickable control that starts an action, or opens or
+ closes a popup. A round button with a square image icon or one-letter font
+ icon is circular. A circular RoundButton takes less space than a normal
+ \l Button, and can also be used as a floating action button.
+
+ \image qtquickcontrols2-roundbutton.png
+
+ Recommendations:
+
+ \list
+ \li Keep labels short and concise.
+ \li If the text is localized, consider the influence of a longer text on the layout.
+ \endlist
+
+ \b {See also} \l RoundButton
+
+ \section1 Switch Control
+
+ \image qtquickcontrols2-switch.png
+
+ \l Switch represents a physical switch that allows users to choose between an "on"
+ or "off" state.
+ Use a switch for binary operations that take effect immediately after it has been
+ switched on. For example, a switch to turn WIFI on or off.
+
+ Recommendations:
+
+ \list
+ \li Keep labels short and concise.
+ \li If the text is localized, consider the influence of a longer text on the layout.
+ \endlist
+
+ \b {See also} \l Switch
+
+ \section1 ToolButton Control
+
+ \image qtquickcontrols2-toolbutton.png
+
+ \l ToolButton is nearly identical to \l Button, but it has a graphical
+ appearance that makes it more suitable for insertion into a \l ToolBar.
+
+ \b {See also} \l ToolButton
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-configuration.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-configuration.qdoc
new file mode 100644
index 0000000000..8ac2b2759a
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-configuration.qdoc
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-configuration.html
+ \keyword Qt Quick Controls Configuration File
+ \title Qt Quick Controls Configuration File
+ \keyword Qt Quick Controls 2 Configuration File
+
+ Qt Quick Controls support a special configuration file, \c qtquickcontrols2.conf,
+ which is built into an application's resources.
+
+ The configuration file can specify the preferred style and certain style-specific
+ attributes. The following example specifies that the preferred style is the \l {Material style}.
+ Furthermore, when the application is run with the Material style, its theme is light and the
+ accent and primary colors are teal and blue grey, respectively. However, if the application
+ is run with the \l {Universal style} instead, the accent color is red and the appropriate theme
+ is chosen based on the system theme colors.
+
+ \code
+ [Controls]
+ Style=Material
+
+ [Universal]
+ Theme=System
+ Accent=Red
+
+ [Material]
+ Theme=Light
+ Accent=Teal
+ Primary=BlueGrey
+ \endcode
+
+ It is possible to specify a custom location for the configuration file with
+ the \l {Supported Environment Variables in Qt Quick Controls}
+ {QT_QUICK_CONTROLS_CONF} environment variable.
+
+ \section1 Controls Section
+
+ The following values can be specified in a \c Controls section of the
+ configuration file:
+
+ \table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c Style
+ \li Specifies the style to run the application with.
+ The value can be the name of one of the \l {Available Styles}{built-in styles}
+ or a \l {Creating a Custom Style}{custom style}.
+ \row
+ \li \c FallbackStyle
+ \li Specifies the style to use for controls that are not implemented.
+ The style must be one of the \l {Available Styles}{built-in styles}.
+ By default, the \l {Basic Style}{Basic} style is used.
+ \endtable
+
+ \section1 Imagine Section
+
+ The following table lists values that can be used to configure the
+ \l {Imagine style} in an \c Imagine section of the configuration file:
+
+ \include qquickimaginestyle.qdocinc conf
+
+ \section1 Material Section
+
+ The following table lists values that can be used to configure the
+ \l {Material style} in a \c Material section of the configuration file:
+
+ \include qquickmaterialstyle.qdocinc conf
+
+ \section1 Universal Section
+
+ The following table lists values that can be used to configure the
+ \l {Universal style} in a \c Universal section of the configuration file:
+
+ \include qquickuniversalstyle.qdocinc conf
+
+ \section1 Font Configuration
+
+ The default \l {Control::font}{font} can be specified in a \c Font sub-group
+ in each style's section in the configuration file. The \c Font sub-group can
+ be defined in two alternative ways:
+
+ \code
+ [Basic]
+ Font\Family=Open Sans
+ Font\PixelSize=20
+
+ [Material\Font]
+ Family=Open Sans
+ PixelSize=20
+ \endcode
+
+ Supported font attributes:
+ \table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c Family
+ \li The \l {QFont::family}{font family}.
+ \row
+ \li \c PointSize
+ \li The \l {QFont::pointSizeF}{point size}.
+ \row
+ \li \c PixelSize
+ \li The \l {QFont::pixelSize}{pixel size}.
+ \row
+ \li \c StyleHint
+ \li The \l {QFont::styleHint}{style hint}.
+ Available values: \c SansSerif, \c Helvetica, \c Serif, \c Times, \c TypeWriter, \c Courier,
+ \c OldEnglish, \c Decorative, \c Monospace, \c Fantasy, \c Cursive.
+ \row
+ \li \c Weight
+ \li The \l {QFont::}{weight}. Qt uses a weighting scale from \c 1 to \c 1000 compatible with OpenType. A weight of \c 1 will be thin,
+ whilst \c 1000 will be extremely black.
+ Available pre-defined weights: \c Thin (100), \c ExtraLight (200), \c Light (300), \c Normal (400),
+ \c Medium (500), \c DemiBold (600), \c Bold (700), \c ExtraBold (800),
+ \c Black (900).
+ \row
+ \li \c Style
+ \li The \l {QFont::}{style}.
+ Available values: \c StyleNormal, \c StyleItalic, \c StyleOblique.
+ \endtable
+
+ \section1 Palette Configuration
+
+ The default \c palette can be configured for each style using the
+ \c Palette sub-group in the configuration file. The \c Palette sub-group can be
+ defined in two alternative ways:
+
+ \code
+ [Fusion]
+ Palette\Window=#dedede
+ Palette\WindowText=#212121
+ \endcode
+
+ or:
+ \code
+ [Fusion\Palette]
+ Window=#dedede
+ WindowText=#212121
+ \endcode
+
+ See \l [QtQuick]{Palette} QML type for more information.
+
+ \section1 Using the Configuration File in a Project
+
+ In order to make it possible for Qt Quick Controls to find the configuration file,
+ it must be built into application's resources using the \l {The Qt Resource System}.
+ Here's an example \c .qrc file:
+
+ \code
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource prefix="/">
+ <file>qtquickcontrols2.conf</file>
+ </qresource>
+ </RCC>
+ \endcode
+
+ \note Qt Quick Controls uses a file selector to load the configuration file. It
+ is possible to provide a different configuration file for different platforms and
+ locales. See \l QFileSelector documentation for more details.
+
+ Finally, the \c .qrc file must be listed in the application's \c .pro file so that
+ the build system knows about it. For example:
+
+ \code
+ RESOURCES = application.qrc
+ \endcode
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \li \l{Supported Environment Variables in Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-containers.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-containers.qdoc
new file mode 100644
index 0000000000..81e24c2698
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-containers.qdoc
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-containers.html
+ \title Container Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for container controls
+
+ Qt Quick Controls offers a selection of container-like controls.
+
+ \annotatedlist qtquickcontrols2-containers
+
+ Each type of container can be used to group a set of controls together.
+ The following sections offer guidelines for choosing the appropriate type
+ of container, depending on the use case.
+
+ \section1 ApplicationWindow Control
+
+ \image qtquickcontrols2-applicationwindow-wireframe.png
+
+ \l ApplicationWindow creates the root window of an application, and makes
+ it easy to add an optional header and footer to that window.
+
+ \section1 Frame Control
+
+ \image qtquickcontrols2-frame.png
+
+ \l Frame is used to layout a logical group of controls together, within
+ a visual frame.
+
+ \section1 GroupBox Control
+
+ \image qtquickcontrols2-groupbox.png
+
+ \l GroupBox is used to layout a logical group of controls together,
+ within a titled visual frame.
+
+ \section1 Page Control
+
+ \image qtquickcontrols2-page-wireframe.png
+
+ \l Page provides page-specific header and footer items.
+ It is perfectly possible to use ApplicationWindow for setting the header
+ and the footer, but if you have a header and footer which varies per
+ screen, then it is better to use \l Page.
+
+ \section1 Pane Control
+
+ \image qtquickcontrols2-pane.png
+
+ \l Pane provides a background color that matches with the application
+ style and theme. Pane does not provide a layout of its own, but requires
+ you to position its contents, for instance by using a \l RowLayout or
+ a \l ColumnLayout.
+
+ \section1 ScrollView Control
+
+ \image qtquickcontrols2-scrollview-wireframe.png
+
+ \l ScrollView provides scrolling for user-defined content.
+
+ \section1 StackView Control
+
+ \image qtquickcontrols2-stackview-wireframe.png
+
+ \l StackView organizes content pages into a stack using a last-in-first-out
+ principle: the last item to be "pushed" onto the stack is the first one to
+ be removed, and the top-most item is always the one that is visible.
+
+ \section1 SwipeView Control
+
+ \image qtquickcontrols2-swipeview-wireframe.png
+
+ \l SwipeView organizes content pages into a swipable strip.
+
+ \section1 TabBar Control
+
+ \image qtquickcontrols2-tabbar-wireframe.png
+
+ \l TabBar organizes content pages into tabs.
+
+ \section1 ToolBar Control
+
+ \image qtquickcontrols2-toolbar.png
+
+ \l ToolBar is a container of application-wide and context-sensitive
+ actions and controls.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-cppclasses.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-cppclasses.qdoc
new file mode 100644
index 0000000000..293ac6de4e
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-cppclasses.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \module QtQuickControls2
+ \keyword Qt Quick Controls C++ Classes
+ \title Qt Quick Controls C++ Classes
+ \keyword Qt Quick Controls 2 C++ Classes
+ \ingroup modules
+ \qtcmakepackage QuickControls2
+ \qtvariable quickcontrols2
+
+ \brief Provides classes for setting up the controls from C++.
+
+ The C++ types can be included into your application using the following
+ include statement:
+
+ \code
+ #include <QtQuickControls2>
+ \endcode
+
+ \note If you are using a few classes from this module, we recommend including
+ those specific classes only instead of the module.
+
+ To link against the corresponding C++ libraries, add the following to your
+ qmake project file:
+
+ \code
+ QT += quickcontrols2
+ \endcode
+
+ The \l{Qt Quick Controls} page contains information about how to use the
+ module.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-customize.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-customize.qdoc
new file mode 100644
index 0000000000..8207b32ab7
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-customize.qdoc
@@ -0,0 +1,1057 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-customize.html
+ \keyword Customizing Qt Quick Controls 2
+ \title Customizing Qt Quick Controls
+ \brief A set of UI controls to create user interfaces in Qt Quick
+
+ Qt Quick Controls consist of a hierarchy (tree) of items. In order to
+ provide a custom look and feel, the default QML implementation of each
+ item can be replaced with a custom one.
+
+ \section1 Customizing a Control
+
+ Sometimes you'll want to create a "one-off" look for a specific part of
+ your UI, and use a complete style everywhere else. Perhaps you're happy
+ with the style you're using, but there's a certain button that has some
+ special significance.
+
+ The first way to create this button is to simply define it in-place,
+ wherever it is needed. For example, perhaps you're not satisfied with the
+ Basic style's Button having square corners. To make them rounded, you
+ can override the \l {Control::}{background} item and set the radius
+ property of Rectangle:
+
+ \include customize-button-background.qdocinc file
+
+ \note as the different items that make up a control in any given style are
+ designed to work together, it may be necessary to override other items to
+ get the look you're after. In addition, not all styles can be customized.
+ See the note in \l {Customization Reference} for more information.
+
+ The second way to create the button is good if you plan to use your rounded
+ button in several places. It involves moving the code into its own QML file
+ within your project.
+
+ For this approach, we'll copy the background code from the Basic style's
+ \c Button.qml. This file can be found in the following path in your Qt
+ installation:
+
+ \c {$QTDIR/qml/QtQuick/Controls/Basic/Button.qml}
+
+ After doing that, we'll simply add the following line:
+
+ \code
+ radius: 4
+ \endcode
+
+ To avoid confusion with the controls in the
+ module itself, we'll call the file \c MyButton.qml. To use the control in
+ your application, refer to it by its filename:
+
+ \qml
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ MyButton {
+ text: qsTr("A Special Button")
+ }
+ }
+ \endqml
+
+ The third way to create the button is a bit more structured, both in terms
+ of where the file sits in the file system and how it is used in QML. First,
+ copy an existing file as you did above, but this time, put it into a
+ subfolder in your project named (for example) \c controls. To use the
+ control, first import the folder into a namespace:
+
+ \qml
+ import QtQuick.Controls
+ import "controls" as MyControls
+
+ ApplicationWindow {
+ MyControls.Button {
+ text: qsTr("A Special Button")
+ }
+ }
+ \endqml
+
+ As you now have the \c MyControls namespace, you can name the controls after
+ their actual counterparts in the Qt Quick Controls module. You can repeat
+ this process for any control that you wish to add.
+
+ An added benefit of these three methods is that it's not necessary to
+ implement the template from scratch.
+
+ \note the three approaches mentioned here do not work for customizing the
+ attached \l ToolTip, as that is a shared item created internally. To do
+ a one-off customization of a \c ToolTip, see \l {Custom Tool Tips}. To
+ customize the attached \c ToolTip, it must be provided as part of
+ \l {Creating a Custom Style}{your own style}.
+
+ \section1 Creating a Custom Style
+
+ There are several ways to go about creating your own styles. Below, we'll
+ explain the various approaches.
+
+ \section2 Definition of a Style
+
+ In Qt Quick Controls, a style is essentially a set of QML files within a
+ single directory. There are four requirements for a style to be
+ \l {Using Styles in Qt Quick Controls}{usable}:
+
+ \list
+ \li At least one QML file whose name matches a control (for example,
+ \c Button.qml) must exist.
+ \li Each QML file must contain the relevant type from the \l {Qt Quick Templates 2}
+ {QtQuick.Templates} import as the root item. For example,
+ Button.qml must contain a Button template as its root item.
+
+ If we instead used the corresponding type from the \l {Qt Quick Controls}
+ {QtQuick.Controls} import as we did in the previous section, it would not work:
+ the control we were defining would try to derive from itself.
+ \li A \l {Module Definition qmldir Files}{qmldir} file must exist alongside
+ the QML file(s). Below is an example of a simple \c qmldir file for a style that
+ provides a button:
+
+ \badcode
+ module MyStyle
+ Button 2.15 Button.qml
+ \endcode
+
+ If you're using \l {Compile-Time Style Selection}{compile-time style
+ selection}, the qmldir should also import the fallback style:
+
+ \badcode
+ # ...
+ import QtQuick.Controls.Basic auto
+ \endcode
+
+ This can also be done for \l {Run-Time Style Selection}{run-time style selection}
+ instead of using, for example, \l QQuickStyle::setFallbackStyle().
+
+ The directory structure for such a style looks like this:
+
+ \badcode
+ MyStyle
+ ├─── Button.qml
+ └─── qmldir
+ \endcode
+ \li The files must be in a directory that is findable via the \l {QML Import Path}.
+
+ For example, if the path to \e MyStyle directory mentioned above was
+ \c /home/user/MyApp/MyStyle, then \c /home/user/MyApp must be added to
+ the QML import path.
+
+ To \l {Using Styles in Qt Quick Controls}{use} \e MyStyle in \e MyApp,
+ refer to it by name:
+
+ \list
+ \li \c {./MyApp -style MyStyle}
+ \endlist
+
+ The style name must match the casing of the style directory; passing
+ \e mystyle or \e MYSTYLE is not supported.
+ \endlist
+
+ By default, the styling system uses the Basic style as a fallback for
+ controls that aren't implemented. To customize or extend any other built-in
+ style, it is possible to specify a different fallback style using
+ \l[QtQuickControls2]{QQuickStyle}.
+
+ What this means is that you can implement as many controls as you like for
+ your custom style, and place them almost anywhere. It also allows users to
+ create their own styles for your application.
+
+ \section3 Previewing Custom Styles in Qt Quick Designer
+
+ Using the approach above, it is possible to preview a custom style
+ in Qt Quick Designer. In order to do so,
+ ensure that the project has a
+ \l {Qt Quick Controls Configuration File}{qtquickcontrols2.conf} file,
+ and that the following entry exists:
+
+ \badcode
+ [Controls]
+ Style=MyStyle
+ \endcode
+
+ For more information, take a look at the
+ \l {Qt Quick Controls - Flat Style}{Flat Style example}.
+
+ \section2 Style-specific C++ Extensions
+
+ Sometimes you may need to use C++ to extend your custom style. There are two
+ ways to expose such types to QML:
+
+ \list
+ \li If the style that uses the type is the only style used by an application,
+ it's enough to register it with the QML engine via qmlRegisterType():
+
+ \code
+ qmlRegisterType<ACoolCppItem>("MyApp", 1, 0, "ACoolItem");
+ \endcode
+
+ See \l {Using C++ Data From QML} for more information about this.
+ \li If the style that uses the type is one of many styles used by an
+ application, it may be better to only register it when necessary. This
+ is the point at which it would make sense to implement your own
+ \l {Creating C++ Plugins for QML}{QML plugin}.
+
+ Using a plugin as part of your style is not that much different from
+ using a set of QML files. The only difference is that the plugin and
+ its \c qmldir file must be present in the same directory as the QML
+ files.
+ \endlist
+
+ \section3 Considerations for custom styles
+
+ When implementing your own style and customizing controls, there are some
+ points to keep in mind to ensure that your application is as performant as
+ possible.
+
+ \section4 Avoid assigning an id to styles' implementations of item delegates
+
+ As explained in \l {Definition of a Style}, when you implement your
+ own style for a control, you start off with the relevant template for
+ that control. For example, a style's \c Button.qml will be structured
+ similarly to this:
+
+ \qml
+ T.Button {
+ // ...
+
+ background: Rectangle {
+ // ...
+ }
+
+ contentItem: Text {
+ // ...
+ }
+
+ // ...
+ }
+ \endqml
+
+ When you use a Button in your application, the \c background and
+ \c contentItem items will be created and parented to the root \c Button
+ item:
+
+ \qml
+ // Creates the Button root item, the Rectangle background,
+ // and the Text contentItem.
+ Button {
+ text: qsTr("Confirm")
+ }
+ \endqml
+
+ Suppose you then needed to do a one-off customization of the Button (as
+ explained in \l {Customizing a Control}):
+
+ \include customize-button-background.qdocinc file
+
+ In QML, this would normally result in both the default \c background
+ implementation and the one-off, custom \c background items being created.
+ Qt Quick Controls uses a technique that avoids creating both items, and
+ instead only creates the custom \c background, greatly improving the
+ creation performance of controls.
+
+ This technique relies on the absence of an \l {The id Attribute}{id} in the
+ style's implementation of that item. If an id is assigned, the technique
+ cannot work, and both items will be created. For example, it can be
+ tempting to assign an id to the \c background or \c contentItem so that
+ other objects within the file can refer to those items:
+
+ \qml
+ T.Button {
+ // ...
+
+ background: Rectangle {
+ id: backgroundRect
+ // ...
+ }
+
+ contentItem: Text {
+ // Use backgroundRect in some way...
+ }
+
+ // ...
+ }
+ \endqml
+
+ With this code, every time a Button instance with a customized background
+ is created, both backgrounds will be created, resulting in sub-optimal
+ creation performance.
+
+ Prior to Qt 5.15, the old, unused background would be deleted to release
+ the resources associated with it. However, as the control does not own the
+ items, it should not delete them. As of Qt 5.15, old items are no longer
+ deleted, and so the \c backgroundRect item will live longer than it needs
+ to—typically until the application exits. Although the old item will be
+ hidden, visually unparented from the control, and removed from the
+ accessibility tree, it is important to keep the creation time and memory
+ usage of these unused items in mind when assigning an id in this context.
+
+ \section4 Avoid imperative assignments of custom items
+
+ The technique mentioned in the section above only works when an item is
+ \l {Prefer Declarative Bindings Over Imperative Assignments}{declaratively}
+ assigned for the first time, and so imperative assignments will result in
+ orphaned items. Always use declarative bindings to assign custom items
+ when possible.
+
+ \section4 Don't import QtQuick.Controls in QML implementations
+
+ When writing the QML for your style's implementation of a control,
+ it's important not to import \c {QtQuick.Controls}. Doing so will
+ prevent the QML from being compiled by the QML compiler.
+
+ \section4 Implement types used by other types
+
+ Suppose you were using ScrollViews in your application, and decided that
+ you want to customize their scroll bars. It is tempting to just implement a
+ custom ScrollBar.qml and have ScrollView pick up the customized ScrollBar
+ automatically. However, this will not work. You must implement both
+ ScrollBar.qml \e and ScrollView.qml.
+
+ \section3 Attached properties
+
+ It is common for a style to have certain properties or attributes that
+ apply to all controls. \l {Attached Properties and Attached Signal
+ Handlers}{Attached properties} are a great way of extending an item in QML
+ without having to modify any existing C++ belonging to that item. For
+ example, both the \l {Material Style}{Material} and \l {Universal
+ Style}{Universal} styles have an attached theme property that controls
+ whether an item and its children will be rendered in a light or dark theme.
+
+ As an example, let's add an attached property that controls elevation. Our
+ style will illustrate the elevation with a drop shadow; the higher the
+ elevation, the larger the shadow.
+
+ The first step is to \l {Qt Creator: Project Types}{create a new Qt Quick
+ Controls application} in Qt Creator. After that, we
+ \l {Qt Creator: Creating C++ Classes}{add a C++ type} that stores the elevation. Since
+ the type will be used for every control supported by our style, and because
+ we may wish to add other attached properties later on, we'll call it
+ MyStyle. Here is \c MyStyle.h:
+
+ \code
+ #ifndef MYSTYLE_H
+ #define MYSTYLE_H
+
+ #include <QObject>
+ #include <QtQml>
+
+ class MyStyle : public QObject
+ {
+ Q_OBJECT
+ Q_PROPERTY(int elevation READ elevation WRITE setElevation NOTIFY elevationChanged)
+
+ public:
+ explicit MyStyle(QObject *parent = nullptr);
+
+ static MyStyle *qmlAttachedProperties(QObject *object);
+
+ int elevation() const;
+ void setElevation(int elevation);
+
+ signals:
+ void elevationChanged();
+
+ private:
+ int m_elevation;
+ };
+
+ QML_DECLARE_TYPEINFO(MyStyle, QML_HAS_ATTACHED_PROPERTIES)
+
+ #endif // MYSTYLE_H
+ \endcode
+
+ \c MyStyle.cpp:
+
+ \code
+ #include "mystyle.h"
+
+ MyStyle::MyStyle(QObject *parent) :
+ QObject(parent),
+ m_elevation(0)
+ {
+ }
+
+ MyStyle *MyStyle::qmlAttachedProperties(QObject *object)
+ {
+ return new MyStyle(object);
+ }
+
+ int MyStyle::elevation() const
+ {
+ return m_elevation;
+ }
+
+ void MyStyle::setElevation(int elevation)
+ {
+ if (elevation == m_elevation)
+ return;
+
+ m_elevation = elevation;
+ emit elevationChanged();
+ }
+ \endcode
+
+ The \c MyStyle type is special in the sense that it shouldn't be
+ instantiated, but rather used for its attached properties. For that reason,
+ we register it in the following manner in \c main.cpp:
+
+ \code
+ #include <QGuiApplication>
+ #include <QQmlApplicationEngine>
+
+ #include "mystyle.h"
+
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ qmlRegisterUncreatableType<MyStyle>("MyStyle", 1, 0, "MyStyle", "MyStyle is an attached property");
+
+ QQmlApplicationEngine engine;
+ // Make the directory containing our style known to the QML engine.
+ engine.addImportPath(":/");
+ engine.load(QUrl(QLatin1String("qrc:/main.qml")));
+
+ return app.exec();
+ }
+ \endcode
+
+ We then copy \c Button.qml from the Basic style in
+ \c {$QTDIR/qml/QtQuick/Controls/Basic/} into a new \c myproject folder in our
+ project directory. Add the newly copied \c Button.qml to \c qml.qrc, which is
+ the resource file that contains our QML files.
+
+ Next, we add a drop shadow to the \l {Control::}{background} delegate of
+ the Button:
+
+ \code
+ // ...
+ import QtGraphicalEffects
+ import MyStyle
+ // ...
+
+ background: Rectangle {
+ // ...
+
+ layer.enabled: control.enabled && control.MyStyle.elevation > 0
+ layer.effect: DropShadow {
+ verticalOffset: 1
+ color: control.visualFocus ? "#330066ff" : "#aaaaaa"
+ samples: control.MyStyle.elevation
+ spread: 0.5
+ }
+ }
+ \endcode
+
+ Note that we:
+
+ \list
+ \li Don't bother using the drop shadow when the elevation is \c 0
+ \li Change the shadow's color depending on whether or not the button has
+ focus
+ \li Make the size of the shadow depend on the elevation
+ \endlist
+
+ To try out the attached property, we create a \l Row with two Buttons in
+ \c main.qml:
+
+ \qml
+ import QtQuick
+ import QtQuick.Controls
+
+ import MyStyle 1.0
+
+ ApplicationWindow {
+ id: window
+ width: 400
+ height: 400
+ visible: true
+
+ Row {
+ spacing: 20
+ anchors.centerIn: parent
+
+ Button {
+ text: "Button 1"
+ }
+ Button {
+ text: "Button 2"
+ MyStyle.elevation: 10
+ }
+ }
+ }
+ \endqml
+
+ One button has no elevation, and the other has an elevation of \c 10.
+
+ With that in place, we can run our example. To tell the application to
+ use our new style, we pass \c {-style MyStyle} as an application
+ argument, but there are \l {Using Styles in Qt Quick Controls}{many
+ ways} to specify the style to use.
+
+ The end result:
+
+ \image qtquickcontrols2-customize-buttons.png
+
+ Note that the \c {import MyStyle 1.0} statement is only necessary
+ because we are using the attached property belonging to \c MyStyle.
+ Both buttons will use our custom style, even if we were to remove the
+ import.
+
+ \section1 Customization Reference
+
+ The following snippets present examples where the Basic style's controls
+ have been customized using the same approach as the
+ \l {Customizing a Control} section. The code can be used as a starting
+ point to implement a custom look and feel.
+
+ \note The \l {macOS Style}{macOS} and \l {Windows Style}{Windows} styles
+ are not suitable for customizing.
+ \include customizing-native-styles.qdocinc
+
+ \section2 Customizing ApplicationWindow
+
+ ApplicationWindow consists of one visual item:
+ \l {ApplicationWindow::background}{background}.
+
+ \code
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ visible: true
+
+ background: Rectangle {
+ gradient: Gradient {
+ GradientStop { position: 0; color: "#ffffff" }
+ GradientStop { position: 1; color: "#c1bbf9" }
+ }
+ }
+ }
+ \endcode
+
+
+ \section2 Customizing BusyIndicator
+
+ BusyIndicator consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{contentItem}.
+
+ \image qtquickcontrols2-busyindicator-custom.png
+
+ \snippet qtquickcontrols2-busyindicator-custom.qml file
+
+
+ \section2 Customizing Button
+
+ Button consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-button-custom.png
+
+ \snippet qtquickcontrols2-button-custom.qml file
+
+
+ \section2 Customizing CheckBox
+
+ CheckBox consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-checkbox-custom.png
+
+ \snippet qtquickcontrols2-checkbox-custom.qml file
+
+ \section2 Customizing CheckDelegate
+
+ CheckDelegate consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-checkdelegate-custom.png
+
+ \snippet qtquickcontrols2-checkdelegate-custom.qml file
+
+
+ \section2 Customizing ComboBox
+
+ ComboBox consists of \l {Control::background}{background},
+ \l {Control::contentItem}{content item}, \l {ComboBox::popup}{popup},
+ \l {ComboBox::indicator}{indicator}, and \l {ComboBox::delegate}{delegate}.
+
+ \image qtquickcontrols2-combobox-custom.png
+
+ \snippet qtquickcontrols2-combobox-custom.qml file
+
+ As explained in \l {ComboBox Model Roles}, ComboBox supports multiple
+ types of models. If you know that your ComboBox instances will only
+ ever use one particular type of model, then it is possible to simplify
+ the code above.
+
+ For example, if your models will only ever be derived from
+ \l QAbstractItemModel and have more than one role, the following
+ binding is sufficient:
+
+ \code
+ text: model[control.textRole]
+ \endcode
+
+ However, if you want to support all standard models, the more complex
+ binding is necessary, and is explained in detail below.
+
+ \quotefromfile qtquickcontrols2-combobox-custom.qml
+ \skipto control.textRole
+ \printto Array.isArray
+
+ The first line checks if the \l {ComboBox::}{textRole} property has
+ been set. It is only necessary to set this property if the model
+ has more than one role.
+
+ \printline Array.isArray
+
+ If \c textRole has been set, the next step is to check if the model
+ is an array.
+
+ If it is an array, the \c modelData context property will be available,
+ and so it must be used. Square bracket notation is used to access
+ the property of modelData since the property name is not known ahead
+ of time.
+
+ If it is not an array, the \c model context property must be used
+ instead.
+
+ \printline modelData
+
+ Finally, if \c textRole has not been set, then the model only has one
+ role, and so it is sufficient to use the value of \c modelData.
+
+ \section2 Customizing DelayButton
+
+ DelayButton consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-delaybutton-custom.png
+
+ \snippet qtquickcontrols2-delaybutton-custom.qml file
+
+
+ \section2 Customizing Dial
+
+ Dial consists of two visual items: \l {Control::background}{background}
+ and \l {Dial::handle}{handle}.
+
+ \image qtquickcontrols2-dial-custom.png
+
+ \snippet qtquickcontrols2-dial-custom.qml file
+
+
+ \section2 Customizing Drawer
+
+ Drawer can have a visual \l {Control::background}{background}
+ item.
+
+ \code
+ background: Rectangle {
+ Rectangle {
+ x: parent.width - 1
+ width: 1
+ height: parent.height
+ color: "#21be2b"
+ }
+ }
+ \endcode
+
+
+ \section2 Customizing Frame
+
+ Frame consists of one visual item: \l {Control::background}{background}.
+
+ \image qtquickcontrols2-frame-custom.png
+
+ \snippet qtquickcontrols2-frame-custom.qml file
+
+
+ \section2 Customizing GroupBox
+
+ GroupBox consists of two visual items: \l {Control::background}{background}
+ and \l {GroupBox::label}{label}.
+
+ \image qtquickcontrols2-groupbox-custom.png
+
+ \snippet qtquickcontrols2-groupbox-custom.qml file
+
+
+ \section2 Customizing ItemDelegate
+
+ ItemDelegate consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-itemdelegate-custom.png
+
+ \snippet qtquickcontrols2-itemdelegate-custom.qml file
+
+
+ \section2 Customizing Label
+
+ Label can have a visual \l {Label::background}{background} item.
+
+ \image qtquickcontrols2-label-custom.png
+
+ \snippet qtquickcontrols2-label-custom.qml file
+
+
+ \section2 Customizing Menu
+
+ \list
+ \li \l Menu consists of a visual \l {Popup::background}{background} item.
+ \li \l MenuItem consists of four visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{content item}, \l {AbstractButton::}{indicator}, and
+ \l {MenuItem::}{arrow}.
+ \li \l MenuSeparator consists of a visual \l {Control::background}{background} and
+ \l {Control::contentItem}{content item}.
+ \endlist
+
+ \image qtquickcontrols2-menu-custom.png
+
+ \quotefromfile qtquickcontrols2-menu-custom.qml
+ \skipto import QtQuick
+ \printuntil import QtQuick.Controls
+ \skipto Menu
+ \printto eof
+
+
+ \section2 Customizing MenuBar
+
+ MenuBar can have a visual \l {Control::background}{background} item,
+ and MenuBarItem consists of two visual items: \l {Control::background}
+ {background} and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-menubar-custom.png
+
+ \quotefromfile qtquickcontrols2-menubar-custom.qml
+ \skipto import QtQuick
+ \printuntil import QtQuick.Controls
+ \skipto MenuBar
+ \printto eof
+
+
+ \section2 Customizing PageIndicator
+
+ PageIndicator consists of a \l {Control::background}{background}, \l {Control::contentItem}{content item}, and \l {PageIndicator::delegate}{delegate}.
+
+ \image qtquickcontrols2-pageindicator-custom.png
+
+ \snippet qtquickcontrols2-pageindicator-custom.qml file
+
+
+ \section2 Customizing Pane
+
+ Pane consists of a \l {Control::background}{background}.
+
+ \image qtquickcontrols2-pane-custom.png
+
+ \snippet qtquickcontrols2-pane-custom.qml file
+
+
+ \section2 Customizing Popup
+
+ Popup consists of a \l {Popup::background}{background} and
+ \l {Popup::contentItem}{content item}.
+
+ \image qtquickcontrols2-popup-custom.png
+
+ \quotefromfile qtquickcontrols2-popup-custom.qml
+ \skipto import QtQuick
+ \printuntil import QtQuick.Controls
+ \codeline
+ \skipto Popup
+ \printuntil {
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+
+ \section2 Customizing ProgressBar
+
+ ProgressBar consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-progressbar-custom.png
+
+ \snippet qtquickcontrols2-progressbar-custom.qml file
+
+
+ \section2 Customizing RadioButton
+
+ RadioButton consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{content item} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-radiobutton-custom.png
+
+ \snippet qtquickcontrols2-radiobutton-custom.qml file
+
+
+ \section2 Customizing RadioDelegate
+
+ RadioDelegate consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-radiodelegate-custom.png
+
+ \snippet qtquickcontrols2-radiodelegate-custom.qml file
+
+
+ \section2 Customizing RangeSlider
+
+ RangeSlider consists of three visual items:
+ \l {Control::background}{background},
+ \l {RangeSlider::first}{first.handle} and
+ \l {RangeSlider::second.handle}{second.handle}.
+
+ \image qtquickcontrols2-rangeslider-custom.png
+
+ \snippet qtquickcontrols2-rangeslider-custom.qml file
+
+
+ \section2 Customizing RoundButton
+
+ RoundButton can be customized in the same manner as
+ \l {Customizing Button}{Button}.
+
+
+ \section2 Customizing ScrollBar
+
+ ScrollBar consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-scrollbar-custom.png
+
+ \snippet qtquickcontrols2-scrollbar-custom.qml file
+
+
+ \section2 Customizing ScrollIndicator
+
+ ScrollIndicator consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-scrollindicator-custom.png
+
+ \snippet qtquickcontrols2-scrollindicator-custom.qml file
+
+
+ \section2 Customizing ScrollView
+
+ ScrollView consists of a \l {Control::background}{background} item,
+ and horizontal and vertical scroll bars.
+
+ \image qtquickcontrols2-scrollview-custom.png
+
+ \snippet qtquickcontrols2-scrollview-custom.qml file
+
+
+ \section2 Customizing Slider
+
+ Slider consists of two visual items: \l {Control::background}{background},
+ and \l {Slider::handle}{handle}.
+
+ \image qtquickcontrols2-slider-custom.png
+
+ \snippet qtquickcontrols2-slider-custom.qml file
+
+
+ \section2 Customizing SpinBox
+
+ SpinBox consists of four visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem}, \l {SpinBox::up.indicator}{up indicator},
+ and \l {SpinBox::down.indicator}{down indicator}.
+
+ \image qtquickcontrols2-spinbox-custom.png
+
+ \snippet qtquickcontrols2-spinbox-custom.qml file
+
+
+ \section2 Customizing SplitView
+
+ SplitView consists of a visual \l {SplitView::handle}{handle} delegate.
+
+ \image qtquickcontrols2-splitview-custom.png
+
+ \snippet qtquickcontrols2-splitview-custom.qml 1
+
+
+ \section2 Customizing StackView
+
+ StackView can have a visual \l {Control::background}{background}
+ item, and it allows customizing the transitions that are used for
+ push, pop, and replace operations.
+
+ \snippet qtquickcontrols2-stackview-custom.qml file
+
+
+ \section2 Customizing SwipeDelegate
+
+ SwipeDelegate consists of six visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{content item}, \l {AbstractButton::indicator}{indicator},
+ \c swipe.left, \c swipe.right, and \c swipe.behind.
+
+ \image qtquickcontrols2-swipedelegate-custom.png
+
+ \snippet qtquickcontrols2-swipedelegate-custom.qml file
+
+
+ \section2 Customizing SwipeView
+
+ SwipeView can have a visual \l {Control::background}{background}
+ item. The navigation is implemented by the \l {Control::contentItem}
+ {content item}.
+
+ \snippet qtquickcontrols2-swipeview-custom.qml file
+
+
+ \section2 Customizing Switch
+
+ Switch consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{content item} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-switch-custom.png
+
+ \snippet qtquickcontrols2-switch-custom.qml file
+
+ \section2 Customizing SwitchDelegate
+
+ SwitchDelegate consists of three visual items: \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem} and \l {AbstractButton::indicator}{indicator}.
+
+ \image qtquickcontrols2-switchdelegate-custom.png
+
+ \snippet qtquickcontrols2-switchdelegate-custom.qml file
+
+
+ \section2 Customizing TabBar
+
+ TabBar consists of two visual items: \l {Control::background}{background},
+ and \l {Control::contentItem}{contentItem}.
+
+ \image qtquickcontrols2-tabbar-custom.png
+
+ \snippet qtquickcontrols2-tabbar-custom.qml file
+
+
+ \section2 Customizing TabButton
+
+ TabButton can be customized in the same manner as
+ \l {Customizing Button}{Button}.
+
+
+ \section2 Customizing TextArea
+
+ TextArea consists of a \l {TextArea::background}{background} item.
+
+ \image qtquickcontrols2-textarea-custom.png
+
+ \snippet qtquickcontrols2-textarea-custom.qml file
+
+
+ \section2 Customizing TextField
+
+ TextField consists of a \l {TextField::background}{background} item.
+
+ \image qtquickcontrols2-textfield-custom.png
+
+ \snippet qtquickcontrols2-textfield-custom.qml file
+
+
+ \section2 Customizing ToolBar
+
+ ToolBar consists of one visual item: \l {Control::background}{background}.
+
+ \image qtquickcontrols2-toolbar-custom.png
+
+ \snippet qtquickcontrols2-toolbar-custom.qml file
+
+
+ \section2 Customizing ToolButton
+
+ ToolButton consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-toolbutton-custom.png
+
+ \snippet qtquickcontrols2-toolbutton-custom.qml file
+
+
+ \section2 Customizing ToolSeparator
+
+ ToolSeparator consists of two visual items: \l {Control::background}{background}
+ and \l {Control::contentItem}{content item}.
+
+ \image qtquickcontrols2-toolseparator-custom.png
+
+ \snippet qtquickcontrols2-toolseparator-custom.qml file
+
+
+ \section2 Customizing ToolTip
+
+ ToolTip consists of two visual items: \l {Popup::background}{background}
+ and \l {Popup::contentItem}{content item}.
+
+ \quotefromfile qtquickcontrols2-tooltip-custom.qml
+ \skipto import QtQuick
+ \printuntil import QtQuick.Controls
+ \skipto ToolTip
+ \printuntil }
+ \printuntil }
+ \printuntil }
+
+ \include qquicktooltip.qdocinc customize-note
+
+ \section2 Customizing Tumbler
+
+ Tumbler consists of three visual items:
+ \l {Control::background}{background},
+ \l {Control::contentItem}{contentItem}, and
+ \l {Tumbler::delegate}{delegate}.
+
+ \image qtquickcontrols2-tumbler-custom.png
+
+ \snippet qtquickcontrols2-tumbler-custom.qml file
+
+ If you want to define your own contentItem, use either a \l ListView or
+ \l PathView as the root item. For a wrapping Tumbler, use PathView:
+
+ \snippet qtquickcontrols2-tumbler-pathView.qml contentItem
+
+ For a non-wrapping Tumbler, use ListView:
+
+ \snippet qtquickcontrols2-tumbler-listView.qml contentItem
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-delegates.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-delegates.qdoc
new file mode 100644
index 0000000000..a3883b1f1d
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-delegates.qdoc
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-delegates.html
+ \title Delegate Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for delegate controls
+
+ Qt Quick Controls offers a selection of controls that are used as
+ delegates in views.
+
+ \annotatedlist qtquickcontrols2-delegates
+
+ Each type of delegate has its own specific target use case. The following
+ sections offer guidelines for choosing the appropriate type of delegate,
+ depending on the use case.
+
+ \section1 CheckDelegate Control
+
+ \image qtquickcontrols2-checkdelegate.gif
+
+ \l CheckDelegate presents a checkable control that can be toggled on
+ (checked) or off (unchecked). Check delegates are typically used to
+ select one or more options from a set of options.
+
+ \b {See also} \l {CheckBox Control}.
+
+ \section1 ItemDelegate Control
+
+ \image qtquickcontrols2-itemdelegate.gif
+
+ \l ItemDelegate presents a checkable control that can be pressed and
+ clicked by the user.
+
+ \section1 RadioDelegate Control
+
+ \image qtquickcontrols2-radiodelegate.gif
+
+ \l RadioDelegate presents a checkable control that can be toggled on
+ (checked) or off (unchecked). Radio delegates are typically used to select
+ one option from a set of options.
+
+ \b {See also} \l {RadioButton Control}.
+
+ \section1 SwipeDelegate Control
+
+ \image qtquickcontrols2-swipedelegate.gif
+
+ \l SwipeDelegate presents a view item that can be swiped left or right to
+ expose more options or information.
+
+ \section1 SwitchDelegate Control
+
+ \image qtquickcontrols2-switchdelegate.gif
+
+ \l SwitchDelegate presents a switchable delegate that can be toggled on or off.
+
+ \b {See also} \l {Switch Control}.
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-deployment.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-deployment.qdoc
new file mode 100644
index 0000000000..a84d0d8790
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-deployment.qdoc
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-deployment.html
+ \title Deploying Qt Quick Controls Applications
+
+ Deployment of Qt Quick Controls applications is very similar to
+ deployment of other types of Qt applications. However, there are a few
+ factors to consider.
+
+ \section1 Deploying an Application with Several Styles
+
+ Suppose you have an application that will be deployed to both Android and
+ Windows devices. To ensure that only the minimum set of files that are
+ necessary for the application to run are deployed to each device, you can
+ use file selectors. For example, your directory structure could look like
+ this:
+
+ \code
+ resources.qrc
+ main.qml
+ +windows/MyPage.qml
+ +windows/qtquickcontrols2.conf
+ +android/MyPage.qml
+ +android/qtquickcontrols2.conf
+ \endcode
+
+ In the project above, \c main.qml would import \c QtQuick.Controls, for
+ example, but shouldn't import, say, \c QtQuick.Controls.Material. Any code
+ that is style-specific is moved out into separate files; just as we've done
+ for \c MyPage.qml.
+
+ The \c +windows/qtquickcontrols2.conf file would contain configuration
+ options specific to the Universal style:
+
+ \code
+ [Controls]
+ Style=Universal
+
+ [Universal]
+ Theme=Dark
+ Accent=Red
+ \endcode
+
+ The \c +android/qtquickcontrols2.conf file would contain configuration
+ options specific to the Material style:
+
+ \code
+ [Controls]
+ Style=Material
+
+ [Material]
+ Theme=Light
+ Accent=Brown
+ \endcode
+
+ \section1 Static Builds
+
+ For dynamically built applications, it is not necessary to import a
+ specific style that should be usable by that application. For statically
+ built applications, Qt's build system must be involved to ensure that
+ QML plugins function as expected. Specifically, \c qmake uses
+ \c qmlimportscanner to scan the QML files in your application for import
+ statements. For this reason, any styles that should be usable by a
+ statically built application must explicitly import that style. Where the
+ import occurs is up to the developer, but it is recommended to follow the
+ approach mentioned in the \l {Deploying an Application with Several Styles}
+ section, so that only the minimum set of files that are necessary for a
+ particular device are deployed.
+
+ \sa {Deploying Qt Applications}, {Using Styles in Qt Quick Controls}
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-environment.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-environment.qdoc
new file mode 100644
index 0000000000..4484acf392
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-environment.qdoc
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-environment.html
+ \title Supported Environment Variables in Qt Quick Controls
+
+ This page contains a list of all environment variables that Qt Quick Controls
+ supports. The environment variables are primarily meant for testing purposes, but
+ they can also be used to set system-wide defaults.
+
+ \table
+ \header
+ \li Variable
+ \li Description
+ \row
+ \li \c QT_QUICK_CONTROLS_STYLE
+ \li Specifies the default \l {Styling Qt Quick Controls}{Qt Quick Controls style}.
+ The value can be either one of the built-in styles, for example \c "Material",
+ or a custom style such as \c "MyStyle".
+ \row
+ \li \c QT_QUICK_CONTROLS_FALLBACK_STYLE
+ \li Specifies a fallback style for \l {Creating a Custom Style}{custom styles}.
+ The value can be one of the built-in styles, for example \c "Material",
+ \row
+ \li \c QT_QUICK_CONTROLS_CONF
+ \li Specifies the location of the \l {Qt Quick Controls configuration file}.
+ By default, the configuration file is loaded from the application's
+ resources in \c ":/qtquickcontrols2.conf".
+ \row
+ \li \c QT_QUICK_CONTROLS_HOVER_ENABLED
+ \li Specifies whether Qt Quick Controls use \l {Control::hoverEnabled}{hover effects}.
+ The value can be set to \c 0 or \c 1 to disable or enable hover effects, respectively.
+ \endtable
+
+ \l {Imagine style} specific environment variables:
+
+ \include qquickimaginestyle.qdocinc env
+
+ \l {Material style} specific environment variables:
+
+ \include qquickmaterialstyle.qdocinc env
+
+ \l {Universal style} specific environment variables:
+
+ \include qquickuniversalstyle.qdocinc env
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \li \l{Qt Quick Controls Configuration File}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-examples.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-examples.qdoc
new file mode 100644
index 0000000000..2924114f3b
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-examples.qdoc
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \group qtquickcontrols2-examples
+ \ingroup all-examples
+ \keyword Qt Quick Controls Examples
+ \title Qt Quick Controls Examples
+ \keyword Qt Quick Controls 2 Examples
+ \brief A collection of examples for \l {Qt Quick Controls}
+
+ These examples demonstrate creating user interfaces using \l {Qt Quick Controls}.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-fileselectors.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-fileselectors.qdoc
new file mode 100644
index 0000000000..4c782de100
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-fileselectors.qdoc
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-fileselectors.html
+ \title Using File Selectors with Qt Quick Controls
+
+ \l {QFileSelector}{File selectors} provide a convenient way of selecting
+ file variants. Qt offers the platform name and the locale as built-in
+ selectors. Qt Quick Controls extends the built-in selectors with the name
+ (lowercase) of the style that an application is running with.
+
+ By using file selectors, style-specific tweaks can be applied without
+ creating a hard dependency to a style. From the available file variants,
+ only the selected QML file is loaded by the QML engine. Each file variant
+ can assume the context, that is, a specific style. This typically leads
+ to some code duplication, but on the other hand, cuts the aforementioned
+ hard dependency to the style, and leads to simpler and more efficient
+ QML code.
+
+ The following example demonstrates a custom rounded button that has a
+ styled drop shadow in the \l {Material Style}{Material style}, and looks
+ flat in other styles. The files are organized so that the Material version
+ of \c CustomButton.qml is placed into a \c +Material sub-directory.
+
+ \code
+ :/main.qml
+ :/CustomButton.qml
+ :/+Material/CustomButton.qml
+ \endcode
+
+ By default, \c main.qml will use \c CustomButton.qml for the \c CustomButton
+ type. However, when the application is run with the Material style, the
+ \c Material selector will be present and the \c +Material/CustomButton.qml
+ version will be used instead.
+
+ \code
+ // main.qml
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ id: window
+ visible: true
+
+ CustomButton {
+ text: "Button"
+ anchors.centerIn: parent
+ }
+ }
+ \endcode
+
+ The base implementation of the custom button is a simple rounded
+ flat button.
+
+ \code
+ // CustomButton.qml
+ import QtQuick
+ import QtQuick.Controls
+
+ Button {
+ id: control
+
+ background: Rectangle {
+ radius: width / 2
+ implicitWidth: 36
+ implicitHeight: 36
+ color: control.pressed ? "#ccc" : "#eee"
+ }
+ }
+ \endcode
+
+ The Material style's implementation of the custom button imports the
+ Material style, requests a dark theme to get light text, and creates
+ a drop shadow for the background.
+
+ \code
+ // +Material/CustomButton.qml
+ import QtQuick
+ import QtGraphicalEffects
+ import QtQuick.Controls
+ import QtQuick.Controls.Material
+
+ Button {
+ id: control
+
+ Material.theme: Material.Dark
+
+ background: Rectangle {
+ implicitWidth: 48
+ implicitHeight: 48
+ color: Material.accentColor
+ radius: width / 2
+
+ layer.enabled: control.enabled
+ layer.effect: DropShadow {
+ verticalOffset: 1
+ color: Material.dropShadowColor
+ samples: control.pressed ? 20 : 10
+ spread: 0.5
+ }
+ }
+ }
+ \endcode
+
+ \note It is recommended to use \l QQmlApplicationEngine, which internally
+ creates a \l QQmlFileSelector instance. This is all that is needed to take
+ QML file selectors into use.
+
+ \section1 Related Information
+ \list
+ \li \l {QFileSelector}
+ \li \l {QQmlFileSelector}
+ \li \l {Styling Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-focus.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-focus.qdoc
new file mode 100644
index 0000000000..77bc9883b9
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-focus.qdoc
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-focus.html
+ \keyword Focus Management in Qt Quick Controls 2
+ \title Focus Management in Qt Quick Controls
+ \brief Overview of focus handling with Qt Quick Controls
+
+ Qt Quick Controls follows the standard
+ \l {Keyboard Focus in Qt Quick}{Qt Quick focus system}, while also
+ providing some added convenience. For example, the
+ \l {Control::}{focusPolicy} property can be used to control the ways in
+ which a control receives focus.
+
+ \section1 Focus Scope Controls
+
+ Qt Quick Controls offers a selection of controls that act as
+ \l {Acquiring Focus and Focus Scopes}{focus scopes}:
+
+ \annotatedlist qtquickcontrols2-focusscopes
+
+ \sa {Keyboard Focus in Qt Quick}
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-fusion.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-fusion.qdoc
new file mode 100644
index 0000000000..ca67985f8d
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-fusion.qdoc
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-fusion.html
+ \title Fusion Style
+
+ The Fusion style is a desktop-oriented style.
+
+ The Fusion style is a platform-agnostic style that offers a desktop-oriented
+ look and feel. It implements the same design language as the
+ \l {Qt Widget Gallery}{Fusion style for Qt Widgets}.
+
+ \image qtquickcontrols2-fusion.png
+
+ To run an application with the Fusion style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \note The Fusion style is not a native desktop style. The style runs on any
+ platform, and looks similar everywhere. Minor differences may occur due to
+ differences in the standard system palettes, available fonts, and font
+ rendering engines.
+
+ \section2 Customization
+
+ The Fusion style uses the standard system \l[QtQuick]{Palette}
+ to provide colors that match the desktop environment.
+
+ \image qtquickcontrols2-fusion-palettes.png
+
+ Custom palettes can be specified for any control,
+ \l{Popup::palette}{popup}, or \l{Window::palette}{application window}.
+ Explicit palette attributes are automatically propagated from parent to children,
+ overriding any system defaults for that attribute. In the following example,
+ the window and all three switches appear with a violet highlight color:
+
+ \table
+ \row
+ \li
+ \qml
+ import QtQuick 2.12
+ import QtQuick.Controls 2.12
+
+ ApplicationWindow {
+ visible: true
+
+ palette.highlight: "violet"
+
+ Column {
+ anchors.centerIn: parent
+
+ Switch { text: qsTr("First"); checked: true }
+ Switch { text: qsTr("Second"); checked: true }
+ Switch { text: qsTr("Third") }
+ }
+ }
+ \endqml
+ \li
+ \image qtquickcontrols2-fusion-violet.png
+ \endtable
+
+ \b {See also} \l {Basic Style}, \l {Material Style}, \l {Universal Style}
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-gettingstarted.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-gettingstarted.qdoc
new file mode 100644
index 0000000000..09209d2115
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-gettingstarted.qdoc
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-gettingstarted.html
+ \keyword Getting Started with Qt Quick Controls 2
+ \title Getting Started with Qt Quick Controls
+
+ A basic example of a QML file that makes use of controls is shown here:
+
+ \qml
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ title: "My Application"
+ width: 640
+ height: 480
+ visible: true
+
+ Button {
+ text: "Push Me"
+ anchors.centerIn: parent
+ }
+ }
+ \endqml
+
+ \section1 Setting Up Controls from C++
+
+ Although QQuickView has traditionally been used to display QML files in a
+ C++ application, doing this means you can only set window properties from
+ C++.
+
+ With Qt Quick Controls, declare an ApplicationWindow as the root item of
+ your application and launch it by using QQmlApplicationEngine instead.
+ This ensures that you can control top level window properties from QML.
+
+ A basic example of a source file that makes use of controls is shown here:
+
+ \code
+ #include <QGuiApplication>
+ #include <QQmlApplicationEngine>
+
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ return app.exec();
+ }
+ \endcode
+
+ \section2 Using C++ Data From QML
+
+ If you need to register a C++ class to use from QML, you can call
+ qmlRegisterType() before declaring your QQmlApplicationEngine.
+ See \l [QtQml] {Defining QML Types from C++} for more information.
+
+ If you need to expose data to QML components, you need to make them
+ available to the context of the current QML engine. See QQmlContext for
+ more information.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-guidelines.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-guidelines.qdoc
new file mode 100644
index 0000000000..83d6db93fe
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-guidelines.qdoc
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-guidelines.html
+ \keyword Qt Quick Controls Guidelines
+ \title Qt Quick Controls Guidelines
+ \keyword Qt Quick Controls 2 Guidelines
+
+ Qt Quick Controls offers a selection of controls that can be used to
+ build complete interfaces in Qt Quick.
+
+ Below you will find practical guidelines on how and when to use
+ the controls.
+
+ \annotatedlist qtquickcontrols2-guidelines
+
+ \section1 Related Information
+ \list
+ \li \l{Qt Quick Controls QML Types}{All Qt Quick Controls QML Types}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-icons.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-icons.qdoc
new file mode 100644
index 0000000000..e043aa05d0
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-icons.qdoc
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-icons.html
+ \keyword Icons in Qt Quick Controls 2
+ \title Icons in Qt Quick Controls
+
+ Qt Quick Controls comes with support for icons since Qt 5.10. This means,
+ Buttons, item delegates, and menu items are now capable of presenting an
+ icon in addition to a text label.
+
+ \section1 Using Icons
+
+ \l {AbstractButton::icon}{AbstractButton} and \l {Action::icon}{Action} provide
+ the following properties through which icons can be set:
+ \list
+ \li \c icon.name
+ \li \c icon.source
+ \li \c icon.width
+ \li \c icon.height
+ \li \c icon.color
+ \li \c icon.cache
+ \endlist
+
+ Theme icons are referenced by a name, and regular icons by a source URL. Both
+ \c icon.name and \c icon.source can be set to ensure that an icon will always
+ be found. If the icon is found in the theme, it will always be used; even if
+ \c icon.source is also set. If the icon is not found in the theme, \c icon.source
+ will be used instead.
+
+ \code
+ Button {
+ icon.name: "edit-cut"
+ icon.source: "images/cut.png"
+ }
+ \endcode
+
+ Each \l {Styling Qt Quick Controls}{Qt Quick Controls 2 style} requests a
+ default icon size and color according to their guidelines, but it is possible
+ to override these by setting the \c icon.width, \c icon.height, and \c icon.color
+ properties.
+
+ The image that is loaded by an icon whose \c width and \c height are not set
+ depends on the type of icon in use. For theme icons, the closest available size
+ will be chosen. For regular icons, the behavior is the same as the \l {Image::}
+ {sourceSize} property of \l Image.
+
+ The icon color is specified by default so that it matches the text color in
+ different states. In order to use an icon with the original colors, set the
+ color to \c "transparent".
+
+ \code
+ Button {
+ icon.color: "transparent"
+ icon.source: "images/logo.png"
+ }
+ \endcode
+
+ For buttons, the \l {AbstractButton::}{display} property can be used to control
+ how the icon and text are displayed within the button.
+
+ The \c icon.cache property controls whether or not the icon image is cached.
+ For more information, see \l {Image::}{cache}.
+
+ \section1 Icon Themes
+
+ Compliant icon themes must follow the freedesktop icon theme specification,
+ which can be obtained here: \l {http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html}.
+
+ Traditionally, only Linux and UNIX support icon themes on the platform level,
+ but it is possible to bundle a compliant icon theme in an application to use
+ themed icons on any platform.
+
+ The default \l {QIcon::themeSearchPaths()}{icon theme search paths} depend on
+ the platform. On Linux and UNIX, the search path will use the \c XDG_DATA_DIRS
+ environment variable if available. All platforms have the resource directory
+ \c :/icons as a fallback. Custom icon theme search paths can be set with
+ \l QIcon::setThemeSearchPaths().
+
+ The following example bundles an icon theme called \e mytheme into the application's
+ resources using \l {The Qt Resource System}{Qt's resource system}.
+
+ \badcode
+ <RCC>
+ <qresource prefix="/">
+ <file>icons/mytheme/index.theme</file>
+ <file>icons/mytheme/32x32/myicon.png</file>
+ <file>icons/mytheme/32x32@2/myicon.png</file>
+ </qresource>
+ </RCC>
+ \endcode
+
+ The \c index.theme file describes the general attributes of the icon theme, and
+ lists the available theme icon directories:
+
+ \badcode
+ [Icon Theme]
+ Name=mytheme
+ Comment=My Icon Theme
+
+ Directories=32x32,32x32@2
+
+ [32x32]
+ Size=32
+ Type=Fixed
+
+ [32x32@2]
+ Size=32
+ Scale=2
+ Type=Fixed
+ \endcode
+
+ In order to use the bundled icon theme, an application should call \l QIcon::setThemeName()
+ before loading the main QML file:
+
+ \code
+ #include <QGuiApplication>
+ #include <QQmlApplicationEngine>
+ #include <QIcon>
+
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ QIcon::setThemeName("mytheme"); // <--
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ return app.exec();
+ }
+ \endcode
+
+ Now it is possible to use named icons from the bundled icon theme without having
+ to specify any fallback source:
+
+ \code
+ Button {
+ icon.name: "myicon"
+ }
+ \endcode
+
+ The \l {Qt Quick Controls - Gallery}{Gallery example} and \l {Qt Quick Controls 2 - Wearable Demo}
+ {Wearable Demo} provide complete runnable applications with a bundled icon theme.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-imagine.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-imagine.qdoc
new file mode 100644
index 0000000000..d2dcb9be5c
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-imagine.qdoc
@@ -0,0 +1,2535 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-imagine.html
+ \title Imagine Style
+
+ The Imagine Style is based on configurable image assets. \l{detailed-desc-imagine}{More...}
+
+ \styleimport {QtQuick.Controls.Imagine 2.12} {Qt 5.10}
+
+ \section1 Attached Properties
+
+ \list
+ \li \l {imagine-path-attached-prop}{\b path} : string
+ \endlist
+
+ \section1 Detailed Description
+ \target detailed-desc-imagine
+
+ The Imagine style is based on image assets. The style comes with a default
+ set of images, but the images can be easily changed by providing a directory
+ with images using a predefined naming convention.
+
+ \image qtquickcontrols2-imagine.png
+ \caption The Imagine style with the default images
+
+ To run an application with the Imagine style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \section2 File Names
+
+ The image files are named using the following convention:
+
+ \c <control>-<element>-<states>
+
+ The \c <control> and \c <element> sections are mandatory, but the
+ \c <states> section is optional. For example, if a single file named
+ \c "button-background.9.png" is provided for \l {Button}, it will be used
+ for every state that \c Button supports. It is up to the developer to
+ decide the set of states that they will provide images for. However, it
+ is recommended to provide images for the most common control states where
+ possible, such as \c disabled, \c pressed, etc. This will ensure that
+ interactive controls visually behave as the end user would expect them to.
+
+ \section2 Element Reference
+
+ The following table lists which elements are supported for each control,
+ along with the possible states for that element, and the file extension
+ that it expects. An element is an image that represents a certain visual
+ part of the control. For example, \c {Button}'s \c "background" element
+ represents its \l {Control::}{background}.
+
+ \table
+ \header
+ \li Control
+ \li Element
+ \li States
+ \li Extension
+ \row
+ \li \l ApplicationWindow
+ \li background
+ \li active
+ \li .9.png (or .png)
+ \row
+ \li \l BusyIndicator
+ \li animation
+ \li disabled, running, mirrored, hovered
+ \li .webp
+ \row
+ \li
+ \li background
+ \li same as above
+ \li .webp
+ \row
+ \li \l Button
+ \li background
+ \li disabled, pressed, checked, checkable, focused, highlighted, flat, mirrored, hovered
+ \li .9.png
+ \row
+ \li \l CheckBox
+ \li background
+ \li disabled, pressed, checked, partially-checked, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li \l CheckDelegate
+ \li background
+ \li disabled, pressed, checked, partially-checked, focused, highlighted, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li \l ComboBox
+ \li background
+ \li disabled, pressed, editable, open, focused, mirrored, hovered, flat
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li
+ \li popup
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l DelayButton
+ \li background
+ \li disabled, pressed, checked, checkable, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li progress
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li mask
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l Dial
+ \li background
+ \li disabled, pressed, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l Dialog
+ \li background
+ \li modal, dim
+ \li .9.png (or .png)
+ \row
+ \li
+ \li title
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li .9.png (or .png)
+ \row
+ \li \l DialogButtonBox
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l Drawer
+ \li background
+ \li modal, dim, top, left, right, bottom
+ \li .9.png (or .png)
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li .9.png (or .png)
+ \row
+ \li \l Frame
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l GroupBox
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li
+ \li title
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l ItemDelegate
+ \li background
+ \li disabled, pressed, focused, highlighted, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l Label
+ \li background
+ \li disabled, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l Menu
+ \li background
+ \li modal, dim
+ \li .9.png (or .png)
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li .9.png (or .png)
+ \row
+ \li \l MenuItem
+ \li arrow
+ \li disabled, pressed, checked, focused, highlighted, mirrored, hovered
+ \li .png
+ \row
+ \li
+ \li background
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li \l MenuSeparator
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li
+ \li separator
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l Page
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l PageIndicator
+ \li background
+ \li disabled, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li delegate
+ \li disabled, pressed, current, mirrored, hovered
+ \li .png
+ \row
+ \li \l Pane
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l Popup
+ \li background
+ \li modal, dim
+ \li .9.png (or .png)
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li .9.png (or .png)
+ \row
+ \li \l ProgressBar
+ \li animation
+ \li disabled, mirrored, hovered
+ \li .png
+ \row
+ \li
+ \li background
+ \li disabled, indeterminate, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li mask
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li progress
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l RadioButton
+ \li background
+ \li disabled, pressed, checked, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li \l RadioDelegate
+ \li background
+ \li disabled, pressed, checked, focused, highlighted, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .png
+ \row
+ \li \l RangeSlider
+ \li background
+ \li vertical, horizontal, disabled, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l RangeSlider
+ \li progress
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li first, second, vertical, horizontal, disabled, pressed, focused, mirrored, hovered
+ \li .png
+ \row
+ \li \l RoundButton
+ \li background
+ \li disabled, pressed, checked, checkable, focused, highlighted, flat, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l ScrollBar
+ \li background
+ \li vertical, horizontal, disabled, interactive, pressed, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l ScrollIndicator
+ \li background
+ \li vertical, horizontal, disabled, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l ScrollView
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l Slider
+ \li background
+ \li vertical, horizontal, disabled, pressed, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li progress
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l SpinBox
+ \li background
+ \li disabled, editable, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li editor
+ \li disabled, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li up, down, disabled, editable, pressed, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l StackView
+ \li background
+ \li disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l SwipeDelegate
+ \li background
+ \li disabled, pressed, focused, highlighted, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l SwipeView
+ \li background
+ \li vertical, horizontal, disabled, interactive, focused, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l Switch
+ \li background
+ \li disabled, pressed, checked, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l SwitchDelegate
+ \li background
+ \li disabled, pressed, checked, focused, highlighted, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li
+ \li handle
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li
+ \li indicator
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l TabBar
+ \li background
+ \li disabled, header, footer, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l TabButton
+ \li background
+ \li disabled, pressed, checked, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l TextArea
+ \li background
+ \li disabled, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l TextField
+ \li background
+ \li disabled, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l ToolBar
+ \li background
+ \li disabled, header, footer, mirrored
+ \li .9.png (or .png)
+ \row
+ \li \l ToolButton
+ \li background
+ \li disabled, pressed, checked, checkable, focused, highlighted, flat, mirrored, hovered
+ \li .9.png (or .png)
+ \row
+ \li \l ToolSeparator
+ \li background
+ \li vertical, horizontal, disabled, mirrored
+ \li .9.png (or .png)
+ \row
+ \li
+ \li separator
+ \li same as above
+ \li .9.png (or .png)
+ \row
+ \li \l ToolTip
+ \li background
+ \li
+ \li .9.png (or .png)
+ \row
+ \li \l Tumbler
+ \li background
+ \li disabled, focused, mirrored, hovered
+ \li .9.png (or .png)
+ \endtable
+
+ \section2 Asset Examples
+
+ The following table lists examples of assets (taken from the
+ \l {https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quickcontrols2/imagine/images}
+ {default Imagine style assets}) for all controls. The list is not
+ exhaustive, as not all elements need assets, but it can be used as a guide
+ when creating your own assets.
+
+ The template that these assets were \l {Exporting 9-Patch Images}
+ {exported from} is available as a
+ \l {https://code.qt.io/cgit/qt/qtdeclarative.git/plain/src/quickcontrols2/imagine/design/imagine.sketch}
+ {Sketch project}.
+
+ \table
+ \header
+ \li Control
+ \li Element
+ \li States
+ \li Asset
+ \li Notes
+ \row
+ \li \l ApplicationWindow
+ \li background
+ \li
+ \li \image imagine/images/applicationwindow-background.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li
+ \li \image imagine/images/applicationwindow-overlay.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li \image imagine/images/applicationwindow-overlay-modal.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li \l Button
+ \li background
+ \li
+ \li \image imagine/images/button-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/button-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/button-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/button-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked
+ \li \image imagine/images/button-background-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, disabled
+ \li \image imagine/images/button-background-checked-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, focused
+ \li \image imagine/images/button-background-checked-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, hovered
+ \li \image imagine/images/button-background-checked-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted
+ \li \image imagine/images/button-background-highlighted.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, disabled
+ \li \image imagine/images/button-background-highlighted-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, focused
+ \li \image imagine/images/button-background-highlighted-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, hovered
+ \li \image imagine/images/button-background-highlighted-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, pressed
+ \li \image imagine/images/button-background-highlighted-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, checked
+ \li \image imagine/images/button-background-highlighted-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/button-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li flat
+ \li \image imagine/images/button-background-flat.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li flat, disabled
+ \li \image imagine/images/button-background-flat-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li flat, hovered
+ \li \image imagine/images/button-background-flat-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li flat, pressed
+ \li \image imagine/images/button-background-flat-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li flat, checked
+ \li \image imagine/images/button-background-flat-checked.9.png
+ \li
+ \row
+ \li \l CheckBox
+ \li indicator
+ \li
+ \li \image imagine/images/checkbox-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/checkbox-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/checkbox-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/checkbox-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/checkbox-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/checkbox-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/checkbox-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked
+ \li \image imagine/images/checkbox-indicator-partially-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, pressed
+ \li \image imagine/images/checkbox-indicator-partially-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, focused
+ \li \image imagine/images/checkbox-indicator-partially-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, hovered
+ \li \image imagine/images/checkbox-indicator-partially-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/checkbox-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/checkbox-indicator-hovered.png
+ \li
+ \row
+ \li \l CheckDelegate
+ \li background
+ \li
+ \li \image imagine/images/checkdelegate-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/checkdelegate-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/checkdelegate-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/checkdelegate-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/checkdelegate-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li
+ \li \image imagine/images/checkdelegate-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/checkdelegate-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/checkdelegate-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/checkdelegate-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/checkdelegate-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/checkdelegate-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/checkdelegate-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/checkdelegate-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/checkdelegate-indicator-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked
+ \li \image imagine/images/checkdelegate-indicator-partially-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, pressed
+ \li \image imagine/images/checkdelegate-indicator-partially-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, focused
+ \li \image imagine/images/checkdelegate-indicator-partially-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li partially, checked, hovered
+ \li \image imagine/images/checkdelegate-indicator-partially-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/checkdelegate-indicator-hovered.png
+ \li
+ \row
+ \li \l ComboBox
+ \li background
+ \li
+ \li \image imagine/images/combobox-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/combobox-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/combobox-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/combobox-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/combobox-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li open
+ \li \image imagine/images/combobox-background-open.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li editable
+ \li \image imagine/images/combobox-background-editable.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li editable, focused
+ \li \image imagine/images/combobox-background-editable-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li editable, disabled
+ \li \image imagine/images/combobox-background-editable-disabled.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li
+ \li \image imagine/images/combobox-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/combobox-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li editable
+ \li \image imagine/images/combobox-indicator-editable.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li editable, disabled
+ \li \image imagine/images/combobox-indicator-editable-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li editable, mirrored
+ \li \image imagine/images/combobox-indicator-editable-mirrored.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li editable, mirrored, disabled
+ \li \image imagine/images/combobox-indicator-editable-mirrored-disabled.png
+ \li
+ \row
+ \li
+ \li popup
+ \li
+ \li \image imagine/images/combobox-popup.9.png
+ \li
+ \row
+ \li \l DelayButton
+ \li background
+ \li
+ \li \image imagine/images/delaybutton-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/delaybutton-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled, checked
+ \li \image imagine/images/delaybutton-background-disabled-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/delaybutton-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/delaybutton-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked
+ \li \image imagine/images/delaybutton-background-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, focused
+ \li \image imagine/images/delaybutton-background-checked-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, hovered
+ \li \image imagine/images/delaybutton-background-checked-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/delaybutton-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li
+ \li \image imagine/images/delaybutton-progress.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li disabled
+ \li \image imagine/images/delaybutton-progress-disabled.9.png
+ \li
+ \row
+ \li
+ \li mask
+ \li
+ \li \image imagine/images/delaybutton-mask.9.png
+ \li
+ \row
+ \li \l Dial
+ \li background
+ \li
+ \li \image imagine/images/dial-background.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/dial-background-disabled.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/dial-background-focused.png
+ \li
+ \row
+ \li
+ \li handle
+ \li
+ \li \image imagine/images/dial-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/dial-handle-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused
+ \li \image imagine/images/dial-handle-focused.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, pressed
+ \li \image imagine/images/dial-handle-focused-pressed.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, hovered
+ \li \image imagine/images/dial-handle-focused-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li pressed
+ \li \image imagine/images/dial-handle-pressed.png
+ \li
+ \row
+ \li
+ \li handle
+ \li hovered
+ \li \image imagine/images/dial-handle-hovered.png
+ \li
+ \row
+ \li \l Dialog
+ \li background
+ \li
+ \li \image imagine/images/dialog-background.9.png
+ \li
+ \row
+ \li
+ \li overlay
+ \li
+ \li \image imagine/images/dialog-overlay.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li \image imagine/images/dialog-overlay-modal.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li \l DialogButtonBox
+ \li background
+ \li
+ \li \image imagine/images/dialogbuttonbox-background.9.png
+ \li
+ \row
+ \li \l Drawer
+ \li background
+ \li left
+ \li \image imagine/images/drawer-background-left.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li right
+ \li \image imagine/images/drawer-background-right.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li top
+ \li \image imagine/images/drawer-background-top.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li bottom
+ \li \image imagine/images/drawer-background-bottom.9.png
+ \li
+ \row
+ \li
+ \li overlay
+ \li
+ \li \image imagine/images/drawer-overlay.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li \image imagine/images/drawer-overlay-modal.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li \l Frame
+ \li background
+ \li
+ \li \image imagine/images/frame-background.9.png
+ \li
+ \row
+ \li \l GroupBox
+ \li background
+ \li
+ \li \image imagine/images/groupbox-background.9.png
+ \li
+ \row
+ \li
+ \li title
+ \li
+ \li \image imagine/images/groupbox-title.9.png
+ \li
+ \row
+ \li \l ItemDelegate
+ \li background
+ \li
+ \li \image imagine/images/itemdelegate-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/itemdelegate-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/itemdelegate-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/itemdelegate-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/itemdelegate-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted
+ \li \image imagine/images/itemdelegate-background-highlighted.9.png
+ \li
+ \row
+ \li \l Menu
+ \li background
+ \li
+ \li \image imagine/images/menu-background.9.png
+ \li
+ \row
+ \li \l MenuItem
+ \li background
+ \li
+ \li \image imagine/images/menuitem-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted
+ \li \image imagine/images/menuitem-background-highlighted.9.png
+ \li
+ \row
+ \li
+ \li arrow
+ \li
+ \li \image imagine/images/menuitem-arrow.png
+ \li
+ \row
+ \li
+ \li arrow
+ \li mirrored
+ \li \image imagine/images/menuitem-arrow-mirrored.png
+ \li
+ \row
+ \li
+ \li arrow
+ \li disabled
+ \li \image imagine/images/menuitem-arrow-disabled.png
+ \li
+ \row
+ \li
+ \li arrow
+ \li mirrored, disabled
+ \li \image imagine/images/menuitem-arrow-mirrored-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li
+ \li \image imagine/images/menuitem-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/menuitem-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/menuitem-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/menuitem-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/menuitem-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/menuitem-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/menuitem-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/menuitem-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/menuitem-indicator-hovered.png
+ \li
+ \row
+ \li \l MenuSeparator
+ \li separator
+ \li
+ \li \image imagine/images/menuseparator-separator.9.png
+ \li
+ \row
+ \li \l Page
+ \li background
+ \li
+ \li \image imagine/images/page-background.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li \l PageIndicator
+ \li delegate
+ \li
+ \li \image imagine/images/pageindicator-delegate.png
+ \li
+ \row
+ \li
+ \li delegate
+ \li disabled
+ \li \image imagine/images/pageindicator-delegate-disabled.png
+ \li
+ \row
+ \li
+ \li delegate
+ \li disabled, current
+ \li \image imagine/images/pageindicator-delegate-disabled-current.png
+ \li
+ \row
+ \li
+ \li delegate
+ \li pressed
+ \li \image imagine/images/pageindicator-delegate-pressed.png
+ \li
+ \row
+ \li
+ \li delegate
+ \li current
+ \li \image imagine/images/pageindicator-delegate-current.png
+ \li
+ \row
+ \li \l Pane
+ \li background
+ \li
+ \li \image imagine/images/pane-background.9.png
+ \li
+ \row
+ \li \l Popup
+ \li background
+ \li
+ \li \image imagine/images/popup-background.9.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li
+ \li \image imagine/images/popup-overlay.png
+ \li \l {sup1}{See footnote} \sup 1
+ \row
+ \li
+ \li overlay
+ \li modal
+ \li \image imagine/images/popup-overlay-modal.png
+ \li
+ \row
+ \li \l ProgressBar
+ \li background
+ \li
+ \li \image imagine/images/progressbar-background.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li
+ \li \image imagine/images/progressbar-progress.png
+ \li
+ \row
+ \li
+ \li mask
+ \li
+ \li \image imagine/images/progressbar-mask.9.png
+ \li
+ \row
+ \li \l RadioButton
+ \li indicator
+ \li
+ \li \image imagine/images/radiobutton-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/radiobutton-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/radiobutton-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/radiobutton-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/radiobutton-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/radiobutton-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/radiobutton-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/radiobutton-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/radiobutton-indicator-hovered.png
+ \li
+ \row
+ \li \l RadioDelegate
+ \li background
+ \li
+ \li \image imagine/images/radiodelegate-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/radiodelegate-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/radiodelegate-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/radiodelegate-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/radiodelegate-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li
+ \li \image imagine/images/radiodelegate-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/radiodelegate-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/radiodelegate-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/radiodelegate-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/radiodelegate-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/radiodelegate-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/radiodelegate-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/radiodelegate-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/radiodelegate-indicator-hovered.png
+ \li
+ \row
+ \li \l RangeSlider
+ \li background
+ \li vertical
+ \li \image imagine/images/rangeslider-background-vertical.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li horizontal
+ \li \image imagine/images/rangeslider-background-horizontal.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li vertical
+ \li \image imagine/images/rangeslider-progress-vertical.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li vertical, disabled
+ \li \image imagine/images/rangeslider-progress-vertical-disabled.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li horizontal
+ \li \image imagine/images/rangeslider-progress-horizontal.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li horizontal, disabled
+ \li \image imagine/images/rangeslider-progress-horizontal-disabled.9.png
+ \li
+ \row
+ \li
+ \li handle
+ \li
+ \li \image imagine/images/rangeslider-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/rangeslider-handle-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused
+ \li \image imagine/images/rangeslider-handle-focused.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, hovered
+ \li \image imagine/images/rangeslider-handle-focused-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, pressed
+ \li \image imagine/images/rangeslider-handle-focused-pressed.png
+ \li
+ \row
+ \li
+ \li handle
+ \li hovered
+ \li \image imagine/images/rangeslider-handle-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li pressed
+ \li \image imagine/images/rangeslider-handle-pressed.png
+ \li
+ \row
+ \li \l RoundButton
+ \li background
+ \li
+ \li \image imagine/images/roundbutton-background.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/roundbutton-background-disabled.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled, checked
+ \li \image imagine/images/roundbutton-background-disabled-checked.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/roundbutton-background-focused.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/roundbutton-background-pressed.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked
+ \li \image imagine/images/roundbutton-background-checked.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, focused
+ \li \image imagine/images/roundbutton-background-checked-focused.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, hovered
+ \li \image imagine/images/roundbutton-background-checked-hovered.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted
+ \li \image imagine/images/roundbutton-background-highlighted.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, pressed
+ \li \image imagine/images/roundbutton-background-highlighted-pressed.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, focused
+ \li \image imagine/images/roundbutton-background-highlighted-focused.png
+ \li
+ \row
+ \li
+ \li background
+ \li highlighted, hovered
+ \li \image imagine/images/roundbutton-background-highlighted-hovered.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/roundbutton-background-hovered.png
+ \li
+ \row
+ \li \l ScrollBar
+ \li handle
+ \li
+ \li \image imagine/images/scrollbar-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/scrollbar-handle-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li interactive
+ \li \image imagine/images/scrollbar-handle-interactive.png
+ \li
+ \row
+ \li
+ \li handle
+ \li interactive, disabled
+ \li \image imagine/images/scrollbar-handle-interactive-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li interactive, pressed
+ \li \image imagine/images/scrollbar-handle-interactive-pressed.png
+ \li
+ \row
+ \li
+ \li handle
+ \li interactive, hovered
+ \li \image imagine/images/scrollbar-handle-interactive-hovered.png
+ \li
+ \row
+ \li \l ScrollIndicator
+ \li handle
+ \li
+ \li \image imagine/images/scrollindicator-handle.png
+ \li
+ \row
+ \li \l Slider
+ \li background
+ \li vertical
+ \li \image imagine/images/slider-background-vertical.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li horizontal
+ \li \image imagine/images/slider-background-horizontal.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li vertical
+ \li \image imagine/images/slider-progress-vertical.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li vertical, disabled
+ \li \image imagine/images/slider-progress-vertical-disabled.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li horizontal
+ \li \image imagine/images/slider-progress-horizontal.9.png
+ \li
+ \row
+ \li
+ \li progress
+ \li horizontal, disabled
+ \li \image imagine/images/slider-progress-horizontal-disabled.9.png
+ \li
+ \row
+ \li
+ \li handle
+ \li
+ \li \image imagine/images/slider-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/slider-handle-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused
+ \li \image imagine/images/slider-handle-focused.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, hovered
+ \li \image imagine/images/slider-handle-focused-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li focused, pressed
+ \li \image imagine/images/slider-handle-focused-pressed.png
+ \li
+ \row
+ \li
+ \li handle
+ \li hovered
+ \li \image imagine/images/slider-handle-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li pressed
+ \li \image imagine/images/slider-handle-pressed.png
+ \li
+ \row
+ \li \l SpinBox
+ \li background
+ \li
+ \li \image imagine/images/spinbox-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/spinbox-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/spinbox-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li editable
+ \li \image imagine/images/spinbox-background-editable.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up
+ \li \image imagine/images/spinbox-indicator-up.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, disabled
+ \li \image imagine/images/spinbox-indicator-up-disabled.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, pressed
+ \li \image imagine/images/spinbox-indicator-up-pressed.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, focused
+ \li \image imagine/images/spinbox-indicator-up-focused.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, mirrored
+ \li \image imagine/images/spinbox-indicator-up-mirrored.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, hovered
+ \li \image imagine/images/spinbox-indicator-up-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, editable
+ \li \image imagine/images/spinbox-indicator-up-editable.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, editable, pressed
+ \li \image imagine/images/spinbox-indicator-up-editable-pressed.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, editable, focused
+ \li \image imagine/images/spinbox-indicator-up-editable-focused.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, editable, mirrored
+ \li \image imagine/images/spinbox-indicator-up-editable-mirrored.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li up, editable, hovered
+ \li \image imagine/images/spinbox-indicator-up-editable-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down
+ \li \image imagine/images/spinbox-indicator-down.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, disabled
+ \li \image imagine/images/spinbox-indicator-down-disabled.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, pressed
+ \li \image imagine/images/spinbox-indicator-down-pressed.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, focused
+ \li \image imagine/images/spinbox-indicator-down-focused.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, mirrored
+ \li \image imagine/images/spinbox-indicator-down-mirrored.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, hovered
+ \li \image imagine/images/spinbox-indicator-down-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, editable
+ \li \image imagine/images/spinbox-indicator-down-editable.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, editable, pressed
+ \li \image imagine/images/spinbox-indicator-down-editable-pressed.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, editable, focused
+ \li \image imagine/images/spinbox-indicator-down-editable-focused.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, editable, mirrored
+ \li \image imagine/images/spinbox-indicator-down-editable-mirrored.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li down, editable, hovered
+ \li \image imagine/images/spinbox-indicator-down-editable-hovered.9.png
+ \li
+ \row
+ \li \l SwipeDelegate
+ \li background
+ \li
+ \li \image imagine/images/swipedelegate-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/swipedelegate-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/swipedelegate-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/swipedelegate-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/swipedelegate-background-hovered.9.png
+ \li
+ \row
+ \li \l Switch
+ \li indicator
+ \li
+ \li \image imagine/images/switch-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/switch-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/switch-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/switch-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/switch-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/switch-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/switch-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/switch-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/switch-indicator-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li
+ \li \image imagine/images/switch-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/switch-handle-disabled.png
+ \li
+ \row
+ \li
+ \li handle
+ \li pressed
+ \li \image imagine/images/switch-handle-pressed.png
+ \li
+ \row
+ \li \l SwitchDelegate
+ \li background
+ \li
+ \li \image imagine/images/switchdelegate-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/switchdelegate-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/switchdelegate-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/switchdelegate-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/switchdelegate-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li
+ \li \image imagine/images/switchdelegate-indicator.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li disabled
+ \li \image imagine/images/switchdelegate-indicator-disabled.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li pressed
+ \li \image imagine/images/switchdelegate-indicator-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked
+ \li \image imagine/images/switchdelegate-indicator-checked.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, focused
+ \li \image imagine/images/switchdelegate-indicator-checked-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, hovered
+ \li \image imagine/images/switchdelegate-indicator-checked-hovered.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li checked, pressed
+ \li \image imagine/images/switchdelegate-indicator-checked-pressed.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li focused
+ \li \image imagine/images/switchdelegate-indicator-focused.png
+ \li
+ \row
+ \li
+ \li indicator
+ \li hovered
+ \li \image imagine/images/switchdelegate-indicator-hovered.png
+ \li
+ \row
+ \li
+ \li handle
+ \li
+ \li \image imagine/images/switchdelegate-handle.png
+ \li
+ \row
+ \li
+ \li handle
+ \li disabled
+ \li \image imagine/images/switchdelegate-handle-disabled.png
+ \li
+ \row
+ \li \l TabBar
+ \li background
+ \li
+ \li \image imagine/images/tabbar-background.png
+ \li
+ \row
+ \li \l TabButton
+ \li background
+ \li
+ \li \image imagine/images/tabbutton-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/tabbutton-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/tabbutton-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked
+ \li \image imagine/images/tabbutton-background-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/tabbutton-background-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled, checked
+ \li \image imagine/images/tabbutton-background-disabled-checked.9.png
+ \li
+ \row
+ \li \l TextArea
+ \li background
+ \li
+ \li \image imagine/images/textarea-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/textarea-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/textarea-background-focused.9.png
+ \li
+ \row
+ \li \l TextField
+ \li background
+ \li
+ \li \image imagine/images/textfield-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled
+ \li \image imagine/images/textfield-background-disabled.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/textfield-background-focused.9.png
+ \li
+ \row
+ \li \l ToolBar
+ \li background
+ \li
+ \li \image imagine/images/toolbar-background.png
+ \li
+ \row
+ \li \l ToolButton
+ \li background
+ \li
+ \li \image imagine/images/toolbutton-background.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li disabled, checked
+ \li \image imagine/images/toolbutton-background-disabled-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li focused
+ \li \image imagine/images/toolbutton-background-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li pressed
+ \li \image imagine/images/toolbutton-background-pressed.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked
+ \li \image imagine/images/toolbutton-background-checked.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, focused
+ \li \image imagine/images/toolbutton-background-checked-focused.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li checked, hovered
+ \li \image imagine/images/toolbutton-background-checked-hovered.9.png
+ \li
+ \row
+ \li
+ \li background
+ \li hovered
+ \li \image imagine/images/toolbutton-background-hovered.9.png
+ \li
+ \row
+ \li \l ToolSeparator
+ \li separator
+ \li horizontal
+ \li \image imagine/images/toolseparator-separator-horizontal.9.png
+ \li
+ \row
+ \li
+ \li separator
+ \li vertical
+ \li \image imagine/images/toolseparator-separator-vertical.9.png
+ \li
+ \row
+ \li \l ToolTip
+ \li background
+ \li
+ \li \image imagine/images/tooltip-background.9.png
+ \li
+ \endtable
+
+ \target sup1
+ \sup 1 A 1x1 image containing one color, stretched to fill the control.
+
+ \section2 9-Patch Images
+
+ The Imagine style uses \l
+ {https://developer.android.com/guide/topics/graphics/2d-graphics.html#nine-patch}{9-patch
+ images} in order to give designers control over how a particular element
+ responds to being resized. Here is an example of a 9-patch image that
+ represents a \l {Button}'s \l {Control::}{background}, alongside a
+ magnified version (to make it easier to see the 9-patch lines):
+
+ \image qtquickcontrols2-imagine-9-patch-4x.png
+
+ The content of the image is 44 pixels wide by 32 pixels high. Every 9-patch
+ image needs a one pixel thick line (collectively referred to as
+ "9-patch lines") around every side, so the actual size of the image becomes
+ 46 pixels wide by 34 pixels high. Note that the 9-patch lines must be one
+ pixel thick regardless of the target DPI of the image. For example,
+ the 9-patch lines for button-background.9.png and button-background@2x.9.png
+ must both be one pixel thick.
+
+ The 9-patch lines must be black, and the remaining areas must be transparent
+ or white:
+
+ \image qtquickcontrols2-imagine-9-patch-size.png
+
+ \section3 Stretchable Areas
+
+ The 9-patch lines on the top and left edges determine which parts of the
+ image are stretched when it is resized.
+
+ Below are examples of the 9-patch image being resized to one and a half
+ times its original size in various dimensions:
+
+ \image qtquickcontrols2-imagine-9-patch-resized-stretchable.png
+
+ Notice how the the rounded corners keep their original size, as they are
+ outside the range of the lines.
+
+ \section3 Padding Areas
+
+ The 9-patch lines on the right and bottom edges determine how much space
+ is available for the control's \l {Control::}{contentItem}, which means it
+ can also be thought of as controlling the \l {Control::}{padding}. For a
+ diagram that illustrates padding, see \l {Control Layout}.
+
+ Below are more examples of the 9-patch image being resized, but this time
+ demonstrating how the padding 9-patch lines work.
+
+ \image qtquickcontrols2-imagine-9-patch-resized-padding.png
+
+ The \c contentItem can take up as much space as it needs within the shaded
+ areas. If the padding lines are left out, the \c contentItem will take as
+ much space as it needs without exceeding the stretchable areas.
+
+ \section3 Inset Areas
+
+ In some cases it is necessary for a control to have a drop shadow, for
+ example. However, if we were to add a drop shadow to the button above, it
+ would affect its size, which presents problems for both layouting and
+ mouse/touch input boundaries.
+
+ Inset areas accounts for this by telling the control that a certain area of
+ the 9-patch image should go outside of the control:
+
+ \image qtquickcontrols2-imagine-9-patch-inset.png
+
+ In the image below, the dashed line represents the button's clickable area,
+ as well as the space that it will take up in a layout. The shadow is marked
+ by the striped area behind it:
+
+ \image qtquickcontrols2-imagine-9-patch-inset-boundaries.png
+
+ \section3 Exporting 9-Patch Images
+
+ Various vector and bitmap editors can be used to create 9-patch images
+ suitable for use with the Imagine style. The following sections briefly
+ explain the export process for each editor, and the last section explains
+ how to ensure the exported images are 9-patch-conformant.
+
+ \section4 Affinity Designer
+
+ See Affinity's \l {https://affinity.help/publisher/en-US.lproj/pages/Publishing/exportSettings.html}
+ {Export Settings} documentation.
+
+ \section4 Adobe Illustrator
+
+ See Adobe's
+ \l {https://helpx.adobe.com/in/illustrator/using/collect-assets-export-for-screens.html#panel}
+ {Asset Export panel} documentation.
+
+ \section4 Adobe Photoshop
+
+ See Adobe's
+ \l {https://helpx.adobe.com/photoshop/using/generate-assets-layers.html}
+ {Generate image assets from layers} documentation.
+
+ \section4 Inkscape
+
+ The \l {https://github.com/mitchcurtis/inkscape-9-patch-export}
+ {Inkscape 9-Patch Export Extension} can be used to export assets with
+ Inkscape.
+
+ \section4 Sketch
+
+ See Sketch's \l {https://sketchapp.com/docs/exporting/}{Exporting} documentation.
+
+ Qt Quick Controls also provides a
+ \l {http://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quickcontrols2/imagine/design}
+ {plugin} for Sketch that automatically fixes the thickness of the 9-patch lines
+ after the assets are exported. To install this file, double-click on it.
+ Once Sketch has confirmed that the 9-patch export plugin has been installed,
+ the plugin will automatically process images when they are exported.
+
+ \section4 Fixing 9-Patch Lines
+
+ When exporting 9-patch images in several DPI variants (\c {@2x}, \c {@3x},
+ etc.), the 9-patch lines will typically be scaled up along with the image.
+ There are several ways to fix this, but perhaps the simplest approach is
+ to use \l {https://www.imagemagick.org/script/mogrify.php}{ImageMagick's mogrify}
+ tool. The tool has a \c -shave feature that can be used to crop the image
+ to reduce the thickness of the 9-patch lines:
+
+ \badcode
+ mogrify -shave 1x1 -path path/to/images *@2x.9.png
+ mogrify -shave 2x2 -path path/to/images *@3x.9.png
+ mogrify -shave 3x3 -path path/to/images *@4x.9.png
+ \endcode
+
+ Regular DPI images (those without the \c @Nx prefix) are not affected, so it
+ is only necessary to run the command on images intended for high DPI displays.
+
+ \section2 Animated Images
+
+ The \l {https://developers.google.com/speed/webp/}{WebP} and GIF animated
+ image formats are supported by the Imagine style.
+
+ \section2 Customization
+
+ \section3 Path
+
+ The Imagine style allows customizing the \l {imagine-path-attached-prop}{path}
+ that is used to do the image asset selection. The path can be specified for any
+ window or item, and it automatically propagates to children in the same manner as
+ \l {Control::font}{fonts}. In the following example, the window and all three radio
+ buttons appear with dark image assets (files that are located in "qrc:/themes/dark").
+
+ \table
+ \row
+ \li
+ \qml
+ import QtQuick 2.12
+ import QtQuick.Controls 2.12
+ import QtQuick.Controls.Imagine 2.12
+
+ ApplicationWindow {
+ visible: true
+
+ Imagine.path: "qrc:/themes/dark"
+
+ Column {
+ anchors.centerIn: parent
+
+ RadioButton { text: qsTr("Small") }
+ RadioButton { text: qsTr("Medium"); checked: true }
+ RadioButton { text: qsTr("Large") }
+ }
+ }
+ \endqml
+ \li
+ \image qtquickcontrols2-imagine-customization-dark.png
+ \endtable
+
+ In addition to specifying the path in QML, it is also possible to specify
+ it via an \l {imagine-customization-environment-variable}{environment variable}
+ or in a \l {imagine-customization-configuration-file}{configuration file}.
+ Attributes specified in QML take precedence over all other methods.
+
+ \section4 Configuration File
+ \target imagine-customization-configuration-file
+
+ \include qquickimaginestyle.qdocinc conf
+
+ See \l {Qt Quick Controls Configuration File} for more details about the
+ configuration file.
+
+ \section4 Environment Variables
+ \target imagine-customization-environment-variable
+
+ \include qquickimaginestyle.qdocinc env
+
+ See \l {Supported Environment Variables in Qt Quick Controls} for the full
+ list of supported environment variables.
+
+ \section3 Palette
+
+ The Imagine style supports palette customization via the \l {Item::}{palette}
+ property and the \l {Palette Configuration}{qtquickcontrols2.conf} file.
+ As with other styles, the exact \l[QML]{Palette}{palette roles}
+ that the Imagine style uses are style-dependent. However, as most of the visual
+ appearance of controls (for example: backgrounds) are managed through image assets,
+ only the roles that are typically used for text will have an effect.
+
+ \section3 Font
+
+ Custom fonts can be set via the \l {Control::}{font} property and the
+ \l {Font Configuration}{configuration} file.
+
+ \section2 Dependency
+
+ The Imagine style must be separately imported to gain access to the
+ attributes that are specific to the Imagine style. It should be noted
+ that regardless of the references to the Imagine style, the same
+ application code runs with any other style. Imagine-specific attributes
+ only have an effect when the application is run with the Imagine style.
+
+ If the Imagine style is imported in a QML file that is always loaded, the
+ Imagine style must be deployed with the application in order to be able
+ to run the application regardless of which style the application is run with.
+ By using \l {Using File Selectors with Qt Quick Controls}{file selectors},
+ style-specific tweaks can be applied without creating a hard dependency to
+ a style.
+
+ \b {See also} \l {Styling Qt Quick Controls}
+
+ \section1 Attached Property Documentation
+
+ \styleproperty {Imagine.path} {string} {imagine-path-attached-prop}
+ \target imagine-path-attached-prop
+ This attached property holds the path to the image assets...
+
+ \code
+ Button {
+ Imagine.path: "qrc:/themes/dark"
+ }
+ \endcode
+
+ \endstyleproperty
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \li \l{Qt Quick Controls - Imagine Style Example: Automotive}{Automotive Example}
+ \li \l{Qt Quick Controls - Imagine Style Example: Music Player}{Music Player Example}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-index.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-index.qdoc
new file mode 100644
index 0000000000..6de9fa228e
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-index.qdoc
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols-index.html
+ \keyword Qt Quick Controls 2
+ \title Qt Quick Controls
+
+ \brief Provides a set of UI controls for Qt Quick.
+
+ Qt Quick Controls provides a set of controls that can be used
+ to build complete interfaces in Qt Quick. The module was introduced
+ in Qt 5.7.
+
+ \image qtquickcontrols2-styles.png
+
+ Qt Quick Controls comes with a selection customizable styles.
+ See \l {Styling Qt Quick Controls} for more details.
+
+
+ \section1 Using the Module
+
+ \section2 QML API
+
+ The \l{Qt Quick Controls QML Types}{QML types} can be imported into your
+ application using the following import statement in your \c {.qml} file:
+
+ \qml
+ import QtQuick.Controls
+ \endqml
+
+ \section2 C++ API
+
+ Using the \l{Qt Quick Controls C++ Classes}{C++ API} requires linking against the module library,
+ either directly or through other dependencies.
+ Several build tools have dedicated support for this, including CMake and qmake.
+
+ \section3 Building with CMake
+ Use the \c find_package() command to locate the needed module components in the Qt6 package:
+
+ \snippet qtquickcontrols2-overview.cmake 0
+
+ See also the \l{Build with CMake} overview.
+
+ \section3 Building with qmake
+ To configure the module for building with qmake,
+ add the module as a value of the QT variable in the project's .pro file:
+
+ \code
+ QT += quickcontrols2
+ \endcode
+
+ \section2 Building From Source
+
+ The \b{Qt Image Formats} module is recommended, but not
+ required. It provides support for the \c {.webp} format used by the
+ \l {Animated Images}{Imagine style}.
+
+ \section1 Versions
+
+ Qt Quick Controls 2.0 was introduced in Qt 5.7. Subsequent minor Qt releases
+ increment the import version of the Qt Quick Controls modules by one,
+ until Qt 5.12, where the import versions match Qt's minor version.
+
+ In Qt 6, both the major and minor versions match, and version numbers may
+ be omitted from imports in QML. If the version is omitted, the latest
+ version will be used.
+
+ The experimental Qt Labs modules use import version 1.0.
+
+ \table
+ \header
+ \li \c Qt
+ \li \l {Qt Quick QML Types}{\c QtQuick}
+ \li \l {Qt Quick Controls QML Types}{\c QtQuick.Controls},\br
+ \l {Material Style}{\c QtQuick.Controls.Material},\br
+ \l {Universal Style}{\c QtQuick.Controls.Universal},\br
+ \l {Qt Quick Templates 2 QML Types}{\c QtQuick.Templates}
+ \li \l {Qt Labs Platform QML Types}{\c Qt.labs.platform}
+ \row
+ \li 5.7
+ \li 2.7
+ \li 2.0
+ \li 1.0
+ \row
+ \li 5.8
+ \li 2.8
+ \li 2.1
+ \li 1.0
+ \row
+ \li 5.9
+ \li 2.9
+ \li 2.2
+ \li 1.0
+ \row
+ \li 5.10
+ \li 2.10
+ \li 2.3
+ \li 1.0
+ \row
+ \li 5.11
+ \li 2.11
+ \li 2.4
+ \li 1.0
+ \row
+ \li 5.12
+ \li 2.12
+ \li 2.12
+ \li 1.0
+ \row
+ \li 6.0
+ \li 6.0
+ \li 6.0
+ \li 1.0
+ \row
+ \li ...
+ \li ...
+ \li ...
+ \li ...
+ \endtable
+
+ \section1 Module Evolution
+
+ Qt Quick Controls was originally written with touch interfaces as the primary focus.
+ While it is already possible to develop desktop interfaces, work is ongoing to
+ provide a more native look and feel.
+
+ \l{Changes to Qt Quick Controls} lists important changes in the
+ module API and functionality that were done for the Qt 6 series of Qt.
+
+ \section1 License and Attributions
+
+ Qt Quick Controls is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under the
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
+ Furthermore Qt Quick Controls potentially contains third party
+ modules under following permissive licenses:
+
+ \generatelist{groupsbymodule attributions-qtquickcontrols}
+
+ \section1 Topics
+
+ \list
+ \li \l{Getting Started with Qt Quick Controls}{Getting Started}
+ \li \l{Qt Quick Controls Guidelines}{Guidelines}
+ \li \l{Styling Qt Quick Controls}{Styling}
+ \li \l{Icons in Qt Quick Controls}{Icons}
+ \li \l{Customizing Qt Quick Controls}{Customization}
+ \li \l{Using File Selectors with Qt Quick Controls}{Using File Selectors}
+ \li \l{Deploying Qt Quick Controls Applications}{Deployment}
+ \li \l{Qt Quick Controls Configuration File}{Configuration File}
+ \li \l{Supported Environment Variables in Qt Quick Controls}{Environment Variables}
+ \endlist
+
+ \section1 Reference
+
+ \list
+ \li \l{Qt Quick Controls QML Types}{QML Types}
+ \li \l{Qt Quick Controls C++ Classes}{C++ Classes}
+ \endlist
+
+ \section1 Examples
+
+ \list
+ \li \l{Qt Quick Controls - Gallery}{Gallery}
+ \li \l{Qt Quick Controls - Chat Tutorial}{Chat Tutorial}
+ \li \l{Qt Quick Controls - Text Editor}{Text Editor}
+ \li \l{Qt Quick Controls - Wearable Demo}{Wearable Demo}
+ \li \l{Qt Quick Controls - Imagine Style Example: Automotive}{Automotive Example}
+ \li \l{Qt Quick Controls - Imagine Style Example: Music Player}{Music Player Example}
+ \li \l{Qt Quick Controls Examples}{All Examples}
+ \endlist
+
+ \section1 Related Modules
+
+ \list
+ \li \l{Qt Quick}
+ \li \l{Qt Quick Layouts}
+ \li \l{Qt Quick Templates 2}
+ \li \l{Qt Labs Platform}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-indicators.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-indicators.qdoc
new file mode 100644
index 0000000000..9f9e357bc6
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-indicators.qdoc
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-indicators.html
+ \title Indicator Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for indicator controls
+
+ Qt Quick Controls offers a selection of indicator-like controls.
+
+ \annotatedlist qtquickcontrols2-indicators
+
+ Each type of indicator has its own specific target use case. The following
+ sections offer guidelines for choosing the appropriate type of indicator,
+ depending on the use case.
+
+ \section1 BusyIndicator Control
+
+ \image qtquickcontrols2-busyindicator.png
+
+ BusyIndicator can be used to show that an operation is in progress,
+ and that the UI has to wait for the operation to complete.
+
+ \section1 PageIndicator Control
+
+ \image qtquickcontrols2-pageindicator.png
+
+ \l PageIndicator is used to indicate the currently active page in
+ a container of multiple pages.
+
+ \section1 ProgressBar Control
+
+ \image qtquickcontrols2-progressbar.gif
+
+ \l ProgressBar indicates the progress of an operation. The value should be
+ updated regularly.
+
+ \section1 ScrollBar Control
+
+ \image qtquickcontrols2-scrollbar.gif
+
+ \l ScrollBar is an interactive bar that indicates the current scroll
+ position, and can be used to scroll to a specific position in a
+ \l Flickable.
+
+ \section1 ScrollIndicator Control
+
+ \image qtquickcontrols2-scrollindicator.gif
+
+ \l ScrollIndicator is a non-interactive indicator that indicates the
+ current scroll position, and can be used to scroll to a specific position in a
+ \l {Flickable}.
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-input.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-input.qdoc
new file mode 100644
index 0000000000..6bc037e007
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-input.qdoc
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-input.html
+ \title Input Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for input controls
+
+ Qt Quick Controls offers a variety of input controls for both numeric
+ and textual input.
+
+ \annotatedlist qtquickcontrols2-input
+
+ Each type of input control has its own specific target use case. The
+ following sections offer guidelines for choosing the appropriate type
+ of input control, depending on the use case.
+
+ \section1 ComboBox Control
+
+ \image qtquickcontrols2-combobox.gif
+
+ \l ComboBox is used to select a value from a static multiple-line drop-down list.
+ It is not possible to add new values, and only one option can be selected.
+
+ Recommendations:
+ \list
+ \li If the number of values is very large, consider applying a filter.
+ \li If the list is very limited, consider using RadioButton. This has the
+ advantage that the user can see all options at the same time.
+ \li Select a default value, the value that will be chosen most often.
+ \endlist
+
+ \b {See also} \l {CheckBox Control}, \l {Tumbler Control}.
+
+ \section1 Dial Control
+
+ \image qtquickcontrols2-dial.png
+
+ \l Dial is similar to a traditional dial knob that is found on devices such
+ as stereos or industrial equipment.
+
+ The dial is rotated by clicking and dragging, with the handle indicating the
+ value of the dial.
+
+ For applications where fast input is important, the circular
+ \l {Dial::inputMode}{input mode} is useful, as clicking on the dial will
+ move it directly to that position.
+
+ For applications where precise input is important, the horizontal and
+ vertical input modes are recommended, as these allow small adjustments to
+ be made relative to where the dial is clicked. These modes are also better
+ for dials where large jumps in values could be unsafe, such as a dial that
+ controls audio volume.
+
+ \b {See also} \l {Tumbler Control}.
+
+ \section1 TextArea Control
+
+ \image qtquickcontrols2-textarea.png
+
+ \l TextArea is a multi-line text editor.
+
+ \section1 TextField Control
+
+ \image qtquickcontrols2-textfield.png
+
+ \l TextField is a single line text editor.
+
+ \b {See also} \l {Tumbler Control}.
+
+ \section1 Slider Control
+
+ \image qtquickcontrols2-slider.gif
+
+ \l Slider is used to select a value by sliding a handle along a track.
+
+ \section1 RangeSlider Control
+
+ \image qtquickcontrols2-rangeslider.gif
+
+ \l RangeSlider is used to select a range specified by two values,
+ by sliding each handle along a track.
+
+ \b {See also} \l {Slider Control}.
+
+ \section1 Tumbler Control
+
+ \image qtquickcontrols2-tumbler.png
+
+ \l Tumbler is a spinnable wheel of items that can be selected.
+
+ \b {See also} \l {ComboBox Control}.
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-macos.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-macos.qdoc
new file mode 100644
index 0000000000..79cf62a92b
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-macos.qdoc
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-macOS.html
+ \title macOS Style
+
+ The macOS style is a style that looks native on macOS.
+ \l {detailed-desc-macOS}{More...}
+
+ \styleimport {QtQuick.Controls.macOS} {Qt 6.0}
+
+ \target detailed-desc-macOS
+
+ The macOS style is a style that looks native on macOS. The controls are drawn run-time using
+ native frameworks, and is therefore only available for applications running on macOS.
+
+ \note Be aware that the apperance of this style can change from one minor Qt version to the
+ next, to better blend in with native applications on the platform.
+
+ \table
+ \row
+ \li \image qtquickcontrols2-macos-light.png
+ \caption The macOS style in light theme
+ \li \image qtquickcontrols2-macos-dark.png
+ \caption The macOS style in dark theme
+ \endtable
+
+ To run an application with the macOS style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \section2 Current state
+
+ The macOS style is under development, and some controls are not yet supported. Those
+ controls are: \l BusyIndicator, \l DelayButton, \l PageIndicator, \l RangeSlider, \l Switch, \l TabBar and
+ \l Tumbler. Those will fall back to use the \l {Fusion Style}.
+
+ \section2 Customization
+
+ The goal of the macOS style is to for the controls look and feel as similar as possible to the
+ native controls in UIKit. The style will follow the theme and colors configured globally from
+ System Preferences, and does not come with a separate customization API on top of that.
+
+ \note The macOS style is not suitable for \l {Customizing Qt Quick Controls}{customizing}.
+ The main reason is that it sometimes draw both the contents and the background
+ onto a single background item, which will not look good together with a custom contentItem.
+ It also tends to use padding and inset values that are different from the other styles.
+ \include customizing-native-styles.qdocinc
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-material.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-material.qdoc
new file mode 100644
index 0000000000..f08c5ec3ba
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-material.qdoc
@@ -0,0 +1,404 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-material.html
+ \title Material Style
+
+ The Material Style is based on the Google Material Design Guidelines.
+ \l{detailed-desc-material}{More...}
+
+ \styleimport {QtQuick.Controls.Material 2.12} {Qt 5.7}
+
+ \section1 Attached Properties
+
+ \list
+ \li \l {material-accent-attached-prop}{\b accent} : color
+ \li \l {material-background-attached-prop}{\b background} : color
+ \li \l {material-elevation-attached-prop}{\b elevation} : int
+ \li \l {material-foreground-attached-prop}{\b foreground} : color
+ \li \l {material-primary-attached-prop}{\b primary} : color
+ \li \l {material-theme-attached-prop}{\b theme} : enumeration
+ \endlist
+
+ \section1 Attached Methods
+
+ \list
+ \li color \l {material-color-attached-method}{\b color}(enumeration predefined, enumeration shade)
+ \endlist
+
+ \section1 Detailed Description
+ \target detailed-desc-material
+
+ The Material style is based on the \l {https://www.google.com/design/spec/material-design/introduction.html}
+ {Google Material Design Guidelines}. It allows for a unified experience
+ across platforms and device sizes.
+
+ \table
+ \row
+ \li \image qtquickcontrols2-material-light.png
+ \caption The Material style in light theme
+ \li \image qtquickcontrols2-material-dark.png
+ \caption The Material style in dark theme
+ \endtable
+
+ To run an application with the Material style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \note The Material style is not a native Android style. The Material
+ style is a 100% cross-platform Qt Quick Controls style implementation that
+ follows the Google Material Design Guidelines. The style runs on any
+ platform, and looks more or less identical everywhere. Minor differences
+ may occur due to differences in available system fonts and font rendering
+ engines.
+
+ \section2 Customization
+
+ The Material style allows customizing five attributes, \l {material-theme-attached-prop}{theme},
+ \l {material-primary-attached-prop}{primary}, \l {material-accent-attached-prop}{accent},
+ \l {material-foreground-attached-prop}{foreground}, and \l {material-background-attached-prop}{background}.
+
+ \image qtquickcontrols2-material-attributes.png
+
+ All attributes can be specified for any window or item, and they automatically
+ propagate to children in the same manner as \l {Control::font}{fonts}. In the
+ following example, the window and all three radio buttons appear in the dark
+ theme using a purple accent color:
+
+ \table
+ \row
+ \li
+ \qml
+ import QtQuick 2.12
+ import QtQuick.Controls 2.12
+ import QtQuick.Controls.Material 2.12
+
+ ApplicationWindow {
+ visible: true
+
+ Material.theme: Material.Dark
+ Material.accent: Material.Purple
+
+ Column {
+ anchors.centerIn: parent
+
+ RadioButton { text: qsTr("Small") }
+ RadioButton { text: qsTr("Medium"); checked: true }
+ RadioButton { text: qsTr("Large") }
+ }
+ }
+ \endqml
+ \li
+ \image qtquickcontrols2-material-purple.png
+ \endtable
+
+ In addition to specifying the attributes in QML, it is also possible to
+ specify them via environment variables or in a configuration file. Attributes
+ specified in QML take precedence over all other methods.
+
+ \section3 Configuration File
+
+ \include qquickmaterialstyle.qdocinc conf
+
+ See \l {Qt Quick Controls Configuration File} for more details about the
+ configuration file.
+
+ \section3 Environment Variables
+
+ \include qquickmaterialstyle.qdocinc env
+
+ See \l {Supported Environment Variables in Qt Quick Controls} for the full
+ list of supported environment variables.
+
+ \section2 Dependency
+
+ The Material style must be separately imported to gain access to the
+ attributes that are specific to the Material style. It should be noted
+ that regardless of the references to the Material style, the same
+ application code runs with any other style. Material-specific attributes
+ only have an effect when the application is run with the Material style.
+
+ If the Material style is imported in a QML file that is always loaded, the
+ Material style must be deployed with the application in order to be able
+ to run the application regardless of which style the application is run with.
+ By using \l {Using File Selectors with Qt Quick Controls}{file selectors},
+ style-specific tweaks can be applied without creating a hard dependency to
+ a style.
+
+ \section2 Pre-defined Material Colors
+
+ Even though primary and accent can be any \l {colorbasictypedocs}{color}, it
+ is recommended to use one of the pre-defined colors that have been designed
+ to work well with the rest of the Material style palette:
+
+ Available pre-defined colors:
+ \value Material.Red \stylecolor {#F44336} {}
+ \value Material.Pink \stylecolor {#E91E63} {(default accent)}
+ \value Material.Purple \stylecolor {#9C27B0} {}
+ \value Material.DeepPurple \stylecolor {#673AB7} {}
+ \value Material.Indigo \stylecolor {#3F51B5} {(default primary)}
+ \value Material.Blue \stylecolor {#2196F3} {}
+ \value Material.LightBlue \stylecolor {#03A9F4} {}
+ \value Material.Cyan \stylecolor {#00BCD4} {}
+ \value Material.Teal \stylecolor {#009688} {}
+ \value Material.Green \stylecolor {#4CAF50} {}
+ \value Material.LightGreen \stylecolor {#8BC34A} {}
+ \value Material.Lime \stylecolor {#CDDC39} {}
+ \value Material.Yellow \stylecolor {#FFEB3B} {}
+ \value Material.Amber \stylecolor {#FFC107} {}
+ \value Material.Orange \stylecolor {#FF9800} {}
+ \value Material.DeepOrange \stylecolor {#FF5722} {}
+ \value Material.Brown \stylecolor {#795548} {}
+ \value Material.Grey \stylecolor {#9E9E9E} {}
+ \value Material.BlueGrey \stylecolor {#607D8B} {}
+
+ When the dark theme is in use, different \l {Pre-defined Shades}{shades} of
+ the pre-defined colors are used by default:
+
+ \value Material.Red \stylecolor {#EF9A9A} {}
+ \value Material.Pink \stylecolor {#F48FB1} {(default accent)}
+ \value Material.Purple \stylecolor {#CE93D8} {}
+ \value Material.DeepPurple \stylecolor {#B39DDB} {}
+ \value Material.Indigo \stylecolor {#9FA8DA} {(default primary)}
+ \value Material.Blue \stylecolor {#90CAF9} {}
+ \value Material.LightBlue \stylecolor {#81D4FA} {}
+ \value Material.Cyan \stylecolor {#80DEEA} {}
+ \value Material.Teal \stylecolor {#80CBC4} {}
+ \value Material.Green \stylecolor {#A5D6A7} {}
+ \value Material.LightGreen \stylecolor {#C5E1A5} {}
+ \value Material.Lime \stylecolor {#E6EE9C} {}
+ \value Material.Yellow \stylecolor {#FFF59D} {}
+ \value Material.Amber \stylecolor {#FFE082} {}
+ \value Material.Orange \stylecolor {#FFCC80} {}
+ \value Material.DeepOrange \stylecolor {#FFAB91} {}
+ \value Material.Brown \stylecolor {#BCAAA4} {}
+ \value Material.Grey \stylecolor {#EEEEEE} {}
+ \value Material.BlueGrey \stylecolor {#B0BEC5} {}
+
+ \section2 Pre-defined Shades
+
+ There are several different
+ \l {https://material.google.com/style/color.html#color-color-palette}{shades}
+ of each \l {Pre-defined Material Colors}{pre-defined color} that can be passed
+ to the \l {material-color-attached-method}{Material.color()} function:
+ \value Material.Shade50
+ \value Material.Shade100
+ \value Material.Shade200
+ \value Material.Shade300
+ \value Material.Shade400
+ \value Material.Shade500
+ \value Material.Shade600
+ \value Material.Shade700
+ \value Material.Shade800
+ \value Material.Shade900
+ \value Material.ShadeA100
+ \value Material.ShadeA200
+ \value Material.ShadeA400
+ \value Material.ShadeA700
+
+ \b {See also} \l {Basic Style}, \l {Universal Style}
+
+ \section2 Variants
+
+ The Material style also supports a dense variant, where controls like
+ buttons and delegates are smaller in height and use smaller font sizes.
+ It is recommended to use the dense variant on desktop platforms, where
+ a mouse and keyboard allow more precise and flexible user interaction.
+
+ To use the dense variant, either set the
+ \c QT_QUICK_CONTROLS_MATERIAL_VARIANT environment variable to \c Dense,
+ or specify \c Variant=Dense in the
+ \l {Qt Quick Controls Configuration File}{qtquickcontrols2.conf} file.
+ The default value in both cases is \c Normal.
+
+ The following images illustrate the differences between some of the
+ controls when using the normal and dense variants:
+
+ \table
+ \row
+ \li
+ \image qtquickcontrols2-material-variant-normal.png
+ \li
+ \image qtquickcontrols2-material-variant-dense.png
+ \endtable
+
+ Note that the heights shown above may vary based on differences in fonts
+ across platforms.
+
+ \section1 Attached Property Documentation
+
+ \styleproperty {Material.accent} {color} {material-accent-attached-prop}
+ \target material-accent-attached-prop
+ This attached property holds the accent color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is \c Material.Pink.
+
+ In the following example, the accent color of the highlighted button is
+ changed to \c Material.Orange:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-material-accent.qml 1
+ \li
+ \image qtquickcontrols2-material-accent.png
+ \endtable
+
+ \note Even though the accent can be any \l {colorbasictypedocs}{color}, it is
+ recommended to use one of the \l {pre-defined Material colors} that have been
+ designed to work well with the rest of the Material style palette.
+
+ \endstyleproperty
+
+ \styleproperty {Material.background} {color} {material-background-attached-prop}
+ \target material-background-attached-prop
+ This attached property holds the background color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is theme-specific (light or dark).
+
+ In the following example, the background color of the button is changed to
+ \c Material.Teal:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-material-background.qml 1
+ \li
+ \image qtquickcontrols2-material-background.png
+ \endtable
+
+ \endstyleproperty
+
+ \styleproperty {Material.elevation} {int} {material-elevation-attached-prop}
+ \target material-elevation-attached-prop
+ This attached property holds the elevation of the control. The higher the
+ elevation, the deeper the shadow. The property can be attached to any control,
+ but not all controls visualize elevation.
+
+ The default value is control-specific.
+
+ In the following example, the elevation of the pane is set to \c 6
+ in order to achieve the look of an
+ \l {https://material.google.com/components/cards.html}{elevated card}:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-material-elevation.qml 1
+ \li
+ \image qtquickcontrols2-material-elevation.png
+ \endtable
+
+ \endstyleproperty
+
+ \styleproperty {Material.foreground} {color} {material-foreground-attached-prop}
+ \target material-foreground-attached-prop
+ This attached property holds the foreground color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is theme-specific (light or dark).
+
+ In the following example, the foreground color of the button is set to \c
+ Material.Pink:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-material-foreground.qml 1
+ \li
+ \image qtquickcontrols2-material-foreground.png
+ \endtable
+
+ \endstyleproperty
+
+ \styleproperty {Material.primary} {color} {material-primary-attached-prop}
+ \target material-primary-attached-prop
+ This attached property holds the primary color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The primary color is used as the background color of ToolBar by default.
+
+ The default value is \c Material.Indigo.
+
+ \note Even though the primary can be any \l {colorbasictypedocs}{color}, it is
+ recommended to use one of the \l {pre-defined Material colors} that have been
+ designed to work well with the rest of the Material style palette.
+
+ \endstyleproperty
+
+ \styleproperty {Material.theme} {enumeration} {material-theme-attached-prop}
+ \target material-theme-attached-prop
+ This attached property holds whether the theme is light or dark. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ Available themes:
+ \value Material.Light Light theme (default)
+ \value Material.Dark Dark theme
+ \value Material.System System theme
+
+ Setting the theme to \c System chooses either the light or dark theme based
+ on the system theme colors. However, when reading the value of the theme
+ property, the value is never \c System, but the actual theme.
+
+ In the following example, the theme for both the pane and the button is set
+ to \c Material.Dark:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-material-theme.qml 1
+ \li
+ \image qtquickcontrols2-material-theme.png
+ \endtable
+
+ \endstyleproperty
+
+ \section1 Attached Method Documentation
+
+ \stylemethod2 {color} {color} {enumeration} {predefined} {enumeration} {shade} {material-color-attached-method}
+ \target material-color-attached-method
+ This attached method returns the effective color value of the specified
+ \l {pre-defined Material colors}{pre-defined Material color} combined with
+ the given \l {pre-defined shades}{shade}. If omitted, the shade argument
+ defaults to \c Material.Shade500.
+
+ \qml
+ Rectangle {
+ color: Material.color(Material.Red)
+ }
+ \endqml
+
+ \endstylemethod2
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-menus.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-menus.qdoc
new file mode 100644
index 0000000000..43db20927c
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-menus.qdoc
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-menus.html
+ \title Menu Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for menu controls
+
+ \annotatedlist qtquickcontrols2-menus
+
+ Each type of menu control has its own specific target use case. The
+ following sections offer guidelines for choosing the appropriate type
+ of menu control, depending on the use case.
+
+ \section1 Menu Control
+
+ \image qtquickcontrols2-menu.png
+
+ \l Menu control can be used for context menus; for example, after
+ right-clicking. It can also be used for popup menus; for example, a
+ menu that is shown after clicking a button.
+
+ \l MenuItem is an item in the Menu control. Each item in a menu:
+ \list
+ \li displays text to the user
+ \li allows checking/unchecking
+ \li is highlighted (for example, on keyboard navigation)
+ \li performs some action on activation
+ \endlist
+
+ \section1 MenuBar Control
+
+ \image qtquickcontrols2-menubar.png
+
+ \l MenuBar control can be used for window menu bars.
+
+ \l MenuBarItem is an item in the MenuBar control. Each item in a menu bar:
+ \list
+ \li displays text to the user
+ \li is highlighted (for example, on keyboard navigation)
+ \li pops up the respective menu on activation
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-navigation.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-navigation.qdoc
new file mode 100644
index 0000000000..95928d1342
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-navigation.qdoc
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-navigation.html
+ \title Navigation Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for navigation controls
+
+ Qt Quick Controls offers a selection of navigation models.
+
+ \annotatedlist qtquickcontrols2-navigation
+
+ The following sections offer guidelines for choosing the appropriate type
+ of navigation model, depending on the use case.
+
+ \section1 StackView Control
+
+ \image qtquickcontrols2-stackview-wireframe.png
+
+ \l StackView provides a stack-based navigation model which can be used
+ with a set of interlinked pages. StackView works according to a last-in
+ first-out principle: the page pushed last on the stack is the one visible.
+ Popping a page removes the last page and makes the previous one visible.
+
+ \section1 SwipeView Control
+
+ \image qtquickcontrols2-swipeview-wireframe.png
+
+ \l SwipeView provides a navigation model that simplifies horizontal paged
+ scrolling. The page indicator on the bottom shows which is the presently
+ active page.
+
+ \section1 TabBar Control
+
+ \image qtquickcontrols2-tabbar-wireframe.png
+
+ \l TabBar is a bar with icons or text that allows the user to switch
+ between different subtasks, views, or modes.
+
+ \section1 TabButton Control
+
+ \image qtquickcontrols2-tabbutton.png
+
+ \l TabButton is a button with a layout suitable for a TabBar control.
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-popups.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-popups.qdoc
new file mode 100644
index 0000000000..c26b4c4bf1
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-popups.qdoc
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-popups.html
+ \title Popup Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for popup controls
+
+ \annotatedlist qtquickcontrols2-popups
+
+ Each type of popup control has its own specific target use case. The
+ following sections offer guidelines for choosing the appropriate type
+ of popup control, depending on the use case.
+
+ \section1 Drawer Control
+
+ \image qtquickcontrols2-drawer-expanded-wireframe.png
+
+ \l Drawer provides a swipe-based side panel, similar to those often used
+ in touch interfaces to provide a central location for navigation.
+
+ The drawer can be positioned at any of the four edges of the screen. It allows
+ the user to add navigation without taking up valuable screen space. The user can
+ show and hide the drawer at any time with a simple swipe movement.
+
+ \section1 Menu Control
+
+ \image qtquickcontrols2-menu.png
+
+ The \l Menu control displays a vertical list of items that can be selected. It can
+ be used for offering a list of actions that can be taken in a given context.
+
+ \b {See also} \l {Drawer Control}.
+
+ \section1 Popup Control
+
+ \image qtquickcontrols2-popup-settings.png
+
+ A \l Popup displays content over other application content.
+ It prompts the user to make a decision or enter information.
+
+ Popups can be modal or non-modal. A modal popup blocks users from interacting
+ with the application until they have made a choice and closed the popup.
+
+ A popup can be used for:
+
+ \list
+ \li communicating a message to the user that they must read and acknowledge.
+ \li displaying an error message.
+ \li prompting the user to make a choice and/or enter a value.
+ \endlist
+
+ \section1 ToolTip Control
+
+ \image qtquickcontrols2-tooltip.png
+
+ \l ToolTip shows a short piece of text that informs the user of a control's
+ function. It is typically placed above or below the parent control.
+
+ Recommendations:
+ \list
+ \li Use a tooltip if a control has little or no descriptive text, or needs
+ a short explanation.
+ \li Use a tooltip only if the information on a particular control is not
+ available elsewhere in the screen.
+ \li Keep the tooltip text short so that it does not cover other content
+ while being displayed.
+ \endlist
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-qmltypes.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-qmltypes.qdoc
new file mode 100644
index 0000000000..7e8d4a06c1
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-qmltypes.qdoc
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule QtQuick.Controls
+ \keyword Qt Quick Controls QML Types
+ \title Qt Quick Controls QML Types
+ \keyword Qt Quick Controls 2 QML Types
+ \ingroup qmlmodules
+ \brief Provides QML types for user interfaces (Qt Quick Controls).
+
+ \l{Qt Quick Controls} provides QML types for creating user interfaces.
+ These QML types work in conjunction with \l{Qt Quick} and
+ \l{Qt Quick Layouts}.
+
+ Qt Quick Controls QML types can be imported into your application
+ using the following import statement in your .qml file:
+
+ \qml
+ import QtQuick.Controls
+ \endqml
+
+ \section1 QML Types
+ \generatelist {qmltypesbymodule QtQuick.Controls}
+ \noautolist
+
+ \section1 Using Qt Quick Controls types in property declarations
+
+ As mentioned in \l {Qt Quick Templates 2 QML Types}, each type in Qt Quick
+ Controls is backed by a C++ "template" type. These types are \l {Qt Quick
+ Templates 2}{non-visual implementations of controls' logic and behavior}.
+
+ For example, the \l Menu type's API and behavior is defined by the C++
+ type in Qt Quick Templates. Each \l {Definition of a Style}{style} that
+ wants to provide a Menu must have a Menu.qml available, and the root
+ item in that file must be the Menu from Qt Quick Templates. When you
+ import QtQuick.Controls and create a Menu in QML, the type you get is
+ actually the QML Menu defined by the style's Menu.qml.
+
+ In order to use a control as the type in a property declaration, you should
+ use the corresponding type from Qt Quick Templates. For example, suppose
+ you had a \c PopupOpener component, which was a Button that opened a
+ Popup:
+
+ \qml
+ // PopupButton.qml
+ import QtQuick.Controls
+
+ Button {
+ required property Popup popup
+
+ onClicked: popup.open()
+ }
+
+ // main.qml
+ PopupButton {
+ popup: saveChangesDialog
+ }
+
+ Dialog {
+ id: saveChangesDialog
+
+ // ...
+ }
+ \endqml
+
+ Running this code will result in an error:
+
+ \badcode
+ Unable to assign Dialog_QMLTYPE to Popup_QMLTYPE
+ \endcode
+
+ This is because of the inheritance hierarchy:
+
+ \badcode
+ Popup (C++ type in QtQuick.Templates)
+ │ └── Popup (QML type in QtQuick.Controls)
+ └── Dialog (C++ type in QtQuick.Templates)
+ └── Dialog (QML type in QtQuick.Controls)
+ \endcode
+
+ Dialog from \c QtQuick.Controls does not derive from the Popup from
+ \c QtQuick.Controls, but from \c QtQuick.Templates.
+
+ Instead, use the Popup from Qt Quick Templates as the property type:
+
+ \qml
+ // PopupButton.qml
+ import QtQuick.Controls
+ import QtQuick.Templates as T
+
+ Button {
+ required property T.Popup popup
+
+ onClicked: popup.open()
+ }
+ \endqml
+
+ For more information on the Qt Quick Controls module, see the
+ \l {Qt Quick Controls} module documentation.
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-separators.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-separators.qdoc
new file mode 100644
index 0000000000..481a744ed0
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-separators.qdoc
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-separators.html
+ \title Separator Controls
+ \ingroup qtquickcontrols2-guidelines
+ \brief Guidelines for separator controls
+
+ Qt Quick Controls offers a selection of separators.
+
+ \annotatedlist qtquickcontrols2-separators
+
+ Each type of separator has its own specific use case. The following
+ sections offer guidelines for choosing the appropriate type of separator,
+ depending on the use case.
+
+ \section1 MenuSeparator Control
+
+ \image qtquickcontrols2-menuseparator.png
+
+ \l MenuSeparator should be used to separate items (typically MenuItem
+ controls) in a Menu. Grouping related menu items together makes it easier
+ for the user to interact with the menu. For example, a typical desktop
+ user interface might have \c Undo and \c Redo items in one group, and
+ \c Cut, \c Copy and \c Paste in another.
+
+ \section1 ToolSeparator Control
+
+ \image qtquickcontrols2-toolseparator.png
+
+ \l ToolSeparator should be used to separate items (typically ToolButton
+ controls) in a ToolBar. It can be used in horizontal or vertical toolbars.
+
+ \section1 Related Information
+ \list
+ \li \l {Qt Quick Controls Guidelines}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-styles.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-styles.qdoc
new file mode 100644
index 0000000000..4273c47264
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-styles.qdoc
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-styles.html
+ \title Styling Qt Quick Controls
+
+ \section1 Available Styles
+
+ Qt Quick Controls comes with a selection of styles.
+
+ \section2 Basic Style
+
+ \image qtquickcontrols2-basic-thumbnail.png
+ The \l {Basic Style} is a simple and light-weight all-round style that offers
+ the maximum performance for Qt Quick Controls.
+
+ \section2 Fusion Style
+
+ \image qtquickcontrols2-fusion-thumbnail.png
+ The \l {Fusion Style} is a platform-agnostic style that offers a desktop-oriented
+ look and feel for Qt Quick Controls.
+
+ \section2 Imagine Style
+
+ \image qtquickcontrols2-imagine-thumbnail.png
+ The \l {Imagine Style} is based on image assets. The style comes with a default
+ set of images which can easily be changed by providing a directory
+ with images using a predefined naming convention.
+
+ \section2 macOS Style
+
+ \image qtquickcontrols2-macos-thumbnail.png
+ The \l {macOS Style} is a native-looking style for macOS.
+ \note this style is only available for applications running on macOS.
+
+ \section2 Material Style
+
+ \image qtquickcontrols2-material-thumbnail.png
+ The \l {Material Style} offers an appealing design based on the
+ \l {https://www.google.com/design/spec/material-design/introduction.html}
+ {Google Material Design Guidelines}, but requires more system resources than
+ the Basic style.
+
+ \section2 Universal Style
+
+ \image qtquickcontrols2-universal-thumbnail.png
+ The \l {Universal Style} offers an appealing design based on the
+ \l {https://dev.windows.com/design}{Microsoft Universal Design Guidelines},
+ but requires more system resources than the Basic style.
+
+ \section2 Windows Style
+
+ \image qtquickcontrols2-windows-thumbnail.png
+ The \l {Windows Style} is a native-looking style for Windows.
+ \note this style is only available for applications running on Windows.
+
+ \section1 Using Styles in Qt Quick Controls
+
+ \section2 Default Styles
+
+ If no style is explicitly set, a default style will be used. The style that
+ is used depends on the operating system:
+
+ \list
+ \li Android: \l {Material Style}
+ \li Linux: \l {Fusion Style}
+ \li macOS: \l {macOS Style}
+ \li Windows: \l {Windows Style}
+ \endlist
+
+ For all other operating systems, the \l {Basic Style} is used.
+
+ \section2 Compile-Time Style Selection
+
+ Compile-time style selection is a way of specifying a style to use by
+ importing it in QML. For example, to import the Material style:
+
+ \qml
+ import QtQuick.Controls.Material
+
+ ApplicationWindow {
+ // ...
+ }
+ \endqml
+
+ Notice that QtQuick.Controls (which is responsible for run-time style
+ selection) is not imported. The fallback style is specified by the qmldir
+ of the style:
+
+ \badcode
+ module QtQuick.Controls.Material
+ # ...
+ import QtQuick.Controls.Basic auto
+ \endcode
+
+ The benefit of compile-time style selection is that the QtQuick.Controls plugin
+ is not used and therefore does not need to be deployed with the application.
+
+ Explicit imports are also necessary if your application is built
+ \l {Static Builds}{statically}.
+
+ \section2 Run-Time Style Selection
+
+ Run-time style selection is a way of specifying a style to use by importing
+ \c QtQuick.Controls:
+
+ \qml
+ import QtQuick.Controls
+ \endqml
+
+ The QtQuick.Controls plugin will import the style and fallback
+ style that were set at runtime via one of the following approaches:
+
+ \list
+ \li \l[CPP]{QQuickStyle::setStyle()}
+ \li The \c -style command line argument
+ \li The \c QT_QUICK_CONTROLS_STYLE environment variable
+ \li The \c qtquickcontrols2.conf configuration file
+ \endlist
+
+ The priority of these approaches follows the order they are listed,
+ from highest to lowest. That is, using \c QQuickStyle to set the style will
+ always take priority over using the command line argument, for example.
+
+ The benefit of run-time style selection is that a single application binary
+ can support multiple styles, meaning that the end user can choose which
+ style to run the application with.
+
+ \section3 Using QQuickStyle in C++
+
+ \l[CPP]{QQuickStyle} provides C++ API for configuring a specific
+ style. The following example runs a Qt Quick Controls application
+ with the Material style:
+
+ \code
+ QQuickStyle::setStyle("Material");
+ \endcode
+
+ See the detailed description of \l[CPP]{QQuickStyle} for more
+ details.
+
+ \section3 Command line argument
+
+ Passing a \c -style command line argument is the convenient way to test different
+ styles. It takes precedence over the other methods listed below. The following
+ example runs a Qt Quick Controls application with the Material style:
+
+ \code
+ ./app -style material
+ \endcode
+
+ \section3 Environment variable
+
+ Setting the \c QT_QUICK_CONTROLS_STYLE environment variable can be used to set
+ a system-wide style preference. It takes precedence over the configuration file
+ mentioned below. The following example runs a Qt Quick Controls application with
+ the Universal style:
+
+ \code
+ QT_QUICK_CONTROLS_STYLE=universal ./app
+ \endcode
+
+ See \l {Supported Environment Variables in Qt Quick Controls} for the full list
+ of supported environment variables.
+
+ \section3 Configuration file
+
+ Qt Quick Controls support a special configuration file, \c :/qtquickcontrols2.conf,
+ that is built into an application's resources.
+
+ The configuration file can specify the preferred style (may be overridden by either
+ of the methods described earlier) and certain style-specific attributes. The following
+ example specifies that the preferred style is the Material style.
+
+ \code
+ [Controls]
+ Style=Material
+ \endcode
+
+ See \l {Qt Quick Controls Configuration File} for more details about the
+ configuration file.
+
+ \section1 Related Information
+ \list
+ \li \l {Basic Style}
+ \li \l {Fusion Style}
+ \li \l {Imagine Style}
+ \li \l {Material Style}
+ \li \l {Universal Style}
+ \li \l {Customizing Qt Quick Controls}
+ \li \l {Using File Selectors with Qt Quick Controls}
+ \li \l {Deploying Qt Quick Controls Applications}
+ \li \l {Qt Quick Controls Configuration File}
+ \li \l {Supported Environment Variables in Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-universal.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-universal.qdoc
new file mode 100644
index 0000000000..7226705068
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-universal.qdoc
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-universal.html
+ \title Universal Style
+
+ The Universal Style is based on the Microsoft Universal Design Guidelines.
+ \l {detailed-desc-universal}{More...}
+
+ \styleimport {QtQuick.Controls.Universal 2.12} {Qt 5.7}
+
+ \section1 Attached Properties
+
+ \list
+ \li \l {universal-accent-attached-prop}{\b accent} : color
+ \li \l {universal-background-attached-prop}{\b background} : color
+ \li \l {universal-foreground-attached-prop}{\b foreground} : color
+ \li \l {universal-theme-attached-prop}{\b theme} : enumeration
+ \endlist
+
+ \section1 Attached Methods
+
+ \list
+ \li color \l {color-attached-method}{\b color}(enumeration predefined)
+ \endlist
+
+ \section1 Detailed Description
+ \target detailed-desc-universal
+
+ The Universal style is a device-agnostic style based on the
+ \l {https://dev.windows.com/design}{Microsoft Universal Design Guidelines}.
+ The Universal style has been designed to look good on all devices, from
+ phones and tablets to PCs.
+
+ \table
+ \row
+ \li \image qtquickcontrols2-universal-light.png
+ \caption The Universal style in light theme
+ \li \image qtquickcontrols2-universal-dark.png
+ \caption The Universal style in dark theme
+ \endtable
+
+ To run an application with the Universal style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \note The Universal style is not a native Windows 10 style. The Universal
+ style is a 100% cross-platform Qt Quick Controls style implementation that
+ follows the Microsoft Universal Design Guidelines. The style runs on any
+ platform, and looks more or less identical everywhere. Minor differences
+ may occur due to differences in available system fonts and font rendering
+ engines.
+
+ \section2 Customization
+
+ The Universal style allows customizing four attributes, \l {universal-theme-attached-prop}{theme},
+ \l {universal-accent-attached-prop}{accent}, \l {universal-foreground-attached-prop}{foreground}, and
+ \l {universal-background-attached-prop}{background}.
+
+ \image qtquickcontrols2-universal-attributes.png
+
+ Both attributes can be specified for any window or item, and they automatically
+ propagate to children in the same manner as \l {Control::font}{fonts}. In the
+ following example, the window and all three radio buttons appear in the dark
+ theme using a violet accent color:
+
+ \table
+ \row
+ \li
+ \qml
+ import QtQuick 2.12
+ import QtQuick.Controls 2.12
+ import QtQuick.Controls.Universal 2.12
+
+ ApplicationWindow {
+ visible: true
+
+ Universal.theme: Universal.Dark
+ Universal.accent: Universal.Violet
+
+ Column {
+ anchors.centerIn: parent
+
+ RadioButton { text: qsTr("Small") }
+ RadioButton { text: qsTr("Medium"); checked: true }
+ RadioButton { text: qsTr("Large") }
+ }
+ }
+ \endqml
+ \li
+ \image qtquickcontrols2-universal-violet.png
+ \endtable
+
+ In addition to specifying the attributes in QML, it is also possible to
+ specify them via environment variables or in a configuration file. Attributes
+ specified in QML take precedence over all other methods.
+
+ \section3 Configuration File
+
+ \include qquickuniversalstyle.qdocinc conf
+
+ See \l {Qt Quick Controls Configuration File} for more details about the
+ configuration file.
+
+ \section3 Environment Variables
+
+ \include qquickuniversalstyle.qdocinc env
+
+ See \l {Supported Environment Variables in Qt Quick Controls} for the full
+ list of supported environment variables.
+
+ \section2 Dependency
+
+ The Universal style must be separately imported to gain access to the
+ attributes that are specific to the Universal style. It should be noted
+ that regardless of the references to the Universal style, the same
+ application code runs with any other style. Universal-specific attributes
+ only have an effect when the application is run with the Universal style.
+
+ If the Universal style is imported in a QML file that is always loaded, the
+ Universal style must be deployed with the application in order to be able
+ to run the application regardless of which style the application is run with.
+ By using \l {Using File Selectors with Qt Quick Controls}{file selectors},
+ style-specific tweaks can be applied without creating a hard dependency to
+ a style.
+
+ \section2 Pre-defined Universal Colors
+
+ Available pre-defined colors:
+ \value Universal.Lime \stylecolor {#A4C400} {}
+ \value Universal.Green \stylecolor {#60A917} {}
+ \value Universal.Emerald \stylecolor {#008A00} {}
+ \value Universal.Teal \stylecolor {#00ABA9} {}
+ \value Universal.Cyan \stylecolor {#1BA1E2} {}
+ \value Universal.Cobalt \stylecolor {#3E65FF} {(default accent)}
+ \value Universal.Indigo \stylecolor {#6A00FF} {}
+ \value Universal.Violet \stylecolor {#AA00FF} {}
+ \value Universal.Pink \stylecolor {#F472D0} {}
+ \value Universal.Magenta \stylecolor {#D80073} {}
+ \value Universal.Crimson \stylecolor {#A20025} {}
+ \value Universal.Red \stylecolor {#E51400} {}
+ \value Universal.Orange \stylecolor {#FA6800} {}
+ \value Universal.Amber \stylecolor {#F0A30A} {}
+ \value Universal.Yellow \stylecolor {#E3C800} {}
+ \value Universal.Brown \stylecolor {#825A2C} {}
+ \value Universal.Olive \stylecolor {#6D8764} {}
+ \value Universal.Steel \stylecolor {#647687} {}
+ \value Universal.Mauve \stylecolor {#76608A} {}
+ \value Universal.Taupe \stylecolor {#87794E} {}
+
+ \b {See also} \l {Basic Style}, \l {Material Style}
+
+ \section1 Attached Property Documentation
+
+ \styleproperty {Universal.accent} {color} {universal-accent-attached-prop}
+ \target universal-accent-attached-prop
+ This attached property holds the accent color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is \c Universal.Cobalt.
+
+ In the following example, the accent color of the highlighted button is
+ changed to \c Universal.Orange:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-universal-accent.qml 1
+ \li
+ \image qtquickcontrols2-universal-accent.png
+ \endtable
+
+ \note Even though the accent can be any \l {colorbasictypedocs}{color}, it is
+ recommended to use one of the \l {pre-defined Universal colors} that have been
+ designed to work well with the rest of the Universal style palette.
+
+ \endstyleproperty
+
+ \styleproperty {Universal.background} {color} {universal-background-attached-prop}
+ \target universal-background-attached-prop
+ This attached property holds the background color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is theme-specific (light or dark).
+
+ In the following example, the background color of the pane is changed to
+ \c Universal.Steel:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-universal-background.qml 1
+ \li
+ \image qtquickcontrols2-universal-background.png
+ \endtable
+
+ \endstyleproperty
+
+ \styleproperty {Universal.foreground} {color} {universal-foreground-attached-prop}
+ \target universal-foreground-attached-prop
+ This attached property holds the foreground color of the theme. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ The default value is theme-specific (light or dark).
+
+ In the following example, the foreground color of the button is set to \c
+ Universal.Pink:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-universal-foreground.qml 1
+ \li
+ \image qtquickcontrols2-universal-foreground.png
+ \endtable
+
+ \styleproperty {Universal.theme} {enumeration} {universal-theme-attached-prop}
+ \target universal-theme-attached-prop
+ This attached property holds whether the theme is light or dark. The property
+ can be attached to any window or item. The value is propagated to children.
+
+ Available themes:
+ \value Universal.Light Light theme (default)
+ \value Universal.Dark Dark theme
+ \value Universal.System System theme
+
+ Setting the theme to \c System chooses either the light or dark theme based
+ on the system theme colors. However, when reading the value of the theme
+ property, the value is never \c System, but the actual theme.
+
+ In the following example, the theme for both the pane and the button is set
+ to \c Universal.Dark:
+
+ \table
+ \row
+ \li
+ \snippet qtquickcontrols2-universal-theme.qml 1
+ \li
+ \image qtquickcontrols2-universal-theme.png
+ \endtable
+
+ \endstyleproperty
+
+ \section1 Attached Method Documentation
+
+ \stylemethod {color} {color} {enumeration} {predefined} {color-attached-method}
+ \target color-attached-method
+ This attached method returns the effective color value of the specified
+ \l {pre-defined Universal colors}{pre-defined Universal color}.
+
+ \qml
+ Rectangle {
+ color: Universal.color(Universal.Red)
+ }
+ \endqml
+
+ \endstylemethod
+
+ \section1 Related Information
+
+ \list
+ \li \l{Styling Qt Quick Controls}
+ \endlist
+*/
diff --git a/src/quickcontrols2/doc/src/qtquickcontrols2-windows.qdoc b/src/quickcontrols2/doc/src/qtquickcontrols2-windows.qdoc
new file mode 100644
index 0000000000..e5e12e712c
--- /dev/null
+++ b/src/quickcontrols2/doc/src/qtquickcontrols2-windows.qdoc
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickcontrols2-Windows.html
+ \title Windows Style
+
+ The Windows style is a style that looks native on Windows.
+ \l {detailed-desc-Windows}{More...}
+
+ \styleimport {QtQuick.Controls.Windows} {Qt 6.0}
+
+ \target detailed-desc-Windows
+
+ The Windows style is a style that looks native on Windows. The controls are drawn run-time using
+ native libraries, and is therefore only available for applications running on Windows.
+
+ \note Be aware that the apperance of this style can change from one minor Qt version to the
+ next, to better blend in with native applications on the platform.
+
+ \table
+ \row
+ \li \image qtquickcontrols2-windows.png
+ \caption The Windows style
+ \endtable
+
+ To run an application with the Windows style, see
+ \l {Using Styles in Qt Quick Controls}.
+
+ \section2 Current state
+
+ The Windows style is under development, and some controls are not yet supported. Those
+ controls are: \l BusyIndicator, \l DelayButton, \l PageIndicator, \l RangeSlider, \l Switch, \l TabBar and
+ \l Tumbler. Those will fall back to use the \l {Fusion Style}.
+
+ \section2 Customization
+
+ The goal of the Windows style is to for the controls look and feel as similar as possible to the
+ native controls on Windows. The style will follow the theme and colors configured globally from
+ Windows Settings, and does not come with a separate customization API on top of that.
+
+ \note The Windows style is not suitable for \l {Customizing Qt Quick Controls}{customizing}.
+ The main reason is that it sometimes draw both the contents and the background
+ onto a single background item, which will not look good together with a custom contentItem.
+ It also tends to use padding and inset values that are different from the other styles.
+ \include customizing-native-styles.qdocinc
+*/
diff --git a/src/quickcontrols2/fusion/ApplicationWindow.qml b/src/quickcontrols2/fusion/ApplicationWindow.qml
new file mode 100644
index 0000000000..090d361c02
--- /dev/null
+++ b/src/quickcontrols2/fusion/ApplicationWindow.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ApplicationWindow {
+ id: window
+
+ color: window.palette.window
+}
diff --git a/src/quickcontrols2/fusion/BusyIndicator.qml b/src/quickcontrols2/fusion/BusyIndicator.qml
new file mode 100644
index 0000000000..ed63782ba7
--- /dev/null
+++ b/src/quickcontrols2/fusion/BusyIndicator.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.BusyIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ contentItem: BusyIndicatorImpl {
+ implicitWidth: 28
+ implicitHeight: 28
+ color: control.palette.text
+
+ running: control.running
+ opacity: control.running ? 1 : 0
+ Behavior on opacity { OpacityAnimator { duration: 250 } }
+
+ RotationAnimator on rotation {
+ running: control.running || control.contentItem.visible
+ from: 0
+ to: 360
+ duration: 1000
+ loops: Animation.Infinite
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/Button.qml b/src/quickcontrols2/fusion/Button.qml
new file mode 100644
index 0000000000..22ce958f89
--- /dev/null
+++ b/src/quickcontrols2/fusion/Button.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 4
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: ButtonPanel {
+ implicitWidth: 80
+ implicitHeight: 24
+
+ control: control
+ visible: !control.flat || control.down || control.checked || control.highlighted || control.visualFocus
+ || (enabled && control.hovered)
+ }
+}
diff --git a/src/quickcontrols2/fusion/CMakeLists.txt b/src/quickcontrols2/fusion/CMakeLists.txt
new file mode 100644
index 0000000000..96f0449836
--- /dev/null
+++ b/src/quickcontrols2/fusion/CMakeLists.txt
@@ -0,0 +1,145 @@
+#####################################################################
+## qtquickcontrols2fusionstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "BusyIndicator.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "CheckDelegate.qml"
+ "ComboBox.qml"
+ "DelayButton.qml"
+ "Dial.qml"
+ "Dialog.qml"
+ "DialogButtonBox.qml"
+ "Drawer.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "HorizontalHeaderView.qml"
+ "ItemDelegate.qml"
+ "Label.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
+ "Page.qml"
+ "PageIndicator.qml"
+ "Pane.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RadioDelegate.qml"
+ "RangeSlider.qml"
+ "RoundButton.qml"
+ "ScrollBar.qml"
+ "ScrollView.qml"
+ "ScrollIndicator.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "SplitView.qml"
+ "SwipeDelegate.qml"
+ "SwitchDelegate.qml"
+ "Switch.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "TextArea.qml"
+ "TextField.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "ToolSeparator.qml"
+ "ToolTip.qml"
+ "Tumbler.qml"
+ "VerticalHeaderView.qml"
+)
+set_source_files_properties(DelayButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(Dialog.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(DialogButtonBox.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(HorizontalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+set_source_files_properties(MenuBar.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuBarItem.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(RoundButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(SplitView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.13;6.0"
+)
+set_source_files_properties(ToolSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(VerticalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2fusionstyleplugin
+ URI "QtQuick.Controls.Fusion"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FusionStylePlugin
+ IMPORTS
+ QtQuick.Controls.Basic/auto
+ PLUGIN_TARGET qtquickcontrols2fusionstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickfusionstyle.cpp qquickfusionstyle_p.h
+ qquickfusiontheme.cpp qquickfusiontheme_p.h
+ qtquickcontrols2fusionstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_internal_add_resource(qtquickcontrols2fusionstyleplugin "qtquickcontrols2fusionstyle"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/Fusion"
+ FILES
+ "images/arrow.png"
+ "images/arrow@2x.png"
+ "images/arrow@3x.png"
+ "images/arrow@4x.png"
+ "images/checkmark.png"
+ "images/checkmark@2x.png"
+ "images/checkmark@3x.png"
+ "images/checkmark@4x.png"
+ "images/progressmask.png"
+ "images/progressmask@2x.png"
+ "images/progressmask@3x.png"
+ "images/progressmask@4x.png"
+)
+
+add_subdirectory(impl)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fusionstyleplugin quickwindow)
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fusionstyleplugin
+ qtquickcontrols2fusionstyleimplplugin)
+
+# Basic style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2fusionstyleplugin
+ qtquickcontrols2basicstyleplugin)
diff --git a/src/quickcontrols2/fusion/CheckBox.qml b/src/quickcontrols2/fusion/CheckBox.qml
new file mode 100644
index 0000000000..ed49a1447e
--- /dev/null
+++ b/src/quickcontrols2/fusion/CheckBox.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+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)
+
+ padding: 6
+ spacing: 6
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/fusion/CheckDelegate.qml b/src/quickcontrols2/fusion/CheckDelegate.qml
new file mode 100644
index 0000000000..93c087e42c
--- /dev/null
+++ b/src/quickcontrols2/fusion/CheckDelegate.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.CheckDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ indicator: CheckIndicator {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickcontrols2/fusion/ComboBox.qml b/src/quickcontrols2/fusion/ComboBox.qml
new file mode 100644
index 0000000000..dfe21f708f
--- /dev/null
+++ b/src/quickcontrols2/fusion/ComboBox.qml
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+ rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+
+ delegate: MenuItem {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/arrow.png"
+ width: 20
+ fillMode: Image.Pad
+ }
+
+ contentItem: T.TextField {
+ topPadding: 4
+ leftPadding: 4 - control.padding
+ rightPadding: 4 - control.padding
+ bottomPadding: 4
+
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+
+ background: PaddedRectangle {
+ clip: true
+ radius: 2
+ padding: 1
+ leftPadding: control.mirrored ? -2 : padding
+ rightPadding: !control.mirrored ? -2 : padding
+ color: control.palette.base
+ visible: control.editable && !control.flat
+
+ Rectangle {
+ x: parent.width - width
+ y: 1
+ width: 1
+ height: parent.height - 2
+ color: Fusion.buttonOutline(control.palette, control.activeFocus, control.enabled)
+ }
+
+ Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 3
+ height: 1
+ color: Fusion.topShadow
+ }
+ }
+
+ Rectangle {
+ x: 1 - control.leftPadding
+ y: 1
+ width: control.width - 2
+ height: control.height - 2
+ color: "transparent"
+ border.color: Color.transparent(Fusion.highlightedOutline(control.palette), 40 / 255)
+ visible: control.activeFocus
+ radius: 1.7
+ }
+ }
+
+ background: ButtonPanel {
+ implicitWidth: 120
+ implicitHeight: 24
+
+ control: control
+ visible: !control.flat || control.down
+ // ### TODO: fix control.contentItem.activeFocus
+ highlighted: control.visualFocus || control.contentItem.activeFocus
+ }
+
+ popup: T.Popup {
+ width: control.width
+ height: Math.min(contentItem.implicitHeight + 2, control.Window.height - topMargin - bottomMargin)
+ topMargin: 6
+ bottomMargin: 6
+ padding: 1
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightRangeMode: ListView.ApplyRange
+ highlightMoveDuration: 0
+
+ T.ScrollBar.vertical: ScrollBar { }
+ }
+
+ background: Rectangle {
+ color: control.popup.palette.window
+ border.color: Fusion.outline(control.palette)
+
+ Rectangle {
+ z: -1
+ x: 1; y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.2
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/DelayButton.qml b/src/quickcontrols2/fusion/DelayButton.qml
new file mode 100644
index 0000000000..239ee6c861
--- /dev/null
+++ b/src/quickcontrols2/fusion/DelayButton.qml
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.DelayButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ transition: Transition {
+ NumberAnimation {
+ duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress)
+ }
+ }
+
+ contentItem: ItemGroup {
+ ClippedText {
+ clip: control.progress > 0
+ clipX: -control.leftPadding + (control.mirrored ? 0 : control.progress * control.width)
+ clipWidth: control.width
+ visible: control.mirrored ? control.progress > 0 : control.progress < 1
+
+ text: control.text
+ font: control.font
+ color: control.mirrored ? control.palette.brightText : control.palette.buttonText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ ClippedText {
+ clip: control.progress > 0
+ clipX: -control.leftPadding
+ clipWidth: (control.mirrored ? 1.0 - control.progress : control.progress) * control.width
+ visible: control.mirrored ? control.progress < 1 : control.progress > 0
+
+ text: control.text
+ font: control.font
+ color: control.mirrored ? control.palette.buttonText : control.palette.brightText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+ }
+
+ background: ButtonPanel {
+ implicitWidth: 80
+ implicitHeight: 24
+
+ control: control
+ highlighted: false
+ scale: control.mirrored ? -1 : 1
+
+ Rectangle {
+ width: control.progress * parent.width
+ height: parent.height
+
+ radius: 2
+ border.color: Qt.darker(Fusion.highlight(control.palette), 1.4)
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.lighter(Fusion.highlight(control.palette), 1.2)
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.highlight(control.palette)
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/Dial.qml b/src/quickcontrols2/fusion/Dial.qml
new file mode 100644
index 0000000000..71bab3a788
--- /dev/null
+++ b/src/quickcontrols2/fusion/Dial.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Dial {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ background: DialImpl {
+ implicitWidth: 100
+ implicitHeight: 100
+ highlight: control.visualFocus
+ }
+
+ handle: KnobImpl {
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+ width: control.width / 7
+ height: control.height / 7
+ transform: [
+ Translate {
+ y: -Math.min(control.background.width, control.background.height) * 0.42 + control.handle.height
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: control.handle.width / 2
+ origin.y: control.handle.height / 2
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols2/fusion/Dialog.qml b/src/quickcontrols2/fusion/Dialog.qml
new file mode 100644
index 0000000000..af7fa4925b
--- /dev/null
+++ b/src/quickcontrols2/fusion/Dialog.qml
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Dialog {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 6
+
+ background: Rectangle {
+ color: control.palette.window
+ border.color: control.palette.mid
+ radius: 2
+
+ Rectangle {
+ z: -1
+ x: 1; y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.2
+ radius: 2
+ }
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 6
+ background: Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 1
+ color: control.palette.window
+ radius: 2
+ }
+ }
+
+ footer: DialogButtonBox {
+ visible: count > 0
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+}
diff --git a/src/quickcontrols2/fusion/DialogButtonBox.qml b/src/quickcontrols2/fusion/DialogButtonBox.qml
new file mode 100644
index 0000000000..a99f142ff5
--- /dev/null
+++ b/src/quickcontrols2/fusion/DialogButtonBox.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.DialogButtonBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 6
+ padding: 6
+ alignment: Qt.AlignRight
+
+ delegate: Button { }
+
+ contentItem: ListView {
+ implicitWidth: contentWidth
+ model: control.contentModel
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ snapMode: ListView.SnapToItem
+ }
+
+ background: Rectangle {
+ implicitHeight: 32
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: control.palette.window
+ radius: 2
+ }
+}
diff --git a/src/quickcontrols2/fusion/Drawer.qml b/src/quickcontrols2/fusion/Drawer.qml
new file mode 100644
index 0000000000..85268b5027
--- /dev/null
+++ b/src/quickcontrols2/fusion/Drawer.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Drawer {
+ id: control
+
+ parent: T.Overlay.overlay
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: control.edge === Qt.BottomEdge
+ leftPadding: control.edge === Qt.RightEdge
+ rightPadding: control.edge === Qt.LeftEdge
+ bottomPadding: control.edge === Qt.TopEdge
+
+ enter: Transition { SmoothedAnimation { velocity: 5 } }
+ exit: Transition { SmoothedAnimation { velocity: 5 } }
+
+ background: Rectangle {
+ color: control.palette.window
+ readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge
+ Rectangle {
+ width: parent.horizontal ? 1 : parent.width
+ height: parent.horizontal ? parent.height : 1
+ color: control.palette.mid
+ x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0
+ y: control.edge === Qt.TopEdge ? parent.height - 1 : 0
+ }
+ Rectangle {
+ width: parent.horizontal ? 1 : parent.width
+ height: parent.horizontal ? parent.height : 1
+ color: control.palette.shadow
+ opacity: 0.2
+ x: control.edge === Qt.LeftEdge ? parent.width : 0
+ y: control.edge === Qt.TopEdge ? parent.height : 0
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+}
diff --git a/src/quickcontrols2/fusion/Frame.qml b/src/quickcontrols2/fusion/Frame.qml
new file mode 100644
index 0000000000..1e1916f123
--- /dev/null
+++ b/src/quickcontrols2/fusion/Frame.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 9
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: Qt.lighter(Fusion.outline(control.palette), 1.08)
+ }
+}
diff --git a/src/quickcontrols2/fusion/GroupBox.qml b/src/quickcontrols2/fusion/GroupBox.qml
new file mode 100644
index 0000000000..943a242709
--- /dev/null
+++ b/src/quickcontrols2/fusion/GroupBox.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 6
+ padding: 9
+ topPadding: padding + (implicitLabelWidth > 0 ? implicitLabelHeight + spacing : 0)
+
+ label: Text {
+ x: control.leftPadding
+ width: control.availableWidth
+
+ text: control.title
+ font: control.font
+ color: control.palette.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ y: control.topPadding - control.bottomPadding
+ width: parent.width
+ height: parent.height - control.topPadding + control.bottomPadding
+
+ radius: 2
+ color: Color.transparent("black", 3 / 255)
+ border.color: Qt.lighter(Fusion.outline(control.palette), 1.08)
+ }
+}
diff --git a/src/quickcontrols2/fusion/HorizontalHeaderView.qml b/src/quickcontrols2/fusion/HorizontalHeaderView.qml
new file mode 100644
index 0000000000..76f42b2985
--- /dev/null
+++ b/src/quickcontrols2/fusion/HorizontalHeaderView.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.HorizontalHeaderView {
+ id: control
+
+ implicitWidth: syncView ? syncView.width : 0
+ implicitHeight: contentHeight
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: text.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(control.height, text.implicitHeight + (cellPadding * 2))
+ border.color: "#cacaca"
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#fbfbfb"
+ }
+ GradientStop {
+ position: 1
+ color: "#e0dfe0"
+ }
+ }
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/ItemDelegate.qml b/src/quickcontrols2/fusion/ItemDelegate.qml
new file mode 100644
index 0000000000..12154d2f4b
--- /dev/null
+++ b/src/quickcontrols2/fusion/ItemDelegate.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickcontrols2/fusion/Label.qml b/src/quickcontrols2/fusion/Label.qml
new file mode 100644
index 0000000000..55db94f9c5
--- /dev/null
+++ b/src/quickcontrols2/fusion/Label.qml
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Label {
+ id: control
+
+ color: control.palette.windowText
+ linkColor: control.palette.link
+}
diff --git a/src/quickcontrols2/fusion/Menu.qml b/src/quickcontrols2/fusion/Menu.qml
new file mode 100644
index 0000000000..7808850ce4
--- /dev/null
+++ b/src/quickcontrols2/fusion/Menu.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+import QtQuick.Window
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 0
+ padding: 1
+ overlap: 2
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height
+ : false
+ clip: true
+ currentIndex: control.currentIndex
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 20
+
+ color: control.palette.base
+ border.color: Fusion.outline(control.palette)
+
+ Rectangle {
+ z: -1
+ x: 1; y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.2
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+}
diff --git a/src/quickcontrols2/fusion/MenuBar.qml b/src/quickcontrols2/fusion/MenuBar.qml
new file mode 100644
index 0000000000..7b6a628ddd
--- /dev/null
+++ b/src/quickcontrols2/fusion/MenuBar.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 20
+
+ color: control.palette.window
+
+ Rectangle {
+ y: parent.height - height
+ width: parent.width
+ height: 1
+ color: Fusion.mergedColors(Qt.darker(control.palette.window, 1.2),
+ Qt.lighter(Fusion.outline(control.palette), 1.4), 60)
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/MenuBarItem.qml b/src/quickcontrols2/fusion/MenuBarItem.qml
new file mode 100644
index 0000000000..336fca0cd6
--- /dev/null
+++ b/src/quickcontrols2/fusion/MenuBarItem.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.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)
+
+ 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.down || control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: Fusion.highlight(control.palette)
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols2/fusion/MenuItem.qml b/src/quickcontrols2/fusion/MenuItem.qml
new file mode 100644
index 0000000000..79468f9da8
--- /dev/null
+++ b/src/quickcontrols2/fusion/MenuItem.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.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)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+ leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
+ rightPadding: control.mirrored ? indicatorPadding : 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 ? Fusion.highlightedText(control.palette) : 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 ? 90 : -90
+ color: control.down || control.hovered || control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/arrow.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: 20
+
+ color: Fusion.highlight(control.palette)
+ visible: control.down || control.highlighted
+ }
+}
diff --git a/src/quickcontrols2/fusion/MenuSeparator.qml b/src/quickcontrols2/fusion/MenuSeparator.qml
new file mode 100644
index 0000000000..b8be640b64
--- /dev/null
+++ b/src/quickcontrols2/fusion/MenuSeparator.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 5
+ verticalPadding: 1
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ color: Qt.lighter(Fusion.darkShade, 1.06)
+ }
+}
diff --git a/src/quickcontrols2/fusion/Page.qml b/src/quickcontrols2/fusion/Page.qml
new file mode 100644
index 0000000000..bf47e23155
--- /dev/null
+++ b/src/quickcontrols2/fusion/Page.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Page {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/fusion/PageIndicator.qml b/src/quickcontrols2/fusion/PageIndicator.qml
new file mode 100644
index 0000000000..0c556cc2ac
--- /dev/null
+++ b/src/quickcontrols2/fusion/PageIndicator.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.PageIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 4
+ spacing: 4
+
+ delegate: Rectangle {
+ implicitWidth: 6
+ implicitHeight: 6
+
+ radius: width / 2
+ color: control.palette.shadow
+
+ opacity: index === currentIndex ? 0.95 : pressed ? 0.75 : 0.45
+
+ required property int index
+
+ Behavior on opacity { OpacityAnimator { duration: 100 } }
+ }
+
+ contentItem: Row {
+ spacing: control.spacing
+
+ Repeater {
+ model: control.count
+ delegate: control.delegate
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/Pane.qml b/src/quickcontrols2/fusion/Pane.qml
new file mode 100644
index 0000000000..9cc4991788
--- /dev/null
+++ b/src/quickcontrols2/fusion/Pane.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Pane {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 9
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+}
diff --git a/src/quickcontrols2/fusion/Popup.qml b/src/quickcontrols2/fusion/Popup.qml
new file mode 100644
index 0000000000..f77ea1d196
--- /dev/null
+++ b/src/quickcontrols2/fusion/Popup.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ background: Rectangle {
+ color: control.palette.window
+ border.color: control.palette.mid
+ radius: 2
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+}
diff --git a/src/quickcontrols2/fusion/ProgressBar.qml b/src/quickcontrols2/fusion/ProgressBar.qml
new file mode 100644
index 0000000000..0ad6b4834a
--- /dev/null
+++ b/src/quickcontrols2/fusion/ProgressBar.qml
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: Item {
+ implicitWidth: 120
+ implicitHeight: 24
+ scale: control.mirrored ? -1 : 1
+
+ Rectangle {
+ height: parent.height
+ width: (control.indeterminate ? 1.0 : control.position) * parent.width
+
+ radius: 2
+ border.color: Qt.darker(Fusion.highlight(control.palette), 1.4)
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.lighter(Fusion.highlight(control.palette), 1.2)
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.highlight(control.palette)
+ }
+ }
+ }
+
+ Item {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ visible: control.indeterminate
+ clip: true
+
+ ColorImage {
+ width: Math.ceil(parent.width / implicitWidth + 1) * implicitWidth
+ height: parent.height
+
+ mirror: control.mirrored
+ fillMode: Image.TileHorizontally
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/progressmask.png"
+ color: Color.transparent(Qt.lighter(Fusion.highlight(control.palette), 1.2), 160 / 255)
+
+ visible: control.indeterminate
+ NumberAnimation on x {
+ running: control.indeterminate && control.visible
+ from: -31 // progressmask.png width
+ to: 0
+ loops: Animation.Infinite
+ duration: 750
+ }
+ }
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 24
+
+ radius: 2
+ color: control.palette.base
+ border.color: Fusion.outline(control.palette)
+
+ Rectangle {
+ x: 1; y: 1; height: 1
+ width: parent.width - 2
+ color: Fusion.topShadow
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/RadioButton.qml b/src/quickcontrols2/fusion/RadioButton.qml
new file mode 100644
index 0000000000..c7796411b3
--- /dev/null
+++ b/src/quickcontrols2/fusion/RadioButton.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+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)
+
+ padding: 6
+ spacing: 6
+
+ indicator: RadioIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/fusion/RadioDelegate.qml b/src/quickcontrols2/fusion/RadioDelegate.qml
new file mode 100644
index 0000000000..4c0d936c00
--- /dev/null
+++ b/src/quickcontrols2/fusion/RadioDelegate.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.RadioDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ indicator: RadioIndicator {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ control: control
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickcontrols2/fusion/RangeSlider.qml b/src/quickcontrols2/fusion/RangeSlider.qml
new file mode 100644
index 0000000000..418bac77d1
--- /dev/null
+++ b/src/quickcontrols2/fusion/RangeSlider.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.RangeSlider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ Math.max(first.implicitHandleWidth,
+ second.implicitHandleWidth) + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ Math.max(first.implicitHandleHeight,
+ second.implicitHandleHeight) + topPadding + bottomPadding)
+
+ first.handle: SliderHandle {
+ x: control.leftPadding + Math.round(control.horizontal ? control.first.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + Math.round(control.horizontal ? (control.availableHeight - height) / 2 : control.first.visualPosition * (control.availableHeight - height))
+
+ palette: control.palette
+ pressed: control.first.pressed
+ hovered: control.first.hovered
+ vertical: control.vertical
+ visualFocus: activeFocus
+ }
+
+ second.handle: SliderHandle {
+ x: control.leftPadding + Math.round(control.horizontal ? control.second.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + Math.round(control.horizontal ? (control.availableHeight - height) / 2 : control.second.visualPosition * (control.availableHeight - height))
+
+ palette: control.palette
+ pressed: control.second.pressed
+ hovered: control.second.hovered
+ vertical: control.vertical
+ visualFocus: activeFocus
+ }
+
+ background: SliderGroove {
+ control: control
+ offset: control.first.position
+ progress: control.second.position
+ visualProgress: control.second.visualPosition
+ }
+}
diff --git a/src/quickcontrols2/fusion/RoundButton.qml b/src/quickcontrols2/fusion/RoundButton.qml
new file mode 100644
index 0000000000..3fa54367cf
--- /dev/null
+++ b/src/quickcontrols2/fusion/RoundButton.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.RoundButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+ visible: !control.flat || control.down || control.checked
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: control.down || control.checked
+ ? Fusion.buttonColor(control.palette, control.highlighted, control.down || control.checked, control.enabled && control.hovered)
+ : Fusion.gradientStart(Fusion.buttonColor(control.palette, control.highlighted, control.down, control.enabled && control.hovered))
+ }
+ GradientStop {
+ position: 1
+ color: control.down || control.checked
+ ? Fusion.buttonColor(control.palette, control.highlighted, control.down || control.checked, control.enabled && control.hovered)
+ : Fusion.gradientStop(Fusion.buttonColor(control.palette, control.highlighted, control.down, control.enabled && control.hovered))
+ }
+ }
+
+ radius: control.radius
+ border.color: Fusion.buttonOutline(control.palette, control.highlighted || control.visualFocus, control.enabled)
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ border.color: Fusion.innerContrastLine
+ color: "transparent"
+ radius: control.radius
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/ScrollBar.qml b/src/quickcontrols2/fusion/ScrollBar.qml
new file mode 100644
index 0000000000..5221e0dfff
--- /dev/null
+++ b/src/quickcontrols2/fusion/ScrollBar.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ScrollBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+ visible: control.policy !== T.ScrollBar.AlwaysOff
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ contentItem: Rectangle {
+ implicitWidth: control.interactive ? 6 : 2
+ implicitHeight: control.interactive ? 6 : 2
+
+ radius: width / 2
+ color: control.pressed ? control.palette.dark : control.palette.mid
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
+ PropertyChanges { target: 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/quickcontrols2/fusion/ScrollIndicator.qml b/src/quickcontrols2/fusion/ScrollIndicator.qml
new file mode 100644
index 0000000000..bf386f6c32
--- /dev/null
+++ b/src/quickcontrols2/fusion/ScrollIndicator.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.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 { target: 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/quickcontrols2/fusion/ScrollView.qml b/src/quickcontrols2/fusion/ScrollView.qml
new file mode 100644
index 0000000000..a6bba9de05
--- /dev/null
+++ b/src/quickcontrols2/fusion/ScrollView.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/fusion/SelectionRectangle.qml b/src/quickcontrols2/fusion/SelectionRectangle.qml
new file mode 100644
index 0000000000..2e6393a07e
--- /dev/null
+++ b/src/quickcontrols2/fusion/SelectionRectangle.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+
+ bottomRightHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+}
diff --git a/src/quickcontrols2/fusion/Slider.qml b/src/quickcontrols2/fusion/Slider.qml
new file mode 100644
index 0000000000..4e20dcfc59
--- /dev/null
+++ b/src/quickcontrols2/fusion/Slider.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ handle: SliderHandle {
+ x: control.leftPadding + Math.round(control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + Math.round(control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+
+ palette: control.palette
+ pressed: control.pressed
+ hovered: control.hovered
+ vertical: control.vertical
+ visualFocus: control.visualFocus
+ }
+
+ background: SliderGroove {
+ control: control
+ progress: control.position
+ visualProgress: control.visualPosition
+ }
+}
diff --git a/src/quickcontrols2/fusion/SpinBox.qml b/src/quickcontrols2/fusion/SpinBox.qml
new file mode 100644
index 0000000000..4ed18f39d6
--- /dev/null
+++ b/src/quickcontrols2/fusion/SpinBox.qml
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth + 2 * padding +
+ Math.max(up.implicitIndicatorWidth,
+ down.implicitIndicatorWidth))
+ implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight,
+ up.implicitIndicatorHeight +
+ down.implicitIndicatorHeight)
+
+ padding: 4
+ leftPadding: padding + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: padding + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ z: 2
+ text: control.displayText
+
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+ }
+
+ up.indicator: PaddedRectangle {
+ x: control.mirrored ? 1 : control.width - width - 1
+ y: 1
+ height: control.height / 2 - 1
+ implicitWidth: 16
+ implicitHeight: 10
+
+ radius: 1.7
+ clip: true
+ topPadding: -2
+ leftPadding: -2
+ color: control.up.pressed ? Fusion.buttonColor(control.palette, false, true, true) : "transparent"
+
+ ColorImage {
+ scale: -1
+ width: parent.width
+ height: parent.height
+ opacity: enabled ? 1.0 : 0.5
+ color: control.palette.buttonText
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/arrow.png"
+ fillMode: Image.Pad
+ }
+ }
+
+ down.indicator: PaddedRectangle {
+ x: control.mirrored ? 1 : control.width - width - 1
+ y: control.height - height - 1
+ height: control.height / 2 - 1
+ implicitWidth: 16
+ implicitHeight: 10
+
+ radius: 1.7
+ clip: true
+ topPadding: -2
+ leftPadding: -2
+ color: control.down.pressed ? Fusion.buttonColor(control.palette, false, true, true) : "transparent"
+
+ ColorImage {
+ width: parent.width
+ height: parent.height
+ opacity: enabled ? 1.0 : 0.5
+ color: control.palette.buttonText
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/arrow.png"
+ fillMode: Image.Pad
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 24
+
+ radius: 2
+ color: control.palette.base
+ border.color: control.activeFocus ? Fusion.highlightedOutline(control.palette) : Fusion.outline(control.palette)
+
+ Rectangle {
+ x: 2
+ y: 1
+ width: parent.width - 4
+ height: 1
+ color: Fusion.topShadow
+ }
+
+ Rectangle {
+ x: control.mirrored ? 1 : parent.width - width - 1
+ y: 1
+ width: Math.max(control.up.indicator ? control.up.indicator.width : 0,
+ control.down.indicator ? control.down.indicator.width : 0) + 1
+ height: parent.height - 2
+
+ radius: 2
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Fusion.gradientStart(Fusion.buttonColor(control.palette, control.visualFocus, false, control.up.hovered || control.down.hovered))
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.gradientStop(Fusion.buttonColor(control.palette, control.visualFocus, false, control.up.hovered || control.down.hovered))
+ }
+ }
+
+ Rectangle {
+ x: control.mirrored ? parent.width - 1 : 0
+ height: parent.height
+ width: 1
+ color: Fusion.outline(control.palette)
+ }
+ }
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: "transparent"
+ border.color: Color.transparent(Fusion.highlightedOutline(control.palette), 40 / 255)
+ visible: control.activeFocus
+ radius: 1.7
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/SplitView.qml b/src/quickcontrols2/fusion/SplitView.qml
new file mode 100644
index 0000000000..9698b82133
--- /dev/null
+++ b/src/quickcontrols2/fusion/SplitView.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+
+T.SplitView {
+ id: control
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ handle: Rectangle {
+ implicitWidth: control.orientation === Qt.Horizontal ? 2 : control.width
+ implicitHeight: control.orientation === Qt.Horizontal ? control.height : 2
+ color: T.SplitHandle.pressed ? control.palette.dark
+ : (enabled && T.SplitHandle.hovered ? control.palette.midlight : control.palette.mid)
+ }
+}
diff --git a/src/quickcontrols2/fusion/SwipeDelegate.qml b/src/quickcontrols2/fusion/SwipeDelegate.qml
new file mode 100644
index 0000000000..ac840f64e8
--- /dev/null
+++ b/src/quickcontrols2/fusion/SwipeDelegate.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.SwipeDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ swipe.transition: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickcontrols2/fusion/Switch.qml b/src/quickcontrols2/fusion/Switch.qml
new file mode 100644
index 0000000000..2e31535b3d
--- /dev/null
+++ b/src/quickcontrols2/fusion/Switch.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/fusion/SwitchDelegate.qml b/src/quickcontrols2/fusion/SwitchDelegate.qml
new file mode 100644
index 0000000000..0439b0cfa5
--- /dev/null
+++ b/src/quickcontrols2/fusion/SwitchDelegate.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.SwitchDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickcontrols2/fusion/TabBar.qml b/src/quickcontrols2/fusion/TabBar.qml
new file mode 100644
index 0000000000..e093365347
--- /dev/null
+++ b/src/quickcontrols2/fusion/TabBar.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: -1
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 0
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 40
+ preferredHighlightEnd: width - 40
+ }
+
+ background: Item {
+ implicitHeight: 21
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ y: control.position === T.TabBar.Header ? parent.height - 1 : 0
+ color: Fusion.outline(control.palette)
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/TabButton.qml b/src/quickcontrols2/fusion/TabButton.qml
new file mode 100644
index 0000000000..161a7b0257
--- /dev/null
+++ b/src/quickcontrols2/fusion/TabButton.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 2
+ horizontalPadding: 4
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ z: checked
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: Rectangle {
+ y: control.checked || control.TabBar.position !== T.TabBar.Header ? 0 : 2
+ implicitHeight: 21
+ height: control.height - (control.checked ? 0 : 2)
+
+ border.color: Qt.lighter(Fusion.outline(control.palette), 1.1)
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: control.checked ? Qt.lighter(Fusion.tabFrameColor(control.palette), 1.04)
+ : Qt.darker(Fusion.tabFrameColor(control.palette), 1.08)
+ }
+ GradientStop {
+ position: control.checked ? 0 : 0.85
+ color: control.checked ? Qt.lighter(Fusion.tabFrameColor(control.palette), 1.04)
+ : Qt.darker(Fusion.tabFrameColor(control.palette), 1.08)
+ }
+ GradientStop {
+ position: 1
+ color: control.checked ? Fusion.tabFrameColor(control.palette)
+ : Qt.darker(Fusion.tabFrameColor(control.palette), 1.16)
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/TextArea.qml b/src/quickcontrols2/fusion/TextArea.qml
new file mode 100644
index 0000000000..5346aad104
--- /dev/null
+++ b/src/quickcontrols2/fusion/TextArea.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ padding: 6
+ leftPadding: padding + 4
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+
+ 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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+}
diff --git a/src/quickcontrols2/fusion/TextField.qml b/src/quickcontrols2/fusion/TextField.qml
new file mode 100644
index 0000000000..d99c3664f2
--- /dev/null
+++ b/src/quickcontrols2/fusion/TextField.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.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)
+
+ padding: 4
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: TextInput.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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 24
+
+ radius: 2
+ color: control.palette.base
+ border.color: control.activeFocus ? Fusion.highlightedOutline(control.palette) : Fusion.outline(control.palette)
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: "transparent"
+ border.color: Color.transparent(Fusion.highlightedOutline(control.palette), 40 / 255)
+ visible: control.activeFocus
+ radius: 1.7
+ }
+
+ Rectangle {
+ x: 2
+ y: 1
+ width: parent.width - 4
+ height: 1
+ color: Fusion.topShadow
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/ToolBar.qml b/src/quickcontrols2/fusion/ToolBar.qml
new file mode 100644
index 0000000000..747a292dc8
--- /dev/null
+++ b/src/quickcontrols2/fusion/ToolBar.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: 6
+ topPadding: control.position === T.ToolBar.Footer ? 1 : 0
+ bottomPadding: control.position === T.ToolBar.Header ? 1 : 0
+
+ background: Rectangle {
+ implicitHeight: 26
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.lighter(control.palette.window, 1.04)
+ }
+ GradientStop {
+ position: 1
+ color: control.palette.window
+ }
+ }
+
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: control.position === T.ToolBar.Header ? Fusion.lightShade : Fusion.darkShade
+ }
+
+ Rectangle {
+ y: parent.height - height
+ width: parent.width
+ height: 1
+ color: control.position === T.ToolBar.Header ? Fusion.darkShade : Fusion.lightShade
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/ToolButton.qml b/src/quickcontrols2/fusion/ToolButton.qml
new file mode 100644
index 0000000000..8b25fbe861
--- /dev/null
+++ b/src/quickcontrols2/fusion/ToolButton.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 16
+ icon.height: 16
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: ButtonPanel {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ control: control
+ visible: control.down || control.checked || control.highlighted || control.visualFocus
+ || (enabled && control.hovered)
+ }
+}
diff --git a/src/quickcontrols2/fusion/ToolSeparator.qml b/src/quickcontrols2/fusion/ToolSeparator.qml
new file mode 100644
index 0000000000..a325af6d48
--- /dev/null
+++ b/src/quickcontrols2/fusion/ToolSeparator.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ToolSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: vertical ? 6 : 2
+ verticalPadding: vertical ? 2 : 6
+
+ contentItem: Rectangle {
+ implicitWidth: control.vertical ? 2 : 8
+ implicitHeight: control.vertical ? 8 : 2
+ color: Qt.darker(control.palette.window, 1.1)
+
+ Rectangle {
+ x: 1
+ width: 1
+ height: parent.height
+ color: Qt.lighter(control.palette.window, 1.1)
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/ToolTip.qml b/src/quickcontrols2/fusion/ToolTip.qml
new file mode 100644
index 0000000000..90e0c268a1
--- /dev/null
+++ b/src/quickcontrols2/fusion/ToolTip.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.ToolTip {
+ id: control
+
+ x: parent ? (parent.width - implicitWidth) / 2 : 0
+ y: -implicitHeight - 3
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 6
+ padding: 6
+
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ wrapMode: Text.Wrap
+ color: control.palette.toolTipText
+ }
+
+ background: Rectangle {
+ color: control.palette.toolTipBase
+ border.color: control.palette.toolTipText
+
+ Rectangle {
+ z: -1
+ x: 1; y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.5
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/Tumbler.qml b/src/quickcontrols2/fusion/Tumbler.qml
new file mode 100644
index 0000000000..77ab18fe70
--- /dev/null
+++ b/src/quickcontrols2/fusion/Tumbler.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+T.Tumbler {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ delegate: Text {
+ text: modelData
+ color: control.palette.windowText
+ font: control.font
+ opacity: (1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)) * (control.enabled ? 1 : 0.6)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ required property var modelData
+ required property int index
+ }
+
+ contentItem: TumblerView {
+ implicitWidth: 60
+ implicitHeight: 200
+ model: control.model
+ delegate: control.delegate
+ path: Path {
+ startX: control.contentItem.width / 2
+ startY: -control.contentItem.delegateHeight / 2
+ PathLine {
+ x: control.contentItem.width / 2
+ y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: control.availableHeight / control.visibleItemCount
+ }
+}
diff --git a/src/quickcontrols2/fusion/VerticalHeaderView.qml b/src/quickcontrols2/fusion/VerticalHeaderView.qml
new file mode 100644
index 0000000000..3da5129004
--- /dev/null
+++ b/src/quickcontrols2/fusion/VerticalHeaderView.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.VerticalHeaderView {
+ id: control
+
+ implicitWidth: contentWidth
+ implicitHeight: syncView ? syncView.height : 0
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: Math.max(control.width, text.implicitWidth + (cellPadding * 2))
+ implicitHeight: text.implicitHeight + (cellPadding * 2)
+ border.color: "#cacaca"
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#fbfbfb"
+ }
+ GradientStop {
+ position: 1
+ color: "#e0dfe0"
+ }
+ }
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/fusion.pri b/src/quickcontrols2/fusion/fusion.pri
new file mode 100644
index 0000000000..135675e2b5
--- /dev/null
+++ b/src/quickcontrols2/fusion/fusion.pri
@@ -0,0 +1,59 @@
+HEADERS += \
+ $$PWD/qquickfusionstyle_p.h \
+ $$PWD/qquickfusiontheme_p.h
+
+SOURCES += \
+ $$PWD/qquickfusionstyle.cpp \
+ $$PWD/qquickfusiontheme.cpp
+
+QML_FILES += \
+ $$PWD/ApplicationWindow.qml \
+ $$PWD/BusyIndicator.qml \
+ $$PWD/Button.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/CheckDelegate.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/DelayButton.qml \
+ $$PWD/Dial.qml \
+ $$PWD/Dialog.qml \
+ $$PWD/DialogButtonBox.qml \
+ $$PWD/Drawer.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/HorizontalHeaderView.qml \
+ $$PWD/ItemDelegate.qml \
+ $$PWD/Label.qml \
+ $$PWD/Menu.qml \
+ $$PWD/MenuBar.qml \
+ $$PWD/MenuBarItem.qml \
+ $$PWD/MenuItem.qml \
+ $$PWD/MenuSeparator.qml \
+ $$PWD/Page.qml \
+ $$PWD/PageIndicator.qml \
+ $$PWD/Pane.qml \
+ $$PWD/Popup.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/RadioDelegate.qml \
+ $$PWD/RangeSlider.qml \
+ $$PWD/RoundButton.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/ScrollIndicator.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/SplitView.qml \
+ $$PWD/SwipeDelegate.qml \
+ $$PWD/SwitchDelegate.qml \
+ $$PWD/Switch.qml \
+ $$PWD/TabBar.qml \
+ $$PWD/TabButton.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TextField.qml \
+ $$PWD/ToolBar.qml \
+ $$PWD/ToolButton.qml \
+ $$PWD/ToolSeparator.qml \
+ $$PWD/ToolTip.qml \
+ $$PWD/Tumbler.qml \
+ $$PWD/VerticalHeaderView.qml
diff --git a/src/quickcontrols2/fusion/images/arrow.png b/src/quickcontrols2/fusion/images/arrow.png
new file mode 100644
index 0000000000..97ef0238e5
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/arrow.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/arrow.svg b/src/quickcontrols2/fusion/images/arrow.svg
new file mode 100644
index 0000000000..4438392495
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/arrow.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="10"
+ height="6"
+ viewBox="0 0 10 6"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ inkscape:export-filename="/Users/jpnurmi/Downloads/arrow@4x.png"
+ inkscape:export-xdpi="360"
+ inkscape:export-ydpi="360"
+ sodipodi:docname="arrow.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="31.678384"
+ inkscape:cx="7.9810383"
+ inkscape:cy="3.0344775"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ units="px"
+ inkscape:snap-to-guides="true"
+ inkscape:snap-page="true"
+ inkscape:window-width="1440"
+ inkscape:window-height="851"
+ inkscape:window-x="0"
+ inkscape:window-y="1"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3336" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1046.3622)">
+ <path
+ transform="matrix(1.2371791,0,0,0.85714284,1.0769252,150.19463)"
+ style="fill:#000000;fill-opacity:0.7254902"
+ inkscape:transform-center-y="1.4999605"
+ d="m 3.1709837,1051.3622 -3.2331616,-4.6667 6.4663233,0 z"
+ id="path3365"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccc" />
+ </g>
+</svg>
diff --git a/src/quickcontrols2/fusion/images/arrow@2x.png b/src/quickcontrols2/fusion/images/arrow@2x.png
new file mode 100644
index 0000000000..9bfc4e6eed
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/arrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/arrow@3x.png b/src/quickcontrols2/fusion/images/arrow@3x.png
new file mode 100644
index 0000000000..6fd9c988dc
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/arrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/arrow@4x.png b/src/quickcontrols2/fusion/images/arrow@4x.png
new file mode 100644
index 0000000000..f5e1e66a1d
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/arrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/checkmark.png b/src/quickcontrols2/fusion/images/checkmark.png
new file mode 100644
index 0000000000..deb30419d0
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/checkmark.svg b/src/quickcontrols2/fusion/images/checkmark.svg
new file mode 100644
index 0000000000..f1afdc4f9f
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/checkmark.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="14"
+ height="14"
+ viewBox="0 0 14 14"
+ id="svg3386"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ inkscape:export-filename="/Users/jpnurmi/Downloads/checkmark@4x.png"
+ inkscape:export-xdpi="360"
+ inkscape:export-ydpi="360"
+ sodipodi:docname="checkmark.svg">
+ <defs
+ id="defs3388" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="32"
+ inkscape:cx="1.9865044"
+ inkscape:cy="6.0706667"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ units="px"
+ inkscape:snap-page="true"
+ inkscape:snap-grids="true"
+ inkscape:snap-to-guides="true"
+ inkscape:window-width="1440"
+ inkscape:window-height="851"
+ inkscape:window-x="0"
+ inkscape:window-y="1"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata3391">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-1038.3622)">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.79999995;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 5,1045.3622 2,4 2.5,-8"
+ id="path4198"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccc"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ </g>
+</svg>
diff --git a/src/quickcontrols2/fusion/images/checkmark@2x.png b/src/quickcontrols2/fusion/images/checkmark@2x.png
new file mode 100644
index 0000000000..f80de0a425
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/checkmark@3x.png b/src/quickcontrols2/fusion/images/checkmark@3x.png
new file mode 100644
index 0000000000..c095eed18a
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/checkmark@4x.png b/src/quickcontrols2/fusion/images/checkmark@4x.png
new file mode 100644
index 0000000000..e58c7b4df4
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/checkmark@4x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/progressmask.png b/src/quickcontrols2/fusion/images/progressmask.png
new file mode 100644
index 0000000000..a354377c4a
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/progressmask.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/progressmask.svg b/src/quickcontrols2/fusion/images/progressmask.svg
new file mode 100644
index 0000000000..a0dfc4269d
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/progressmask.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="31"
+ height="22"
+ viewBox="0 0 8.202083 5.8208335"
+ version="1.1"
+ id="svg8"
+ inkscape:export-filename="/home/jpnurmi/Projects/qt-dev/qtquickcontrols2/src/imports/controls/fusion/images/progressmask@4x.png"
+ inkscape:export-xdpi="384"
+ inkscape:export-ydpi="384"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="progressmask.svg">
+ <defs
+ id="defs2" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="15.839192"
+ inkscape:cx="61.144853"
+ inkscape:cy="14.574824"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ units="px"
+ inkscape:pagecheckerboard="true"
+ inkscape:window-width="3840"
+ inkscape:window-height="2031"
+ inkscape:window-x="0"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-291.17915)">
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4.5;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 0,296.99998 4.7625,-5.82083"
+ id="path4485"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:4.5;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 8.2020833,296.99998 4.7624997,-5.82083"
+ id="path4485-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+</svg>
diff --git a/src/quickcontrols2/fusion/images/progressmask@2x.png b/src/quickcontrols2/fusion/images/progressmask@2x.png
new file mode 100644
index 0000000000..69476bf4a0
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/progressmask@2x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/progressmask@3x.png b/src/quickcontrols2/fusion/images/progressmask@3x.png
new file mode 100644
index 0000000000..00a1c09d87
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/progressmask@3x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/images/progressmask@4x.png b/src/quickcontrols2/fusion/images/progressmask@4x.png
new file mode 100644
index 0000000000..263110d5fe
--- /dev/null
+++ b/src/quickcontrols2/fusion/images/progressmask@4x.png
Binary files differ
diff --git a/src/quickcontrols2/fusion/impl/ButtonPanel.qml b/src/quickcontrols2/fusion/impl/ButtonPanel.qml
new file mode 100644
index 0000000000..6d64df8f78
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/ButtonPanel.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: panel
+
+ property Item control
+ property bool highlighted: control.highlighted
+
+ visible: !control.flat || control.down || control.checked
+
+ color: Fusion.buttonColor(control.palette, panel.highlighted, control.down || control.checked,
+ enabled && control.hovered)
+ gradient: control.down || control.checked ? null : buttonGradient
+
+ Gradient {
+ id: buttonGradient
+ GradientStop {
+ position: 0
+ color: Fusion.gradientStart(Fusion.buttonColor(panel.control.palette, panel.highlighted,
+ panel.control.down, panel.enabled && panel.control.hovered))
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.gradientStop(Fusion.buttonColor(panel.control.palette, panel.highlighted,
+ panel.control.down, panel.enabled && panel.control.hovered))
+ }
+ }
+
+ radius: 2
+ border.color: Fusion.buttonOutline(control.palette, panel.highlighted || control.visualFocus, control.enabled)
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ border.color: Fusion.innerContrastLine
+ color: "transparent"
+ radius: 2
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/CMakeLists.txt b/src/quickcontrols2/fusion/impl/CMakeLists.txt
new file mode 100644
index 0000000000..1aaebf266f
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/CMakeLists.txt
@@ -0,0 +1,39 @@
+#####################################################################
+## qtquickcontrols2fusionstyleimplplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ButtonPanel.qml"
+ "CheckIndicator.qml"
+ "RadioIndicator.qml"
+ "SliderGroove.qml"
+ "SliderHandle.qml"
+ "SwitchIndicator.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2fusionstyleimplplugin
+ URI "QtQuick.Controls.Fusion.impl"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2FusionStyleImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2fusionstyleimplplugin
+ NO_PLUGIN_OPTIONAL
+ SOURCES
+ qquickfusionbusyindicator.cpp qquickfusionbusyindicator_p.h
+ qquickfusiondial.cpp qquickfusiondial_p.h
+ qquickfusionknob.cpp qquickfusionknob_p.h
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
diff --git a/src/quickcontrols2/fusion/impl/CheckIndicator.qml b/src/quickcontrols2/fusion/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..3a083653f5
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/CheckIndicator.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: indicator
+
+ property Item control
+ readonly property color pressedColor: Fusion.mergedColors(control.palette.base, control.palette.windowText, 85)
+ readonly property color checkMarkColor: Qt.darker(control.palette.text, 1.2)
+
+ implicitWidth: 14
+ implicitHeight: 14
+
+ color: control.down ? indicator.pressedColor : control.palette.base
+ border.color: control.visualFocus ? Fusion.highlightedOutline(control.palette)
+ : Qt.lighter(Fusion.outline(control.palette), 1.1)
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: 1
+ color: Fusion.topShadow
+ visible: indicator.control.enabled && !indicator.control.down
+ }
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ color: Color.transparent(indicator.checkMarkColor, 210 / 255)
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Fusion/images/checkmark.png"
+ visible: indicator.control.checkState === Qt.Checked || (indicator.control.checked && indicator.control.checkState === undefined)
+ }
+
+ Rectangle {
+ x: 3; y: 3
+ width: parent.width - 6
+ height: parent.width - 6
+
+ visible: indicator.control.checkState === Qt.PartiallyChecked
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Color.transparent(indicator.checkMarkColor, 80 / 255)
+ }
+ GradientStop {
+ position: 1
+ color: Color.transparent(indicator.checkMarkColor, 140 / 255)
+ }
+ }
+ border.color: Color.transparent(indicator.checkMarkColor, 180 / 255)
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/RadioIndicator.qml b/src/quickcontrols2/fusion/impl/RadioIndicator.qml
new file mode 100644
index 0000000000..d459a2e84f
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/RadioIndicator.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: indicator
+
+ property Item control
+ readonly property color pressedColor: Fusion.mergedColors(control.palette.base, control.palette.windowText, 85)
+ readonly property color checkMarkColor: Qt.darker(control.palette.text, 1.2)
+
+ implicitWidth: 14
+ implicitHeight: 14
+
+ radius: width / 2
+ color: control.down ? indicator.pressedColor : control.palette.base
+ border.color: control.visualFocus ? Fusion.highlightedOutline(control.palette)
+ : Qt.darker(control.palette.window, 1.5)
+
+ Rectangle {
+ y: 1
+ width: parent.width
+ height: parent.height - 1
+ radius: width / 2
+ color: "transparent"
+ border.color: Fusion.topShadow
+ visible: indicator.control.enabled && !indicator.control.down
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 2.32
+ height: parent.height / 2.32
+ radius: width / 2
+ color: Color.transparent(indicator.checkMarkColor, 180 / 255)
+ border.color: Color.transparent(indicator.checkMarkColor, 200 / 255)
+ visible: indicator.control.checked
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/SliderGroove.qml b/src/quickcontrols2/fusion/impl/SliderGroove.qml
new file mode 100644
index 0000000000..76b7156a85
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/SliderGroove.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: groove
+
+ property Item control
+ property real offset
+ property real progress
+ property real visualProgress
+
+ x: control.horizontal ? 0 : (control.availableWidth - width) / 2
+ y: control.horizontal ? (control.availableHeight - height) / 2 : 0
+
+ implicitWidth: control.horizontal ? 160 : 5
+ implicitHeight: control.horizontal ? 5 : 160
+ width: control.horizontal ? control.availableWidth : implicitWidth
+ height: control.horizontal ? implicitHeight : control.availableHeight
+
+ radius: 2
+ border.color: Fusion.outline(control.palette)
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.darker(Fusion.grooveColor(groove.control.palette), 1.1)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.lighter(Fusion.grooveColor(groove.control.palette), 1.1)
+ }
+ }
+
+ Rectangle {
+ x: groove.control.horizontal ? groove.offset * parent.width : 0
+ y: groove.control.horizontal ? 0 : groove.visualProgress * parent.height
+ width: groove.control.horizontal ? groove.progress * parent.width - groove.offset * parent.width : 5
+ height: groove.control.horizontal ? 5 : groove.progress * parent.height - groove.offset * parent.height
+
+ radius: 2
+ border.color: Qt.darker(Fusion.highlightedOutline(groove.control.palette), 1.1)
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Fusion.highlight(groove.control.palette)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.lighter(Fusion.highlight(groove.control.palette), 1.2)
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/SliderHandle.qml b/src/quickcontrols2/fusion/impl/SliderHandle.qml
new file mode 100644
index 0000000000..80b0e4db9c
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/SliderHandle.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: handle
+
+ property var palette
+ property bool pressed
+ property bool hovered
+ property bool vertical
+ property bool visualFocus
+
+ implicitWidth: 13
+ implicitHeight: 13
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Fusion.gradientStart(Fusion.buttonColor(handle.palette, handle.visualFocus,
+ handle.pressed, handle.enabled && handle.hovered))
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.gradientStop(Fusion.buttonColor(handle.palette, handle.visualFocus,
+ handle.pressed, handle.enabled && handle.hovered))
+ }
+ }
+ rotation: handle.vertical ? -90 : 0
+ border.width: 1
+ border.color: "transparent"
+ radius: 2
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ border.color: handle.visualFocus ? Fusion.highlightedOutline(handle.palette) : Fusion.outline(handle.palette)
+ color: "transparent"
+ radius: 2
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ border.color: Fusion.innerContrastLine
+ color: "transparent"
+ radius: 2
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/SwitchIndicator.qml b/src/quickcontrols2/fusion/impl/SwitchIndicator.qml
new file mode 100644
index 0000000000..f54737816c
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/SwitchIndicator.qml
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+
+Rectangle {
+ id: indicator
+
+ property T.AbstractButton control
+ readonly property color pressedColor: Fusion.mergedColors(control.palette.base, control.palette.windowText, 85)
+ readonly property color checkMarkColor: Qt.darker(control.palette.text, 1.2)
+
+ implicitWidth: 40
+ implicitHeight: 16
+
+ radius: 2
+ border.color: Fusion.outline(control.palette)
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Qt.darker(Fusion.grooveColor(indicator.control.palette), 1.1)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.lighter(Fusion.grooveColor(indicator.control.palette), 1.1)
+ }
+ }
+
+ Rectangle {
+ x: indicator.control.mirrored ? handle.x : 0
+ width: indicator.control.mirrored ? parent.width - handle.x : handle.x + handle.width
+ height: parent.height
+
+ opacity: indicator.control.checked ? 1 : 0
+ Behavior on opacity {
+ enabled: !indicator.control.down
+ NumberAnimation { duration: 80 }
+ }
+
+ radius: 2
+ border.color: Qt.darker(Fusion.highlightedOutline(indicator.control.palette), 1.1)
+ border.width: indicator.control.enabled ? 1 : 0
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Fusion.highlight(indicator.control.palette)
+ }
+ GradientStop {
+ position: 1
+ color: Qt.lighter(Fusion.highlight(indicator.control.palette), 1.2)
+ }
+ }
+ }
+
+ Rectangle {
+ id: handle
+ x: Math.max(0, Math.min(parent.width - width, indicator.control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 20
+ height: 16
+ radius: 2
+
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: Fusion.gradientStart(Fusion.buttonColor(indicator.control.palette,
+ indicator.control.visualFocus, indicator.control.pressed, indicator.enabled && indicator.control.hovered))
+ }
+ GradientStop {
+ position: 1
+ color: Fusion.gradientStop(Fusion.buttonColor(indicator.control.palette,
+ indicator.control.visualFocus, indicator.control.pressed, indicator.enabled && indicator.control.hovered))
+ }
+ }
+ border.width: 1
+ border.color: "transparent"
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ border.color: indicator.control.visualFocus ? Fusion.highlightedOutline(indicator.control.palette) : Fusion.outline(indicator.control.palette)
+ color: "transparent"
+ radius: 2
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ border.color: Fusion.innerContrastLine
+ color: "transparent"
+ radius: 2
+ }
+ }
+
+ Behavior on x {
+ enabled: !indicator.control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+}
diff --git a/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator.cpp b/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator.cpp
new file mode 100644
index 0000000000..3c30045ad9
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusionbusyindicator_p.h"
+
+#include <QtGui/qpainter.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickFusionBusyIndicator::QQuickFusionBusyIndicator(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+}
+
+QColor QQuickFusionBusyIndicator::color() const
+{
+ return m_color;
+}
+
+void QQuickFusionBusyIndicator::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+bool QQuickFusionBusyIndicator::isRunning() const
+{
+ return isVisible();
+}
+
+void QQuickFusionBusyIndicator::setRunning(bool running)
+{
+ if (running) {
+ setVisible(true);
+ update();
+ }
+}
+
+void QQuickFusionBusyIndicator::paint(QPainter *painter)
+{
+ const qreal w = width();
+ const qreal h = height();
+ if (w <= 0 || h <= 0 || !isRunning())
+ return;
+
+ const qreal sz = qMin(w, h);
+ const qreal dx = (w - sz) / 2;
+ const qreal dy = (h - sz) / 2;
+ const int hpw = qRound(qMax(qreal(1), sz / 14)) & -1;
+ const int pw = 2 * hpw;
+ const QRectF bounds(dx + hpw, dy + hpw, sz - pw - 1, sz - pw - 1);
+
+ QConicalGradient gradient;
+ gradient.setCenter(QPointF(dx + sz / 2, dy + sz / 2));
+ gradient.setColorAt(0, m_color);
+ gradient.setColorAt(0.1, m_color);
+ gradient.setColorAt(1, Qt::transparent);
+
+ painter->translate(0.5, 0.5);
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setPen(QPen(gradient, pw, Qt::SolidLine));
+ painter->drawArc(bounds, 0, 360 * 16);
+ painter->setPen(QPen(m_color, pw, Qt::SolidLine, Qt::RoundCap));
+ painter->drawArc(bounds, 0, 20 * 16);
+}
+
+void QQuickFusionBusyIndicator::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ QQuickPaintedItem::itemChange(change, data);
+
+ if (change == ItemOpacityHasChanged && qFuzzyIsNull(data.realValue))
+ setVisible(false);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfusionbusyindicator_p.cpp"
diff --git a/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator_p.h b/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator_p.h
new file mode 100644
index 0000000000..5aeea6c488
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusionbusyindicator_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFUSIONBUSYINDICATOR_P_H
+#define QQUICKFUSIONBUSYINDICATOR_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>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFusionBusyIndicator : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning)
+ QML_NAMED_ELEMENT(BusyIndicatorImpl)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickFusionBusyIndicator(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+ void paint(QPainter *painter) override;
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+
+private:
+ QColor m_color;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFUSIONBUSYINDICATOR_P_H
diff --git a/src/quickcontrols2/fusion/impl/qquickfusiondial.cpp b/src/quickcontrols2/fusion/impl/qquickfusiondial.cpp
new file mode 100644
index 0000000000..86d3652c1f
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusiondial.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusiondial_p.h"
+
+#include <QtGui/qpainter.h>
+#include <QtGui/private/qmath_p.h>
+#include <QtQuick/private/qquickpalette_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickFusionDial::QQuickFusionDial(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+}
+
+bool QQuickFusionDial::highlight() const
+{
+ return m_highlight;
+}
+
+void QQuickFusionDial::setHighlight(bool highlight)
+{
+ if (m_highlight == highlight)
+ return;
+
+ m_highlight = highlight;
+ update();
+}
+
+// based on QStyleHelper::drawDial()
+void QQuickFusionDial::paint(QPainter *painter)
+{
+ const int width = QQuickItem::width();
+ const int height = QQuickItem::height();
+ if (width <= 0 || height <= 0 || !isVisible())
+ return;
+
+ QColor buttonColor = QQuickItemPrivate::get(this)->palette()->button();
+ const bool enabled = isEnabled();
+ qreal r = qMin(width, height) / 2.0;
+ r -= r/50;
+ const qreal penSize = r/20.0;
+
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ const qreal d_ = r / 6;
+ const qreal dx = d_ + (width - 2 * r) / 2 + 1;
+ const qreal dy = d_ + (height - 2 * r) / 2 + 1;
+
+ QRectF br = QRectF(dx + 0.5, dy + 0.5,
+ int(r * 2 - 2 * d_ - 2),
+ int(r * 2 - 2 * d_ - 2));
+ buttonColor.setHsv(buttonColor .hue(),
+ qMin(140, buttonColor .saturation()),
+ qMax(180, buttonColor.value()));
+
+ if (enabled) {
+ // Drop shadow
+ qreal shadowSize = qMax(1.0, penSize/2.0);
+ QRectF shadowRect= br.adjusted(-2*shadowSize, -2*shadowSize,
+ 2*shadowSize, 2*shadowSize);
+ QRadialGradient shadowGradient(shadowRect.center().x(),
+ shadowRect.center().y(), shadowRect.width()/2.0,
+ shadowRect.center().x(), shadowRect.center().y());
+ shadowGradient.setColorAt(qreal(0.91), QColor(0, 0, 0, 40));
+ shadowGradient.setColorAt(qreal(1.0), Qt::transparent);
+ painter->setBrush(shadowGradient);
+ painter->setPen(Qt::NoPen);
+ painter->translate(shadowSize, shadowSize);
+ painter->drawEllipse(shadowRect);
+ painter->translate(-shadowSize, -shadowSize);
+
+ // Main gradient
+ QRadialGradient gradient(br.center().x() - br.width()/3, dy,
+ br.width()*1.3, br.center().x(),
+ br.center().y() - br.height()/2);
+ gradient.setColorAt(0, buttonColor.lighter(110));
+ gradient.setColorAt(qreal(0.5), buttonColor);
+ gradient.setColorAt(qreal(0.501), buttonColor.darker(102));
+ gradient.setColorAt(1, buttonColor.darker(115));
+ painter->setBrush(gradient);
+ } else {
+ painter->setBrush(Qt::NoBrush);
+ }
+
+ painter->setPen(QPen(buttonColor.darker(280)));
+ painter->drawEllipse(br);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(buttonColor.lighter(110));
+ painter->drawEllipse(br.adjusted(1, 1, -1, -1));
+
+ if (m_highlight) {
+ QColor highlight = QQuickItemPrivate::get(this)->palette()->highlight();
+ highlight.setHsv(highlight.hue(),
+ qMin(160, highlight.saturation()),
+ qMax(230, highlight.value()));
+ highlight.setAlpha(127);
+ painter->setPen(QPen(highlight, 2.0));
+ painter->setBrush(Qt::NoBrush);
+ painter->drawEllipse(br.adjusted(-1, -1, 1, 1));
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfusiondial_p.cpp"
diff --git a/src/quickcontrols2/fusion/impl/qquickfusiondial_p.h b/src/quickcontrols2/fusion/impl/qquickfusiondial_p.h
new file mode 100644
index 0000000000..c320527a4e
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusiondial_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFUSIONDIAL_P_H
+#define QQUICKFUSIONDIAL_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/qquickpainteditem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFusionDial : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(bool highlight READ highlight WRITE setHighlight FINAL)
+ QML_NAMED_ELEMENT(DialImpl)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickFusionDial(QQuickItem *parent = nullptr);
+
+ bool highlight() const;
+ void setHighlight(bool highlight);
+
+ void paint(QPainter *painter) override;
+
+private:
+ bool m_highlight = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFUSIONDIAL_P_H
diff --git a/src/quickcontrols2/fusion/impl/qquickfusionknob.cpp b/src/quickcontrols2/fusion/impl/qquickfusionknob.cpp
new file mode 100644
index 0000000000..0b520e43ba
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusionknob.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusionknob_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtGui/qpainter.h>
+#include <QtQuick/private/qquickpalette_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickFusionKnob::QQuickFusionKnob(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+ connect(this, &QQuickItem::paletteChanged, this, [this](){ update(); });
+}
+
+// extracted from QStyleHelper::drawDial()
+void QQuickFusionKnob::paint(QPainter *painter)
+{
+ const qreal w = width();
+ const qreal h = height();
+ if (w <= 0 || h <= 0)
+ return;
+
+ QColor color = QQuickItemPrivate::get(this)->palette()->button();
+ color.setHsv(color.hue(),
+ qMin(140, color .saturation()),
+ qMax(180, color.value()));
+ color = color.lighter(104);
+ color.setAlphaF(0.8f);
+
+ const qreal sz = qMin(w, h);
+ QRectF rect(0, 0, sz, sz);
+ rect.moveCenter(QPointF(w / 2.0, h / 2.0));
+ const QPointF center = rect.center();
+
+ QRadialGradient gradient(center.x() + rect.width() / 2,
+ center.y() + rect.width(),
+ rect.width() * 2,
+ center.x(), center.y());
+ gradient.setColorAt(1, color.darker(140));
+ gradient.setColorAt(qreal(0.4), color.darker(120));
+ gradient.setColorAt(0, color.darker(110));
+
+ painter->setRenderHint(QPainter::Antialiasing);
+ painter->setBrush(gradient);
+ painter->setPen(QColor(255, 255, 255, 150));
+ painter->drawEllipse(rect);
+ painter->setPen(QColor(0, 0, 0, 80));
+ painter->drawEllipse(rect.adjusted(1, 1, -1, -1));
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfusionknob_p.cpp"
diff --git a/src/quickcontrols2/fusion/impl/qquickfusionknob_p.h b/src/quickcontrols2/fusion/impl/qquickfusionknob_p.h
new file mode 100644
index 0000000000..b9b9c3776d
--- /dev/null
+++ b/src/quickcontrols2/fusion/impl/qquickfusionknob_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFUSIONKNOB_P_H
+#define QQUICKFUSIONKNOB_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/qquickpainteditem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFusionKnob : public QQuickPaintedItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(KnobImpl)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickFusionKnob(QQuickItem *parent = nullptr);
+
+ void paint(QPainter *painter) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFUSIONKNOB_P_H
diff --git a/src/quickcontrols2/fusion/qquickfusionstyle.cpp b/src/quickcontrols2/fusion/qquickfusionstyle.cpp
new file mode 100644
index 0000000000..f2e8f8236b
--- /dev/null
+++ b/src/quickcontrols2/fusion/qquickfusionstyle.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusionstyle_p.h"
+
+#include <QtGui/qcolor.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <QtQuick/private/qquickpalette_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickFusionStyle::QQuickFusionStyle(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QColor QQuickFusionStyle::lightShade()
+{
+ return QColor(255, 255, 255, 90);
+}
+
+QColor QQuickFusionStyle::darkShade()
+{
+ return QColor(0, 0, 0, 60);
+}
+
+QColor QQuickFusionStyle::topShadow()
+{
+ return QColor(0, 0, 0, 18);
+}
+
+QColor QQuickFusionStyle::innerContrastLine()
+{
+ return QColor(255, 255, 255, 30);
+}
+
+QColor QQuickFusionStyle::highlight(QQuickPalette *palette)
+{
+ return palette->highlight();
+}
+
+QColor QQuickFusionStyle::highlightedText(QQuickPalette *palette)
+{
+ return palette->highlightedText();
+}
+
+QColor QQuickFusionStyle::outline(QQuickPalette *palette)
+{
+ return palette->window().darker(140);
+}
+
+QColor QQuickFusionStyle::highlightedOutline(QQuickPalette *palette)
+{
+ QColor highlightedOutline = highlight(palette).darker(125);
+ if (highlightedOutline.value() > 160)
+ highlightedOutline.setHsl(highlightedOutline.hue(), highlightedOutline.saturation(), 160);
+ return highlightedOutline;
+}
+
+QColor QQuickFusionStyle::tabFrameColor(QQuickPalette *palette)
+{
+ return buttonColor(palette).lighter(104);
+}
+
+QColor QQuickFusionStyle::buttonColor(QQuickPalette *palette, bool highlighted, bool down, bool hovered)
+{
+ QColor buttonColor = palette->button();
+ int val = qGray(buttonColor.rgb());
+ buttonColor = buttonColor.lighter(100 + qMax(1, (180 - val)/6));
+ buttonColor.setHsv(buttonColor.hue(), int(buttonColor.saturation() * 0.75), buttonColor.value());
+ if (highlighted)
+ buttonColor = mergedColors(buttonColor, highlightedOutline(palette).lighter(130), 90);
+ if (!hovered)
+ buttonColor = buttonColor.darker(104);
+ if (down)
+ buttonColor = buttonColor.darker(110);
+ return buttonColor;
+}
+
+QColor QQuickFusionStyle::buttonOutline(QQuickPalette *palette, bool highlighted, bool enabled)
+{
+ QColor darkOutline = enabled && highlighted ? highlightedOutline(palette) : outline(palette);
+ return !enabled ? darkOutline.lighter(115) : darkOutline;
+}
+
+QColor QQuickFusionStyle::gradientStart(const QColor &baseColor)
+{
+ return baseColor.lighter(124);
+}
+
+QColor QQuickFusionStyle::gradientStop(const QColor &baseColor)
+{
+ return baseColor.lighter(102);
+}
+
+QColor QQuickFusionStyle::mergedColors(const QColor &colorA, const QColor &colorB, int factor)
+{
+ const int maxFactor = 100;
+ QColor tmp = colorA;
+ tmp.setRed((tmp.red() * factor) / maxFactor + (colorB.red() * (maxFactor - factor)) / maxFactor);
+ tmp.setGreen((tmp.green() * factor) / maxFactor + (colorB.green() * (maxFactor - factor)) / maxFactor);
+ tmp.setBlue((tmp.blue() * factor) / maxFactor + (colorB.blue() * (maxFactor - factor)) / maxFactor);
+ return tmp;
+}
+
+QColor QQuickFusionStyle::grooveColor(QQuickPalette *palette)
+{
+ QColor color = buttonColor(palette);
+ color.setHsv(color.hue(),
+ qMin(255, color.saturation()),
+ qMin<int>(255, color.value() * 0.9));
+ return color;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfusionstyle_p.cpp"
diff --git a/src/quickcontrols2/fusion/qquickfusionstyle_p.h b/src/quickcontrols2/fusion/qquickfusionstyle_p.h
new file mode 100644
index 0000000000..c609e9c6a6
--- /dev/null
+++ b/src/quickcontrols2/fusion/qquickfusionstyle_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFUSIONSTYLE_P_H
+#define QQUICKFUSIONSTYLE_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 <QtGui/qcolor.h>
+#include <QtQml/qqml.h>
+#include <QtQuick/private/qquickpalette_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFusionStyle : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor lightShade READ lightShade CONSTANT)
+ Q_PROPERTY(QColor darkShade READ darkShade CONSTANT)
+ Q_PROPERTY(QColor topShadow READ topShadow CONSTANT)
+ Q_PROPERTY(QColor innerContrastLine READ innerContrastLine CONSTANT)
+ QML_NAMED_ELEMENT(Fusion)
+ QML_SINGLETON
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickFusionStyle(QObject *parent = nullptr);
+
+ static QColor lightShade();
+ static QColor darkShade();
+ static QColor topShadow();
+ static QColor innerContrastLine();
+
+ Q_INVOKABLE static QColor highlight(QQuickPalette *palette);
+ Q_INVOKABLE static QColor highlightedText(QQuickPalette *palette);
+ Q_INVOKABLE static QColor outline(QQuickPalette *palette);
+ Q_INVOKABLE static QColor highlightedOutline(QQuickPalette *palette);
+ Q_INVOKABLE static QColor tabFrameColor(QQuickPalette *palette);
+ Q_INVOKABLE static QColor buttonColor(QQuickPalette *palette, bool highlighted = false, bool down = false, bool hovered = false);
+ Q_INVOKABLE static QColor buttonOutline(QQuickPalette *palette, bool highlighted = false, bool enabled = true);
+ Q_INVOKABLE static QColor gradientStart(const QColor &baseColor);
+ Q_INVOKABLE static QColor gradientStop(const QColor &baseColor);
+ Q_INVOKABLE static QColor mergedColors(const QColor &colorA, const QColor &colorB, int factor = 50);
+ Q_INVOKABLE static QColor grooveColor(QQuickPalette *palette);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFUSIONSTYLE_P_H
diff --git a/src/quickcontrols2/fusion/qquickfusiontheme.cpp b/src/quickcontrols2/fusion/qquickfusiontheme.cpp
new file mode 100644
index 0000000000..29d2ed1ab2
--- /dev/null
+++ b/src/quickcontrols2/fusion/qquickfusiontheme.cpp
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusiontheme_p.h"
+
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickFusionTheme::initialize(QQuickTheme *theme)
+{
+ const bool isDarkSystemTheme = QQuickStylePrivate::isDarkSystemTheme();
+ QPalette systemPalette;
+ systemPalette.setColor(QPalette::Active, QPalette::ButtonText,
+ isDarkSystemTheme ? QColor::fromRgb(0xe7e7e7) : QColor::fromRgb(0x252525));
+ systemPalette.setColor(QPalette::Inactive, QPalette::ButtonText,
+ isDarkSystemTheme ? QColor::fromRgb(0xe7e7e7) : QColor::fromRgb(0x252525));
+ systemPalette.setColor(QPalette::Disabled, QPalette::ButtonText,
+ isDarkSystemTheme ? QColor::fromRgb(0x777777) : QColor::fromRgb(0xb6b6b6));
+ theme->setPalette(QQuickTheme::System, systemPalette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/fusion/qquickfusiontheme_p.h b/src/quickcontrols2/fusion/qquickfusiontheme_p.h
new file mode 100644
index 0000000000..814c191961
--- /dev/null
+++ b/src/quickcontrols2/fusion/qquickfusiontheme_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFUSIONTHEME_P_H
+#define QQUICKFUSIONTHEME_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 QQuickFusionTheme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFUSIONTHEME_P_H
diff --git a/src/quickcontrols2/fusion/qtquickcontrols2fusionstyle.qrc b/src/quickcontrols2/fusion/qtquickcontrols2fusionstyle.qrc
new file mode 100644
index 0000000000..0a9e195a29
--- /dev/null
+++ b/src/quickcontrols2/fusion/qtquickcontrols2fusionstyle.qrc
@@ -0,0 +1,16 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="qt-project.org/imports/QtQuick/Controls/Fusion">
+ <file>images/arrow.png</file>
+ <file>images/arrow@2x.png</file>
+ <file>images/arrow@3x.png</file>
+ <file>images/arrow@4x.png</file>
+ <file>images/checkmark.png</file>
+ <file>images/checkmark@2x.png</file>
+ <file>images/checkmark@3x.png</file>
+ <file>images/checkmark@4x.png</file>
+ <file>images/progressmask.png</file>
+ <file>images/progressmask@2x.png</file>
+ <file>images/progressmask@3x.png</file>
+ <file>images/progressmask@4x.png</file>
+</qresource>
+</RCC>
diff --git a/src/quickcontrols2/fusion/qtquickcontrols2fusionstyleplugin.cpp b/src/quickcontrols2/fusion/qtquickcontrols2fusionstyleplugin.cpp
new file mode 100644
index 0000000000..9d6516a1e8
--- /dev/null
+++ b/src/quickcontrols2/fusion/qtquickcontrols2fusionstyleplugin.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfusionstyle_p.h"
+#include "qquickfusiontheme_p.h"
+
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+extern void qml_register_types_QtQuick_Controls_Fusion();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Fusion);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2FusionStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2FusionStylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+
+ QQuickFusionTheme theme;
+};
+
+QtQuickControls2FusionStylePlugin::QtQuickControls2FusionStylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Fusion;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2FusionStylePlugin::name() const
+{
+ return QStringLiteral("Fusion");
+}
+
+void QtQuickControls2FusionStylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ this->theme.initialize(theme);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2fusionstyleplugin.moc"
diff --git a/src/quickcontrols2/imagine/ApplicationWindow.qml b/src/quickcontrols2/imagine/ApplicationWindow.qml
new file mode 100644
index 0000000000..b54527eb9e
--- /dev/null
+++ b/src/quickcontrols2/imagine/ApplicationWindow.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ApplicationWindow {
+ id: window
+
+ background: NinePatchImage {
+ width: window.width
+ height: window.height
+
+ source: Imagine.url + "applicationwindow-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"active": window.active}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/BusyIndicator.qml b/src/quickcontrols2/imagine/BusyIndicator.qml
new file mode 100644
index 0000000000..c0fa8e515e
--- /dev/null
+++ b/src/quickcontrols2/imagine/BusyIndicator.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.BusyIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: AnimatedImage {
+ opacity: control.running ? 1 : 0
+ playing: control.running || opacity > 0
+ visible: control.running || opacity > 0
+ Behavior on opacity { OpacityAnimator { duration: 250 } }
+
+ source: Imagine.url + "busyindicator-animation"
+ AnimatedImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"running": control.running},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "busyindicator-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"running": control.running},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Button.qml b/src/quickcontrols2/imagine/Button.qml
new file mode 100644
index 0000000000..3287202f5e
--- /dev/null
+++ b/src/quickcontrols2/imagine/Button.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.enabled && control.flat && control.highlighted ? control.palette.highlight
+ : control.enabled && (control.down || control.checked || control.highlighted) && !control.flat
+ ? control.palette.brightText : control.flat ? control.palette.windowText : control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled && control.flat && control.highlighted ? control.palette.highlight
+ : control.enabled && (control.down || control.checked || control.highlighted) && !control.flat
+ ? control.palette.brightText : control.flat ? control.palette.windowText : control.palette.buttonText
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "button-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"checkable": control.checkable},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"flat": control.flat},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/CMakeLists.txt b/src/quickcontrols2/imagine/CMakeLists.txt
new file mode 100644
index 0000000000..e1348f1dee
--- /dev/null
+++ b/src/quickcontrols2/imagine/CMakeLists.txt
@@ -0,0 +1,145 @@
+#####################################################################
+## qtquickcontrols2imaginestyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "BusyIndicator.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "CheckDelegate.qml"
+ "ComboBox.qml"
+ "DelayButton.qml"
+ "Dial.qml"
+ "Dialog.qml"
+ "DialogButtonBox.qml"
+ "Drawer.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "HorizontalHeaderView.qml"
+ "ItemDelegate.qml"
+ "Label.qml"
+ "Menu.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
+ "PageIndicator.qml"
+ "Page.qml"
+ "Pane.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RadioDelegate.qml"
+ "RangeSlider.qml"
+ "RoundButton.qml"
+ "ScrollView.qml"
+ "ScrollBar.qml"
+ "ScrollIndicator.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "SplitView.qml"
+ "StackView.qml"
+ "SwipeDelegate.qml"
+ "SwipeView.qml"
+ "Switch.qml"
+ "SwitchDelegate.qml"
+ "TextField.qml"
+ "TextArea.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "ToolSeparator.qml"
+ "ToolTip.qml"
+ "Tumbler.qml"
+ "VerticalHeaderView.qml"
+)
+set_source_files_properties(DelayButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(Dialog.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(DialogButtonBox.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(HorizontalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+set_source_files_properties(MenuSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(RoundButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(SplitView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.13;6.0"
+)
+set_source_files_properties(ToolSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(VerticalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2imaginestyleplugin
+ URI "QtQuick.Controls.Imagine"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2ImagineStylePlugin
+ IMPORTS
+ QtQuick.Controls.Basic/auto
+ PLUGIN_TARGET qtquickcontrols2imaginestyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickimaginestyle.cpp qquickimaginestyle_p.h
+ qquickimaginetheme.cpp qquickimaginetheme_p.h
+ qtquickcontrols2imaginestyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+file(GLOB resource_glob_0 RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "images/*.png")
+foreach(file IN LISTS resource_glob_0)
+ set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/${file}" PROPERTIES QT_RESOURCE_ALIAS "${file}")
+endforeach()
+
+file(GLOB resource_glob_1 RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "images/*.webp")
+foreach(file IN LISTS resource_glob_1)
+ set_source_files_properties("${CMAKE_CURRENT_SOURCE_DIR}/${file}" PROPERTIES QT_RESOURCE_ALIAS "${file}")
+endforeach()
+
+# Resources:
+set(qmake_qtquickcontrols2imaginestyleplugin_resource_files
+ ${resource_glob_0}
+ ${resource_glob_1}
+)
+
+qt_internal_add_resource(qtquickcontrols2imaginestyleplugin "qmake_qtquickcontrols2imaginestyleplugin"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/Imagine"
+ FILES
+ ${qmake_qtquickcontrols2imaginestyleplugin_resource_files}
+)
+
+add_subdirectory(impl)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2imaginestyleplugin quickwindow)
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2imaginestyleplugin
+ qtquickcontrols2imaginestyleimplplugin)
+
+# Basic style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2imaginestyleplugin
+ qtquickcontrols2basicstyleplugin)
diff --git a/src/quickcontrols2/imagine/CheckBox.qml b/src/quickcontrols2/imagine/CheckBox.qml
new file mode 100644
index 0000000000..25ffee6197
--- /dev/null
+++ b/src/quickcontrols2/imagine/CheckBox.qml
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+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: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ indicator: Image {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ source: Imagine.url + "checkbox-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checkState === Qt.Checked},
+ {"partially-checked": control.checkState === Qt.PartiallyChecked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ 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.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "checkbox-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checkState === Qt.Checked},
+ {"partially-checked": control.checkState === Qt.PartiallyChecked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/CheckDelegate.qml b/src/quickcontrols2/imagine/CheckDelegate.qml
new file mode 100644
index 0000000000..4b98ddf900
--- /dev/null
+++ b/src/quickcontrols2/imagine/CheckDelegate.qml
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.CheckDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ indicator: Image {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ source: Imagine.url + "checkdelegate-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checkState === Qt.Checked},
+ {"partially-checked": control.checkState === Qt.PartiallyChecked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "checkdelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checkState === Qt.Checked},
+ {"partially-checked": control.checkState === Qt.PartiallyChecked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ComboBox.qml b/src/quickcontrols2/imagine/ComboBox.qml
new file mode 100644
index 0000000000..45ce8fb38e
--- /dev/null
+++ b/src/quickcontrols2/imagine/ComboBox.qml
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (background ? background.leftPadding + background.rightPadding : 0))
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ Math.max(implicitContentHeight,
+ implicitIndicatorHeight) + (background ? background.topPadding + background.bottomPadding : 0))
+
+ leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+ rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: Image {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ source: Imagine.url + "combobox-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"editable": control.editable},
+ {"open": control.down},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered},
+ {"flat": control.flat}
+ ]
+ }
+ }
+
+ contentItem: T.TextField {
+ topPadding: control.background ? control.background.topPadding : 0
+ leftPadding: control.background ? control.background.leftPadding : 0
+ rightPadding: control.background ? control.background.rightPadding : 0
+ bottomPadding: control.background ? control.background.bottomPadding : 0
+
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.flat ? control.palette.windowText : control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "combobox-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"editable": control.editable},
+ {"open": control.down},
+ {"focused": control.visualFocus || (control.editable && control.activeFocus)},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered},
+ {"flat": control.flat}
+ ]
+ }
+ }
+
+ popup: T.Popup {
+ width: control.width
+ height: Math.min(contentItem.implicitHeight + topPadding + bottomPadding, control.Window.height - topMargin - bottomMargin)
+
+ topMargin: background.topInset
+ bottomMargin: background.bottomInset
+
+ topPadding: background.topPadding
+ leftPadding: background.leftPadding
+ rightPadding: background.rightPadding
+ bottomPadding: background.bottomPadding
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ palette.text: control.palette.text
+ palette.highlight: control.palette.highlight
+ palette.highlightedText: control.palette.highlightedText
+ palette.windowText: control.palette.windowText
+ palette.buttonText: control.palette.buttonText
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "combobox-popup"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"editable": control.editable},
+ {"focused": control.visualFocus || (control.editable && control.activeFocus)},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered},
+ {"flat": control.flat}
+ ]
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/DelayButton.qml b/src/quickcontrols2/imagine/DelayButton.qml
new file mode 100644
index 0000000000..145b3383b5
--- /dev/null
+++ b/src/quickcontrols2/imagine/DelayButton.qml
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.DelayButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ transition: Transition {
+ NumberAnimation {
+ duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress)
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ background: NinePatchImage {
+ source: control.Imagine.url + "delaybutton-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ readonly property NinePatchImage progress: NinePatchImage {
+ parent: control.background
+ width: control.progress * parent.width
+ height: parent.height
+ visible: false
+
+ source: control.Imagine.url + "delaybutton-progress"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ readonly property NinePatchImage mask: NinePatchImage {
+ width: control.background.width
+ height: control.background.height
+ visible: false
+
+ source: control.Imagine.url + "delaybutton-mask"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ readonly property OpacityMask effect: OpacityMask {
+ parent: control.background
+ width: source.width
+ height: source.height
+ source: control.background.progress
+
+ maskSource: ShaderEffectSource {
+ sourceItem: control.background.mask
+ sourceRect: Qt.rect(0, 0, control.background.effect.width, control.background.effect.height)
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Dial.qml b/src/quickcontrols2/imagine/Dial.qml
new file mode 100644
index 0000000000..aa4f5bc76f
--- /dev/null
+++ b/src/quickcontrols2/imagine/Dial.qml
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Dial {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ (handle ? handle.implicitWidth : 0) + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ (handle ? handle.implicitHeight : 0) + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ handle: Image {
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+
+ source: Imagine.url + "dial-handle"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ transform: [
+ Translate {
+ y: -Math.min(control.background.width, control.background.height) * 0.4 + control.handle.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: control.handle.width / 2
+ origin.y: control.handle.height / 2
+ }
+ ]
+ }
+
+ background: NinePatchImage {
+ x: control.width / 2 - width / 2
+ y: control.height / 2 - height / 2
+ width: Math.max(64, Math.min(control.width, control.height))
+ height: width
+ fillMode: Image.PreserveAspectFit
+
+ source: Imagine.url + "dial-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Dialog.qml b/src/quickcontrols2/imagine/Dialog.qml
new file mode 100644
index 0000000000..b788cc3ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/Dialog.qml
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Dialog {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "dialog-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 12
+
+ background: NinePatchImage {
+ width: parent.width
+ height: parent.height
+
+ source: Imagine.url + "dialog-title"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+ }
+
+ footer: DialogButtonBox {
+ visible: count > 0
+ }
+
+ T.Overlay.modal: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ T.Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/DialogButtonBox.qml b/src/quickcontrols2/imagine/DialogButtonBox.qml
new file mode 100644
index 0000000000..bdd956f166
--- /dev/null
+++ b/src/quickcontrols2/imagine/DialogButtonBox.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.DialogButtonBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ (control.count === 1 ? contentWidth * 2 : contentWidth) + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ spacing: 6
+
+ delegate: Button {
+ width: control.count === 1 ? control.availableWidth / 2 : undefined
+ flat: true
+ }
+
+ contentItem: ListView {
+ implicitWidth: contentWidth
+ model: control.contentModel
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ snapMode: ListView.SnapToItem
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "dialogbuttonbox-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Drawer.qml b/src/quickcontrols2/imagine/Drawer.qml
new file mode 100644
index 0000000000..414516d307
--- /dev/null
+++ b/src/quickcontrols2/imagine/Drawer.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Drawer {
+ id: control
+
+ parent: T.Overlay.overlay
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ enter: Transition { SmoothedAnimation { velocity: 5 } }
+ exit: Transition { SmoothedAnimation { velocity: 5 } }
+
+ background: NinePatchImage {
+ source: Imagine.url + "drawer-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim},
+ {"top": control.edge === Qt.TopEdge},
+ {"left": control.edge === Qt.LeftEdge},
+ {"right": control.edge === Qt.RightEdge},
+ {"bottom": control.edge === Qt.BottomEdge}
+ ]
+ }
+ }
+
+ T.Overlay.modal: NinePatchImage {
+ source: Imagine.url + "drawer-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ T.Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "drawer-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Frame.qml b/src/quickcontrols2/imagine/Frame.qml
new file mode 100644
index 0000000000..7ba93dbceb
--- /dev/null
+++ b/src/quickcontrols2/imagine/Frame.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "frame-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/GroupBox.qml b/src/quickcontrols2/imagine/GroupBox.qml
new file mode 100644
index 0000000000..3fc99d97e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/GroupBox.qml
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: ((background as NinePatchImage)?.topPadding ?? 0) + (implicitLabelWidth > 0 ? implicitLabelHeight + spacing : 0)
+ leftPadding: ((background as NinePatchImage)?.leftPadding ?? 0)
+ rightPadding: ((background as NinePatchImage)?.rightPadding ?? 0)
+ bottomPadding: ((background as NinePatchImage)?.bottomPadding ?? 0)
+
+ label: Label {
+ width: control.width
+
+ topPadding: background.topPadding
+ leftPadding: background.leftPadding
+ rightPadding: background.rightPadding
+ bottomPadding: background.bottomPadding
+
+ text: control.title
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ color: control.palette.windowText
+
+ background: NinePatchImage {
+ width: parent.width
+ height: parent.height
+
+ source: Imagine.url + "groupbox-title"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+ }
+
+ background: NinePatchImage {
+ x: -leftInset
+ y: control.topPadding - control.bottomPadding - topInset
+ width: control.width + leftInset + rightInset
+ height: control.height + topInset + bottomInset - control.topPadding + control.bottomPadding
+
+ source: Imagine.url + "groupbox-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/HorizontalHeaderView.qml b/src/quickcontrols2/imagine/HorizontalHeaderView.qml
new file mode 100644
index 0000000000..e52145932f
--- /dev/null
+++ b/src/quickcontrols2/imagine/HorizontalHeaderView.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.HorizontalHeaderView {
+ id: control
+
+ implicitWidth: syncView ? syncView.width : 0
+ implicitHeight: contentHeight
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: text.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(control.height, text.implicitHeight + (cellPadding * 2))
+ color: "#f6f6f6"
+ border.color: "#e4e4e4"
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ItemDelegate.qml b/src/quickcontrols2/imagine/ItemDelegate.qml
new file mode 100644
index 0000000000..d0f7b29db0
--- /dev/null
+++ b/src/quickcontrols2/imagine/ItemDelegate.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "itemdelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Label.qml b/src/quickcontrols2/imagine/Label.qml
new file mode 100644
index 0000000000..da41e7065a
--- /dev/null
+++ b/src/quickcontrols2/imagine/Label.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Label {
+ id: control
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ color: control.palette.windowText
+ linkColor: control.palette.link
+
+ background: NinePatchImage {
+ source: Imagine.url + "label-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Menu.qml b/src/quickcontrols2/imagine/Menu.qml
new file mode 100644
index 0000000000..346c649021
--- /dev/null
+++ b/src/quickcontrols2/imagine/Menu.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+import QtQuick.Window
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topMargin: background ? background.topInset : 0
+ leftMargin: background ? background.leftInset : 0
+ rightMargin: background ? background.rightInset : 0
+ bottomMargin: background ? background.bottomInset : 0
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height
+ : false
+ clip: true
+ currentIndex: control.currentIndex
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "menu-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+
+ T.Overlay.modal: NinePatchImage {
+ source: Imagine.url + "menu-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ T.Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "menu-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/MenuItem.qml b/src/quickcontrols2/imagine/MenuItem.qml
new file mode 100644
index 0000000000..c17c0ba7b1
--- /dev/null
+++ b/src/quickcontrols2/imagine/MenuItem.qml
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.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)
+
+ spacing: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.windowText
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+ leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
+ rightPadding: control.mirrored ? indicatorPadding : 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.windowText
+ }
+
+ arrow: Image {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.subMenu
+ source: Imagine.url + "menuitem-arrow"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ indicator: Image {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.checkable
+ source: Imagine.url + "menuitem-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "menuitem-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/MenuSeparator.qml b/src/quickcontrols2/imagine/MenuSeparator.qml
new file mode 100644
index 0000000000..42d1812fa5
--- /dev/null
+++ b/src/quickcontrols2/imagine/MenuSeparator.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: NinePatchImage {
+ source: Imagine.url + "menuseparator-separator"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "menuseparator-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Page.qml b/src/quickcontrols2/imagine/Page.qml
new file mode 100644
index 0000000000..1b77112f3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/Page.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Page {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "page-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/PageIndicator.qml b/src/quickcontrols2/imagine/PageIndicator.qml
new file mode 100644
index 0000000000..7f576c5d05
--- /dev/null
+++ b/src/quickcontrols2/imagine/PageIndicator.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.PageIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ delegate: Image {
+ source: Imagine.url + "pageindicator-delegate"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": pressed},
+ {"current": index === control.currentIndex},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered} // ### TODO: context property
+ ]
+ }
+ }
+
+ contentItem: Row {
+ spacing: control.spacing
+
+ Repeater {
+ model: control.count
+ delegate: control.delegate
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "pageindicator-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Pane.qml b/src/quickcontrols2/imagine/Pane.qml
new file mode 100644
index 0000000000..4fdfaa18ce
--- /dev/null
+++ b/src/quickcontrols2/imagine/Pane.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Pane {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "pane-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Popup.qml b/src/quickcontrols2/imagine/Popup.qml
new file mode 100644
index 0000000000..bc7e544be7
--- /dev/null
+++ b/src/quickcontrols2/imagine/Popup.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : undefined
+ leftPadding: background ? background.leftPadding : undefined
+ rightPadding: background ? background.rightPadding : undefined
+ bottomPadding: background ? background.bottomPadding : undefined
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "popup-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+
+ T.Overlay.modal: NinePatchImage {
+ source: Imagine.url + "popup-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ T.Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "popup-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ProgressBar.qml b/src/quickcontrols2/imagine/ProgressBar.qml
new file mode 100644
index 0000000000..12ef501e72
--- /dev/null
+++ b/src/quickcontrols2/imagine/ProgressBar.qml
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: Item {
+ implicitWidth: control.indeterminate ? animation.implicitWidth || progress.implicitWidth : progress.implicitWidth
+ implicitHeight: control.indeterminate ? animation.implicitHeight || progress.implicitHeight : progress.implicitHeight
+ scale: control.mirrored ? -1 : 1
+
+ readonly property bool hasMask: mask.status !== Image.Null
+
+ readonly property NinePatchImage progress: NinePatchImage {
+ parent: control.contentItem
+ width: control.position * parent.width
+ height: parent.height
+ visible: !control.indeterminate && !control.contentItem.hasMask
+
+ source: Imagine.url + "progressbar-progress"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"indeterminate": control.indeterminate},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ readonly property AnimatedImage animation: AnimatedImage {
+ parent: control.contentItem
+ width: parent.width
+ height: parent.height
+ playing: control.indeterminate
+ visible: control.indeterminate && !control.contentItem.hasMask
+
+ source: Imagine.url + "progressbar-animation"
+ AnimatedImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ readonly property NinePatchImage mask: NinePatchImage {
+ width: control.availableWidth
+ height: control.availableHeight
+ visible: false
+
+ source: Imagine.url + "progressbar-mask"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"indeterminate": control.indeterminate},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ readonly property OpacityMask effect: OpacityMask {
+ parent: control.contentItem
+ width: source.width
+ height: source.height
+ source: control.indeterminate ? control.contentItem.animation : control.contentItem.progress
+
+ maskSource: ShaderEffectSource {
+ sourceItem: control.contentItem.mask
+ sourceRect: Qt.rect(0, 0, control.contentItem.effect.width, control.contentItem.effect.height)
+ }
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "progressbar-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"indeterminate": control.indeterminate},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/RadioButton.qml b/src/quickcontrols2/imagine/RadioButton.qml
new file mode 100644
index 0000000000..8c915443d1
--- /dev/null
+++ b/src/quickcontrols2/imagine/RadioButton.qml
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+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: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ indicator: Image {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ source: Imagine.url + "radiobutton-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ 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.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "radiobutton-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/RadioDelegate.qml b/src/quickcontrols2/imagine/RadioDelegate.qml
new file mode 100644
index 0000000000..b322e332c3
--- /dev/null
+++ b/src/quickcontrols2/imagine/RadioDelegate.qml
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.RadioDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ indicator: Image {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ source: Imagine.url + "radiodelegate-indicator"
+ ImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "radiodelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/RangeSlider.qml b/src/quickcontrols2/imagine/RangeSlider.qml
new file mode 100644
index 0000000000..6526bb60fd
--- /dev/null
+++ b/src/quickcontrols2/imagine/RangeSlider.qml
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+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: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ first.handle: Image {
+ x: control.leftPadding + (control.horizontal ? control.first.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.first.visualPosition * (control.availableHeight - height))
+
+ source: control.Imagine.url + "rangeslider-handle"
+ ImageSelector on source {
+ states: [
+ {"first": true},
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": control.first.pressed},
+ {"focused": control.first.handle.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.first.hovered}
+ ]
+ }
+ }
+
+ second.handle: Image {
+ x: control.leftPadding + (control.horizontal ? control.second.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.second.visualPosition * (control.availableHeight - height))
+
+ source: control.Imagine.url + "rangeslider-handle"
+ ImageSelector on source {
+ states: [
+ {"second": true},
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": control.second.pressed},
+ {"focused": control.second.handle.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.second.hovered}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ source: control.Imagine.url + "rangeslider-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ NinePatchImage {
+ x: control.horizontal ? control.first.handle.width / 2 + control.first.position * (parent.width - control.first.handle.width) : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : control.first.handle.height / 2 + control.second.visualPosition * (parent.height - control.first.handle.height)
+ width: control.horizontal ? control.second.position * (parent.width - control.first.handle.width) - control.first.position * (parent.width - control.first.handle.width) : parent.width
+ height: control.vertical ? control.second.position * (parent.height - control.first.handle.height) - control.first.position * (parent.height - control.first.handle.height): parent.height
+
+ source: control.Imagine.url + "rangeslider-progress"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/RoundButton.qml b/src/quickcontrols2/imagine/RoundButton.qml
new file mode 100644
index 0000000000..2485266740
--- /dev/null
+++ b/src/quickcontrols2/imagine/RoundButton.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.RoundButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.enabled && control.flat && control.highlighted ? control.palette.highlight
+ : control.enabled && (control.down || control.checked || control.highlighted) && !control.flat
+ ? control.palette.brightText : control.flat ? control.palette.windowText : control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled && control.flat && control.highlighted ? control.palette.highlight
+ : control.enabled && (control.down || control.checked || control.highlighted) && !control.flat
+ ? control.palette.brightText : control.flat ? control.palette.windowText : control.palette.buttonText
+ }
+
+ background: NinePatchImage {
+ // ### TODO: radius?
+ source: Imagine.url + "roundbutton-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"checkable": control.checkable},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"flat": control.flat},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ScrollBar.qml b/src/quickcontrols2/imagine/ScrollBar.qml
new file mode 100644
index 0000000000..69d7cd5971
--- /dev/null
+++ b/src/quickcontrols2/imagine/ScrollBar.qml
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ScrollBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ visible: control.policy !== T.ScrollBar.AlwaysOff
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: NinePatchImage {
+ width: control.availableWidth
+ height: control.availableHeight
+
+ source: Imagine.url + "scrollbar-handle"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"interactive": control.interactive},
+ {"pressed": control.pressed},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ opacity: 0.0
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "scrollbar-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"interactive": control.interactive},
+ {"pressed": control.pressed},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ opacity: 0.0
+ }
+
+ states: [
+ State {
+ name: "active"
+ when: control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "active"
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 1.0 }
+ },
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PropertyAction{ targets: [control.contentItem, control.background]; property: "opacity"; value: 1.0 }
+ PauseAnimation { duration: 3000 }
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+}
diff --git a/src/quickcontrols2/imagine/ScrollIndicator.qml b/src/quickcontrols2/imagine/ScrollIndicator.qml
new file mode 100644
index 0000000000..14fb507cec
--- /dev/null
+++ b/src/quickcontrols2/imagine/ScrollIndicator.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: NinePatchImage {
+ width: control.availableWidth
+ height: control.availableHeight
+
+ source: Imagine.url + "scrollindicator-handle"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ opacity: 0.0
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "scrollindicator-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ opacity: 0.0
+ }
+
+ states: [
+ State {
+ name: "active"
+ when: (control.active && control.size < 1.0)
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "active"
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 1.0 }
+ },
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 5000 }
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+}
diff --git a/src/quickcontrols2/imagine/ScrollView.qml b/src/quickcontrols2/imagine/ScrollView.qml
new file mode 100644
index 0000000000..80427e9d27
--- /dev/null
+++ b/src/quickcontrols2/imagine/ScrollView.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ T.ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.T.ScrollBar.horizontal.active
+ }
+
+ T.ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.T.ScrollBar.vertical.active
+ }
+
+ background: NinePatchImage {
+ source: Imagine.path + "scrollview-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SelectionRectangle.qml b/src/quickcontrols2/imagine/SelectionRectangle.qml
new file mode 100644
index 0000000000..2dbce02b63
--- /dev/null
+++ b/src/quickcontrols2/imagine/SelectionRectangle.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: handle
+ bottomRightHandle: handle
+
+ Component {
+ id: handle
+ Image {
+ id: image
+ source: Imagine.url + "slider-handle"
+ visible: SelectionRectangle.control.active
+ ImageSelector on source {
+ states: [
+ {"vertical": false},
+ {"horizontal": true},
+ {"disabled": false},
+ {"pressed": tapHandler.pressed || image.SelectionRectangle.dragging},
+ {"focused": true},
+ {"mirrored": false},
+ {"hovered": hoverHandler.hovered}
+ ]
+ }
+
+ HoverHandler {
+ id: hoverHandler
+ }
+
+ TapHandler {
+ id: tapHandler
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Slider.qml b/src/quickcontrols2/imagine/Slider.qml
new file mode 100644
index 0000000000..08b81e2369
--- /dev/null
+++ b/src/quickcontrols2/imagine/Slider.qml
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ handle: Image {
+ 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)))
+
+ source: control.Imagine.url + "slider-handle"
+ ImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": control.pressed},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ source: control.Imagine.url + "slider-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ NinePatchImage {
+ x: control.horizontal ? 0 : (parent.width - width) / 2
+ y: control.horizontal
+ ? (parent.height - height) / 2
+ : control.handle.height / 2 + control.visualPosition * (parent.height - control.handle.height)
+ width: control.horizontal
+ ? control.handle.width / 2 + control.position * (parent.width - control.handle.width)
+ : parent.width
+ height: control.vertical
+ ? control.handle.height / 2 + control.position * (parent.height - control.handle.height)
+ : parent.height
+
+ source: control.Imagine.url + "slider-progress"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SpinBox.qml b/src/quickcontrols2/imagine/SpinBox.qml
new file mode 100644
index 0000000000..ba61354fae
--- /dev/null
+++ b/src/quickcontrols2/imagine/SpinBox.qml
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth + 2 * padding +
+ up.implicitIndicatorWidth +
+ down.implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight,
+ up.implicitIndicatorHeight,
+ down.implicitIndicatorHeight)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: (background ? background.leftPadding : 0) + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: (background ? background.rightPadding : 0) + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ z: 2
+ text: control.displayText
+ opacity: control.enabled ? 1 : 0.3
+
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+
+ NinePatchImage {
+ z: -1
+ width: control.width
+ height: control.height
+ visible: control.editable
+
+ source: Imagine.url + "spinbox-editor"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+ }
+
+ up.indicator: NinePatchImage {
+ x: control.mirrored ? 0 : control.width - width
+ height: control.height
+
+ source: Imagine.url + "spinbox-indicator"
+ NinePatchImageSelector on source {
+ states: [
+ {"up": true},
+ {"disabled": !control.up.indicator.enabled},
+ {"editable": control.editable},
+ {"pressed": control.up.pressed},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.up.hovered}
+ ]
+ }
+ }
+
+ down.indicator: NinePatchImage {
+ x: control.mirrored ? control.width - width : 0
+ height: control.height
+
+ source: Imagine.url + "spinbox-indicator"
+ NinePatchImageSelector on source {
+ states: [
+ {"down": true},
+ {"disabled": !control.down.indicator.enabled},
+ {"editable": control.editable},
+ {"pressed": control.down.pressed},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.down.hovered}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "spinbox-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"editable": control.editable},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SplitView.qml b/src/quickcontrols2/imagine/SplitView.qml
new file mode 100644
index 0000000000..36e1b2134a
--- /dev/null
+++ b/src/quickcontrols2/imagine/SplitView.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SplitView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ handle: NinePatchImage {
+ source: Imagine.url + "splitview-handle"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.orientation === Qt.Vertical},
+ {"horizontal":control.orientation === Qt.Horizontal},
+ {"disabled": !control.enabled},
+ {"pressed": T.SplitHandle.pressed},
+ {"mirrored": control.mirrored},
+ {"hovered": T.SplitHandle.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/StackView.qml b/src/quickcontrols2/imagine/StackView.qml
new file mode 100644
index 0000000000..a9ddac66d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/StackView.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.StackView {
+ id: control
+
+ implicitWidth: implicitBackgroundWidth
+ implicitHeight: implicitBackgroundHeight
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ popEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * -control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ popExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ pushEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ pushExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * -control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ replaceEnter: Transition {
+ XAnimator { from: (control.mirrored ? -1 : 1) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ replaceExit: Transition {
+ XAnimator { from: 0; to: (control.mirrored ? -1 : 1) * -control.width; duration: 400; easing.type: Easing.OutCubic }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "stackview-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SwipeDelegate.qml b/src/quickcontrols2/imagine/SwipeDelegate.qml
new file mode 100644
index 0000000000..05e9e7d4a9
--- /dev/null
+++ b/src/quickcontrols2/imagine/SwipeDelegate.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SwipeDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ swipe.transition: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "swipedelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SwipeView.qml b/src/quickcontrols2/imagine/SwipeView.qml
new file mode 100644
index 0000000000..12cafbb815
--- /dev/null
+++ b/src/quickcontrols2/imagine/SwipeView.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SwipeView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: ListView {
+ model: control.contentModel
+ interactive: control.interactive
+ currentIndex: control.currentIndex
+ focus: control.focus
+
+ spacing: control.spacing
+ orientation: control.orientation
+ snapMode: ListView.SnapOneItem
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+ highlightMoveDuration: 250
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "swipeview-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"interactive": control.interactive},
+ {"focused": control.contentItem.activeFocus},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Switch.qml b/src/quickcontrols2/imagine/Switch.qml
new file mode 100644
index 0000000000..a7d83998ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/Switch.qml
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ indicator: NinePatchImage {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: Math.max(implicitWidth, handle.leftPadding && handle.rightPadding ? handle.implicitWidth : 2 * handle.implicitWidth)
+ height: Math.max(implicitHeight, handle.implicitHeight)
+
+ source: control.Imagine.url + "switch-indicator"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ property NinePatchImage handle: NinePatchImage {
+ readonly property real minPos: parent.leftPadding - leftPadding
+ readonly property real maxPos: parent.width - width + rightPadding - parent.rightPadding
+ readonly property real dragPos: control.visualPosition * parent.width - (width / 2)
+
+ parent: control.indicator
+
+ x: Math.max(minPos, Math.min(maxPos, control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+
+ source: control.Imagine.url + "switch-handle"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+ }
+
+ 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.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NinePatchImage {
+ source: control.Imagine.url + "switch-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/SwitchDelegate.qml b/src/quickcontrols2/imagine/SwitchDelegate.qml
new file mode 100644
index 0000000000..4c29ecd859
--- /dev/null
+++ b/src/quickcontrols2/imagine/SwitchDelegate.qml
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.SwitchDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.text
+
+ indicator: NinePatchImage {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ width: Math.max(implicitWidth, handle.leftPadding && handle.rightPadding ? handle.implicitWidth : 2 * handle.implicitWidth)
+ height: Math.max(implicitHeight, handle.implicitHeight)
+
+ source: control.Imagine.url + "switchdelegate-indicator"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ property NinePatchImage handle: NinePatchImage {
+ readonly property real minPos: parent.leftPadding - leftPadding
+ readonly property real maxPos: parent.width - width + rightPadding - parent.rightPadding
+ readonly property real dragPos: control.visualPosition * parent.width - (width / 2)
+
+ parent: control.indicator
+
+ x: Math.max(minPos, Math.min(maxPos, control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+
+ source: control.Imagine.url + "switchdelegate-handle"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+
+ Behavior on x {
+ enabled: !control.down
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+ }
+
+ contentItem: IconLabel {
+ leftPadding: control.mirrored ? control.indicator.width + control.spacing : 0
+ rightPadding: !control.mirrored ? control.indicator.width + control.spacing : 0
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.text
+ }
+
+ background: NinePatchImage {
+ source: control.Imagine.url + "switchdelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/TabBar.qml b/src/quickcontrols2/imagine/TabBar.qml
new file mode 100644
index 0000000000..26c30e926e
--- /dev/null
+++ b/src/quickcontrols2/imagine/TabBar.qml
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 0
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 48
+ preferredHighlightEnd: width - 48
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "tabbar-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"header": control.position === T.TabBar.Header },
+ {"footer": control.position === T.TabBar.Footer },
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/TabButton.qml b/src/quickcontrols2/imagine/TabButton.qml
new file mode 100644
index 0000000000..dff0024779
--- /dev/null
+++ b/src/quickcontrols2/imagine/TabButton.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "tabbutton-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/TextArea.qml b/src/quickcontrols2/imagine/TextArea.qml
new file mode 100644
index 0000000000..1309d7793a
--- /dev/null
+++ b/src/quickcontrols2/imagine/TextArea.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Qt.AlignVCenter
+ placeholderTextColor: control.palette.placeholderText
+
+ 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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "textarea-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/TextField.qml b/src/quickcontrols2/imagine/TextField.qml
new file mode 100644
index 0000000000..f2ae0ff8c3
--- /dev/null
+++ b/src/quickcontrols2/imagine/TextField.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.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)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: Qt.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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "textfield-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"focused": control.activeFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ToolBar.qml b/src/quickcontrols2/imagine/ToolBar.qml
new file mode 100644
index 0000000000..4a343e3c03
--- /dev/null
+++ b/src/quickcontrols2/imagine/ToolBar.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ background: NinePatchImage {
+ source: Imagine.url + "toolbar-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"header": control.position === T.ToolBar.Header },
+ {"footer": control.position === T.ToolBar.Footer },
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ToolButton.qml b/src/quickcontrols2/imagine/ToolButton.qml
new file mode 100644
index 0000000000..5c70693ac9
--- /dev/null
+++ b/src/quickcontrols2/imagine/ToolButton.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ spacing: 6 // ###
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "toolbutton-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"pressed": control.down},
+ {"checked": control.checked},
+ {"checkable": control.checkable},
+ {"focused": control.visualFocus},
+ {"highlighted": control.highlighted},
+ {"flat": control.flat},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ToolSeparator.qml b/src/quickcontrols2/imagine/ToolSeparator.qml
new file mode 100644
index 0000000000..962c14c741
--- /dev/null
+++ b/src/quickcontrols2/imagine/ToolSeparator.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ToolSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ contentItem: NinePatchImage {
+ source: Imagine.url + "toolseparator-separator"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "toolseparator-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"vertical": control.vertical},
+ {"horizontal": control.horizontal},
+ {"disabled": !control.enabled},
+ {"mirrored": control.mirrored}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/ToolTip.qml b/src/quickcontrols2/imagine/ToolTip.qml
new file mode 100644
index 0000000000..f52614000e
--- /dev/null
+++ b/src/quickcontrols2/imagine/ToolTip.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.ToolTip {
+ id: control
+
+ x: parent ? (parent.width - implicitWidth) / 2 : 0 - (background ? background.leftInset : 0)
+ y: -implicitHeight - (background ? background.topInset : 0)
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topMargin: background ? background.topInset : 0
+ leftMargin: background ? background.leftInset : 0
+ rightMargin: background ? background.rightInset : 0
+ bottomMargin: background ? background.bottomInset : 0
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ wrapMode: Text.Wrap
+ color: control.palette.toolTipText
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "tooltip-background"
+ NinePatchImageSelector on source {
+ states: [
+ // ###
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/Tumbler.qml b/src/quickcontrols2/imagine/Tumbler.qml
new file mode 100644
index 0000000000..6cd78fb6cc
--- /dev/null
+++ b/src/quickcontrols2/imagine/Tumbler.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+
+T.Tumbler {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ delegate: Text {
+ text: modelData
+ font: control.font
+ color: control.palette.text
+ opacity: (1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)) * (control.enabled ? 1 : 0.6)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ required property var modelData
+ required property int index
+ }
+
+ contentItem: TumblerView {
+ implicitWidth: 60
+ implicitHeight: 200
+ model: control.model
+ delegate: control.delegate
+ path: Path {
+ startX: control.contentItem.width / 2
+ startY: -control.contentItem.delegateHeight / 2
+ PathLine {
+ x: control.contentItem.width / 2
+ y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: control.availableHeight / control.visibleItemCount
+ }
+
+ background: NinePatchImage {
+ source: Imagine.url + "tumbler-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"disabled": !control.enabled},
+ {"focused": control.visualFocus},
+ {"mirrored": control.mirrored},
+ {"hovered": control.enabled && control.hovered}
+ ]
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/VerticalHeaderView.qml b/src/quickcontrols2/imagine/VerticalHeaderView.qml
new file mode 100644
index 0000000000..7c057e01e2
--- /dev/null
+++ b/src/quickcontrols2/imagine/VerticalHeaderView.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.VerticalHeaderView {
+ id: control
+
+ implicitWidth: contentWidth
+ implicitHeight: syncView ? syncView.height : 0
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: Math.max(control.width, text.implicitWidth + (cellPadding * 2))
+ implicitHeight: text.implicitHeight + (cellPadding * 2)
+ color: "#f6f6f6"
+ border.color: "#e4e4e4"
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: "#ff26282a"
+ }
+ }
+}
diff --git a/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/9-patch-export.js b/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/9-patch-export.js
new file mode 100644
index 0000000000..a7f9a4598d
--- /dev/null
+++ b/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/9-patch-export.js
@@ -0,0 +1,24 @@
+// 9-patch export
+//
+// This plugin crops upscaled 9-patch PNG assets when exported from Sketch,
+// to ensure that 9-patch borders remain 1px wide when upscaled.
+//
+function onExportSlices(context) {
+ var exports = context.actionContext.exports;
+ for (var i = 0; i < exports.count(); ++i) {
+ var name = exports[i].request.name();
+ var scale = exports[i].request.scale();
+ if (scale > 1 && name.endsWith(".9"))
+ cropAsset(exports[i].path, scale - 1);
+ }
+}
+
+function cropAsset(path, inset) {
+ var url = NSURL.fileURLWithPath(path);
+ var img = CIImage.imageWithContentsOfURL(url);
+ var rect = NSInsetRect(img.extent(), inset, inset);
+ var cropped = img.imageByCroppingToRect(rect);
+ var rep = NSBitmapImageRep.alloc().initWithCIImage(cropped);
+ var data = rep.PNGRepresentationWithInterlaced(false);
+ data.writeToFile(path);
+}
diff --git a/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/manifest.json b/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/manifest.json
new file mode 100644
index 0000000000..40807aa3d5
--- /dev/null
+++ b/src/quickcontrols2/imagine/design/9-patch-export.sketchplugin/Contents/Sketch/manifest.json
@@ -0,0 +1,19 @@
+{
+ "name" : "9-patch export",
+ "description" : "Crops upscaled 9-patch PNG assets when exported from Sketch.",
+ "version" : "0.1",
+ "identifier" : "org.qt-project.sketch.9-patch-export",
+ "author" : "The Qt Project",
+ "commands" : [
+ {
+ "name" : "9-patch export",
+ "identifier" : "9-patch-export",
+ "script" : "9-patch-export.js",
+ "handlers" : {
+ "actions" : {
+ "ExportSlices": "onExportSlices",
+ },
+ },
+ },
+ ],
+}
diff --git a/src/quickcontrols2/imagine/design/imagine.sketch b/src/quickcontrols2/imagine/design/imagine.sketch
new file mode 100644
index 0000000000..f3535b372b
--- /dev/null
+++ b/src/quickcontrols2/imagine/design/imagine.sketch
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-background.png b/src/quickcontrols2/imagine/images/applicationwindow-background.png
new file mode 100644
index 0000000000..2d8d70f288
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-background@2x.png b/src/quickcontrols2/imagine/images/applicationwindow-background@2x.png
new file mode 100644
index 0000000000..18fbaa4c63
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-background@3x.png b/src/quickcontrols2/imagine/images/applicationwindow-background@3x.png
new file mode 100644
index 0000000000..241232b1e0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-background@4x.png b/src/quickcontrols2/imagine/images/applicationwindow-background@4x.png
new file mode 100644
index 0000000000..8eb1b1ecc1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal.png
new file mode 100644
index 0000000000..d4a43d1c70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@2x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@2x.png
new file mode 100644
index 0000000000..c9a8f4124b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@3x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@3x.png
new file mode 100644
index 0000000000..4a1084a919
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@4x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@4x.png
new file mode 100644
index 0000000000..b92e600dae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay-modal@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay.png
new file mode 100644
index 0000000000..b7da23c00f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay@2x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay@2x.png
new file mode 100644
index 0000000000..23828d5a1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay@3x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay@3x.png
new file mode 100644
index 0000000000..d9d5382867
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/applicationwindow-overlay@4x.png b/src/quickcontrols2/imagine/images/applicationwindow-overlay@4x.png
new file mode 100644
index 0000000000..a76c1a3a71
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/applicationwindow-overlay@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/busyindicator-animation.webp b/src/quickcontrols2/imagine/images/busyindicator-animation.webp
new file mode 100644
index 0000000000..ebf04c4a0c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/busyindicator-animation.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/busyindicator-animation@2x.webp b/src/quickcontrols2/imagine/images/busyindicator-animation@2x.webp
new file mode 100644
index 0000000000..43805a0bdc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/busyindicator-animation@2x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/busyindicator-animation@3x.webp b/src/quickcontrols2/imagine/images/busyindicator-animation@3x.webp
new file mode 100644
index 0000000000..b700b81f83
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/busyindicator-animation@3x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/busyindicator-animation@4x.webp b/src/quickcontrols2/imagine/images/busyindicator-animation@4x.webp
new file mode 100644
index 0000000000..bfaa8df921
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/busyindicator-animation@4x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-disabled.9.png b/src/quickcontrols2/imagine/images/button-background-checked-disabled.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-disabled@2x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-disabled@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-disabled@3x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-disabled@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-disabled@4x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-disabled@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-focused.9.png b/src/quickcontrols2/imagine/images/button-background-checked-focused.9.png
new file mode 100644
index 0000000000..e3d14e9954
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-focused@2x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-focused@2x.9.png
new file mode 100644
index 0000000000..ebc74b4a34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-focused@3x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-focused@3x.9.png
new file mode 100644
index 0000000000..7583472304
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-focused@4x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-focused@4x.9.png
new file mode 100644
index 0000000000..9b570f4d15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-hovered.9.png b/src/quickcontrols2/imagine/images/button-background-checked-hovered.9.png
new file mode 100644
index 0000000000..e3d14e9954
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-hovered@2x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-hovered@2x.9.png
new file mode 100644
index 0000000000..ebc74b4a34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-hovered@3x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-hovered@3x.9.png
new file mode 100644
index 0000000000..7583472304
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked-hovered@4x.9.png b/src/quickcontrols2/imagine/images/button-background-checked-hovered@4x.9.png
new file mode 100644
index 0000000000..9b570f4d15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked.9.png b/src/quickcontrols2/imagine/images/button-background-checked.9.png
new file mode 100644
index 0000000000..d0942509f7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked@2x.9.png b/src/quickcontrols2/imagine/images/button-background-checked@2x.9.png
new file mode 100644
index 0000000000..c38bcd026f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked@3x.9.png b/src/quickcontrols2/imagine/images/button-background-checked@3x.9.png
new file mode 100644
index 0000000000..80889bf801
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-checked@4x.9.png b/src/quickcontrols2/imagine/images/button-background-checked@4x.9.png
new file mode 100644
index 0000000000..05de8377ef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-disabled.9.png b/src/quickcontrols2/imagine/images/button-background-disabled.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/button-background-disabled@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/button-background-disabled@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/button-background-disabled@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-checked@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-checked@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-disabled.9.png b/src/quickcontrols2/imagine/images/button-background-flat-disabled.9.png
new file mode 100644
index 0000000000..59907409c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-disabled@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-disabled@2x.9.png
new file mode 100644
index 0000000000..d66acd9c48
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-disabled@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-disabled@3x.9.png
new file mode 100644
index 0000000000..89b8c35357
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-disabled@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-disabled@4x.9.png
new file mode 100644
index 0000000000..d3a675cfe7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted.9.png
new file mode 100644
index 0000000000..59907409c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@2x.9.png
new file mode 100644
index 0000000000..d66acd9c48
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@3x.9.png
new file mode 100644
index 0000000000..89b8c35357
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@4x.9.png
new file mode 100644
index 0000000000..d3a675cfe7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-hovered.9.png b/src/quickcontrols2/imagine/images/button-background-flat-hovered.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-hovered@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-hovered@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-hovered@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-hovered@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-hovered@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-hovered@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-pressed.9.png b/src/quickcontrols2/imagine/images/button-background-flat-pressed.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-pressed@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-pressed@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-pressed@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-pressed@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat-pressed@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat-pressed@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat.9.png b/src/quickcontrols2/imagine/images/button-background-flat.9.png
new file mode 100644
index 0000000000..59907409c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat@2x.9.png b/src/quickcontrols2/imagine/images/button-background-flat@2x.9.png
new file mode 100644
index 0000000000..d66acd9c48
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat@3x.9.png b/src/quickcontrols2/imagine/images/button-background-flat@3x.9.png
new file mode 100644
index 0000000000..89b8c35357
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-flat@4x.9.png b/src/quickcontrols2/imagine/images/button-background-flat@4x.9.png
new file mode 100644
index 0000000000..d3a675cfe7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-flat@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-focused.9.png b/src/quickcontrols2/imagine/images/button-background-focused.9.png
new file mode 100644
index 0000000000..42e40e6082
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/button-background-focused@2x.9.png
new file mode 100644
index 0000000000..90dc70bfe0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/button-background-focused@3x.9.png
new file mode 100644
index 0000000000..2ed2340cb0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/button-background-focused@4x.9.png
new file mode 100644
index 0000000000..e1428e37eb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-checked.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-checked.9.png
new file mode 100644
index 0000000000..7a2a401106
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-checked@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@2x.9.png
new file mode 100644
index 0000000000..05b2f21423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-checked@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@3x.9.png
new file mode 100644
index 0000000000..8c22e1f32a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-checked@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@4x.9.png
new file mode 100644
index 0000000000..c5617f0e0d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-disabled.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-focused.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-focused.9.png
new file mode 100644
index 0000000000..3ea580e01f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-focused@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@2x.9.png
new file mode 100644
index 0000000000..effcce1f42
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-focused@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@3x.9.png
new file mode 100644
index 0000000000..502ac68999
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-focused@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@4x.9.png
new file mode 100644
index 0000000000..3243231ef7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-hovered.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered.9.png
new file mode 100644
index 0000000000..3ea580e01f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@2x.9.png
new file mode 100644
index 0000000000..effcce1f42
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@3x.9.png
new file mode 100644
index 0000000000..502ac68999
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@4x.9.png
new file mode 100644
index 0000000000..3243231ef7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-pressed.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed.9.png
new file mode 100644
index 0000000000..7a2a401106
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@2x.9.png
new file mode 100644
index 0000000000..05b2f21423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@3x.9.png
new file mode 100644
index 0000000000..8c22e1f32a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@4x.9.png
new file mode 100644
index 0000000000..c5617f0e0d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted.9.png
new file mode 100644
index 0000000000..7761595fcd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..8bb42c45af
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..8c23c021a5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/button-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..365cd0489d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-hovered.9.png b/src/quickcontrols2/imagine/images/button-background-hovered.9.png
new file mode 100644
index 0000000000..42e40e6082
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/button-background-hovered@2x.9.png
new file mode 100644
index 0000000000..90dc70bfe0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/button-background-hovered@3x.9.png
new file mode 100644
index 0000000000..2ed2340cb0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/button-background-hovered@4x.9.png
new file mode 100644
index 0000000000..e1428e37eb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-pressed.9.png b/src/quickcontrols2/imagine/images/button-background-pressed.9.png
new file mode 100644
index 0000000000..d0942509f7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/button-background-pressed@2x.9.png
new file mode 100644
index 0000000000..c38bcd026f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/button-background-pressed@3x.9.png
new file mode 100644
index 0000000000..80889bf801
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/button-background-pressed@4x.9.png
new file mode 100644
index 0000000000..05de8377ef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background.9.png b/src/quickcontrols2/imagine/images/button-background.9.png
new file mode 100644
index 0000000000..6f1daed831
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background@2x.9.png b/src/quickcontrols2/imagine/images/button-background@2x.9.png
new file mode 100644
index 0000000000..4a2507f535
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background@3x.9.png b/src/quickcontrols2/imagine/images/button-background@3x.9.png
new file mode 100644
index 0000000000..4f13b4ef55
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/button-background@4x.9.png b/src/quickcontrols2/imagine/images/button-background@4x.9.png
new file mode 100644
index 0000000000..0e1ab4524e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/button-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed.png
new file mode 100644
index 0000000000..9c03d096e4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..680ba3efca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..974205de54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..2c8b6aabf4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked.png
new file mode 100644
index 0000000000..598b163aaa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@2x.png
new file mode 100644
index 0000000000..06382264f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@3x.png
new file mode 100644
index 0000000000..12a32dcd20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@4x.png
new file mode 100644
index 0000000000..4bc6701d65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-disabled.png b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled.png
new file mode 100644
index 0000000000..0a499f8f2d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..db652c5ac9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..482f045d32
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@4x.png
new file mode 100644
index 0000000000..a386e27251
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-focused.png b/src/quickcontrols2/imagine/images/checkbox-indicator-focused.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-hovered.png b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused.png
new file mode 100644
index 0000000000..cd07b1ccb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@2x.png
new file mode 100644
index 0000000000..acae6afffe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@3x.png
new file mode 100644
index 0000000000..1e8d2c4575
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@4x.png
new file mode 100644
index 0000000000..577017c4c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered.png
new file mode 100644
index 0000000000..cd07b1ccb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@2x.png
new file mode 100644
index 0000000000..acae6afffe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@3x.png
new file mode 100644
index 0000000000..1e8d2c4575
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@4x.png
new file mode 100644
index 0000000000..577017c4c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed.png
new file mode 100644
index 0000000000..928706ab27
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@2x.png
new file mode 100644
index 0000000000..3645d78a21
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@3x.png
new file mode 100644
index 0000000000..ade63bd04b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@4x.png
new file mode 100644
index 0000000000..cd73617e3c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked.png
new file mode 100644
index 0000000000..e404a4e3c8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@2x.png
new file mode 100644
index 0000000000..2d0f51767a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@3x.png
new file mode 100644
index 0000000000..4b9777b7ea
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@4x.png
new file mode 100644
index 0000000000..e0f67e9894
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-partially-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-pressed.png b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed.png
new file mode 100644
index 0000000000..a1baaf903e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@2x.png
new file mode 100644
index 0000000000..81a7c3647a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@3x.png
new file mode 100644
index 0000000000..9325de38cb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@4x.png
new file mode 100644
index 0000000000..c93b8fb8a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator.png b/src/quickcontrols2/imagine/images/checkbox-indicator.png
new file mode 100644
index 0000000000..2b3e2323d7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator@2x.png b/src/quickcontrols2/imagine/images/checkbox-indicator@2x.png
new file mode 100644
index 0000000000..ce8985dbb1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator@3x.png b/src/quickcontrols2/imagine/images/checkbox-indicator@3x.png
new file mode 100644
index 0000000000..2968731dd7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkbox-indicator@4x.png b/src/quickcontrols2/imagine/images/checkbox-indicator@4x.png
new file mode 100644
index 0000000000..ea8da28498
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkbox-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-disabled.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled.9.png
new file mode 100644
index 0000000000..23570729d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-focused.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-focused.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted.9.png
new file mode 100644
index 0000000000..e79d8e1d01
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..ea68d35fc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..6d61041599
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..590cca96a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-hovered.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-pressed.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background@2x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background@3x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-background@4x.9.png b/src/quickcontrols2/imagine/images/checkdelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed.png
new file mode 100644
index 0000000000..9c03d096e4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..680ba3efca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..974205de54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..2c8b6aabf4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked.png
new file mode 100644
index 0000000000..598b163aaa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@2x.png
new file mode 100644
index 0000000000..06382264f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@3x.png
new file mode 100644
index 0000000000..12a32dcd20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@4x.png
new file mode 100644
index 0000000000..4bc6701d65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled.png
new file mode 100644
index 0000000000..0a499f8f2d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@2x.png
new file mode 100644
index 0000000000..db652c5ac9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@3x.png
new file mode 100644
index 0000000000..482f045d32
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@4x.png
new file mode 100644
index 0000000000..a386e27251
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused.png
new file mode 100644
index 0000000000..cd07b1ccb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@2x.png
new file mode 100644
index 0000000000..acae6afffe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@3x.png
new file mode 100644
index 0000000000..1e8d2c4575
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@4x.png
new file mode 100644
index 0000000000..577017c4c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered.png
new file mode 100644
index 0000000000..cd07b1ccb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@2x.png
new file mode 100644
index 0000000000..acae6afffe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@3x.png
new file mode 100644
index 0000000000..1e8d2c4575
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@4x.png
new file mode 100644
index 0000000000..577017c4c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed.png
new file mode 100644
index 0000000000..928706ab27
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@2x.png
new file mode 100644
index 0000000000..3645d78a21
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@3x.png
new file mode 100644
index 0000000000..ade63bd04b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@4x.png
new file mode 100644
index 0000000000..cd73617e3c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked.png
new file mode 100644
index 0000000000..e404a4e3c8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@2x.png
new file mode 100644
index 0000000000..2d0f51767a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@3x.png
new file mode 100644
index 0000000000..4b9777b7ea
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@4x.png
new file mode 100644
index 0000000000..e0f67e9894
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-partially-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed.png
new file mode 100644
index 0000000000..a1baaf903e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@2x.png
new file mode 100644
index 0000000000..81a7c3647a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@3x.png
new file mode 100644
index 0000000000..9325de38cb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@4x.png
new file mode 100644
index 0000000000..c93b8fb8a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator.png
new file mode 100644
index 0000000000..2b3e2323d7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator@2x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator@2x.png
new file mode 100644
index 0000000000..ce8985dbb1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator@3x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator@3x.png
new file mode 100644
index 0000000000..2968731dd7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/checkdelegate-indicator@4x.png b/src/quickcontrols2/imagine/images/checkdelegate-indicator@4x.png
new file mode 100644
index 0000000000..ea8da28498
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/checkdelegate-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-disabled.9.png b/src/quickcontrols2/imagine/images/combobox-background-disabled.9.png
new file mode 100644
index 0000000000..a91b4b5519
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-disabled@2x.9.png
new file mode 100644
index 0000000000..570b990c9b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-disabled@3x.9.png
new file mode 100644
index 0000000000..b0f9b9c4ce
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-disabled@4x.9.png
new file mode 100644
index 0000000000..6e810f7592
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-disabled.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled.9.png
new file mode 100644
index 0000000000..e192afb8a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@2x.9.png
new file mode 100644
index 0000000000..58a0f6e9a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@3x.9.png
new file mode 100644
index 0000000000..cd6f226b33
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@4x.9.png
new file mode 100644
index 0000000000..ff9103b091
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-focused.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-focused.9.png
new file mode 100644
index 0000000000..a0f079bc47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-focused@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@2x.9.png
new file mode 100644
index 0000000000..83cb503f89
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-focused@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@3x.9.png
new file mode 100644
index 0000000000..4cf96edf90
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable-focused@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@4x.9.png
new file mode 100644
index 0000000000..5823de804f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable.9.png
new file mode 100644
index 0000000000..8edac13208
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable@2x.9.png
new file mode 100644
index 0000000000..15e465f12a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable@3x.9.png
new file mode 100644
index 0000000000..910b48d2c6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-editable@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-editable@4x.9.png
new file mode 100644
index 0000000000..ff0f64118e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-editable@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-focused.9.png b/src/quickcontrols2/imagine/images/combobox-background-focused.9.png
new file mode 100644
index 0000000000..a3865fa698
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-focused@2x.9.png
new file mode 100644
index 0000000000..fc49f4b824
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-focused@3x.9.png
new file mode 100644
index 0000000000..b432b4ec54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-focused@4x.9.png
new file mode 100644
index 0000000000..1586205998
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-hovered.9.png b/src/quickcontrols2/imagine/images/combobox-background-hovered.9.png
new file mode 100644
index 0000000000..a3865fa698
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-hovered@2x.9.png
new file mode 100644
index 0000000000..fc49f4b824
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-hovered@3x.9.png
new file mode 100644
index 0000000000..b432b4ec54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-hovered@4x.9.png
new file mode 100644
index 0000000000..1586205998
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-open.9.png b/src/quickcontrols2/imagine/images/combobox-background-open.9.png
new file mode 100644
index 0000000000..1be8440336
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-open.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-open@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-open@2x.9.png
new file mode 100644
index 0000000000..95f7cd6d8a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-open@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-open@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-open@3x.9.png
new file mode 100644
index 0000000000..2f71271ce8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-open@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-open@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-open@4x.9.png
new file mode 100644
index 0000000000..17f6f2ce11
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-open@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-pressed.9.png b/src/quickcontrols2/imagine/images/combobox-background-pressed.9.png
new file mode 100644
index 0000000000..1be8440336
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background-pressed@2x.9.png
new file mode 100644
index 0000000000..95f7cd6d8a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background-pressed@3x.9.png
new file mode 100644
index 0000000000..2f71271ce8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background-pressed@4x.9.png
new file mode 100644
index 0000000000..17f6f2ce11
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background.9.png b/src/quickcontrols2/imagine/images/combobox-background.9.png
new file mode 100644
index 0000000000..4ed8ddc36f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background@2x.9.png b/src/quickcontrols2/imagine/images/combobox-background@2x.9.png
new file mode 100644
index 0000000000..1d7a88943a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background@3x.9.png b/src/quickcontrols2/imagine/images/combobox-background@3x.9.png
new file mode 100644
index 0000000000..313630f85c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-background@4x.9.png b/src/quickcontrols2/imagine/images/combobox-background@4x.9.png
new file mode 100644
index 0000000000..be63d56ea0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-disabled.png b/src/quickcontrols2/imagine/images/combobox-indicator-disabled.png
new file mode 100644
index 0000000000..761537f9c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@2x.png
new file mode 100644
index 0000000000..322b7b6837
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@3x.png
new file mode 100644
index 0000000000..73feec349d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@4x.png
new file mode 100644
index 0000000000..910c4d3d21
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled.png
new file mode 100644
index 0000000000..4399b6aab5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@2x.png
new file mode 100644
index 0000000000..e45a2ad125
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@3x.png
new file mode 100644
index 0000000000..23f74b10ea
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@4x.png
new file mode 100644
index 0000000000..db495899a8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled.png
new file mode 100644
index 0000000000..2e954ae99e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@2x.png
new file mode 100644
index 0000000000..252a5e37d5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@3x.png
new file mode 100644
index 0000000000..6d939a93f6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@4x.png
new file mode 100644
index 0000000000..00a21ebdfb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored.png
new file mode 100644
index 0000000000..ad52991212
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@2x.png
new file mode 100644
index 0000000000..70b995c135
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@3x.png
new file mode 100644
index 0000000000..9b86537727
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@4x.png
new file mode 100644
index 0000000000..b4f7ae25d3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable-mirrored@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable.png
new file mode 100644
index 0000000000..e053109f10
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable@2x.png
new file mode 100644
index 0000000000..b8dfd6fe0e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable@3x.png
new file mode 100644
index 0000000000..2cdee7a8f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator-editable@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator-editable@4x.png
new file mode 100644
index 0000000000..2569b4aef0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator-editable@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator.png b/src/quickcontrols2/imagine/images/combobox-indicator.png
new file mode 100644
index 0000000000..cc32f2a272
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator@2x.png b/src/quickcontrols2/imagine/images/combobox-indicator@2x.png
new file mode 100644
index 0000000000..57ea3f3082
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator@3x.png b/src/quickcontrols2/imagine/images/combobox-indicator@3x.png
new file mode 100644
index 0000000000..384f8152db
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-indicator@4x.png b/src/quickcontrols2/imagine/images/combobox-indicator@4x.png
new file mode 100644
index 0000000000..f326c03b4b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-popup.9.png b/src/quickcontrols2/imagine/images/combobox-popup.9.png
new file mode 100644
index 0000000000..7344cdf6db
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-popup.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-popup@2x.9.png b/src/quickcontrols2/imagine/images/combobox-popup@2x.9.png
new file mode 100644
index 0000000000..00c88c7d59
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-popup@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-popup@3x.9.png b/src/quickcontrols2/imagine/images/combobox-popup@3x.9.png
new file mode 100644
index 0000000000..82d911ed66
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-popup@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/combobox-popup@4x.9.png b/src/quickcontrols2/imagine/images/combobox-popup@4x.9.png
new file mode 100644
index 0000000000..98db30af66
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/combobox-popup@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused.9.png
new file mode 100644
index 0000000000..e3d14e9954
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@2x.9.png
new file mode 100644
index 0000000000..ebc74b4a34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@3x.9.png
new file mode 100644
index 0000000000..7583472304
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@4x.9.png
new file mode 100644
index 0000000000..9b570f4d15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered.9.png
new file mode 100644
index 0000000000..e3d14e9954
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@2x.9.png
new file mode 100644
index 0000000000..ebc74b4a34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@3x.9.png
new file mode 100644
index 0000000000..7583472304
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@4x.9.png
new file mode 100644
index 0000000000..9b570f4d15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked.9.png
new file mode 100644
index 0000000000..d0942509f7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked@2x.9.png
new file mode 100644
index 0000000000..c38bcd026f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked@3x.9.png
new file mode 100644
index 0000000000..80889bf801
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-checked@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-checked@4x.9.png
new file mode 100644
index 0000000000..05de8377ef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled.9.png
new file mode 100644
index 0000000000..8196289cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@2x.9.png
new file mode 100644
index 0000000000..76cd44908b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@3x.9.png
new file mode 100644
index 0000000000..8bd6259a47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@4x.9.png
new file mode 100644
index 0000000000..3e08152013
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-focused.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-focused.9.png
new file mode 100644
index 0000000000..294ff8bda6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-focused@2x.9.png
new file mode 100644
index 0000000000..48e2bbcb56
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-focused@3x.9.png
new file mode 100644
index 0000000000..0981eb2ac5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-focused@4x.9.png
new file mode 100644
index 0000000000..4ae48bfa36
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-hovered.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-hovered.9.png
new file mode 100644
index 0000000000..42e40e6082
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@2x.9.png
new file mode 100644
index 0000000000..90dc70bfe0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@3x.9.png
new file mode 100644
index 0000000000..2ed2340cb0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@4x.9.png
new file mode 100644
index 0000000000..e1428e37eb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-pressed.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-pressed.9.png
new file mode 100644
index 0000000000..d0942509f7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@2x.9.png
new file mode 100644
index 0000000000..c38bcd026f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@3x.9.png
new file mode 100644
index 0000000000..80889bf801
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@4x.9.png
new file mode 100644
index 0000000000..05de8377ef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background.9.png b/src/quickcontrols2/imagine/images/delaybutton-background.9.png
new file mode 100644
index 0000000000..6f1daed831
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background@2x.9.png
new file mode 100644
index 0000000000..4a2507f535
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background@3x.9.png
new file mode 100644
index 0000000000..4f13b4ef55
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-background@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-background@4x.9.png
new file mode 100644
index 0000000000..0e1ab4524e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-mask.9.png b/src/quickcontrols2/imagine/images/delaybutton-mask.9.png
new file mode 100644
index 0000000000..76d3967d04
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-mask.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-mask@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-mask@2x.9.png
new file mode 100644
index 0000000000..b8db224cc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-mask@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-mask@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-mask@3x.9.png
new file mode 100644
index 0000000000..3bff2c15ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-mask@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-mask@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-mask@4x.9.png
new file mode 100644
index 0000000000..045c7fac88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-mask@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress-disabled.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled.9.png
new file mode 100644
index 0000000000..5c209c9c6b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@2x.9.png
new file mode 100644
index 0000000000..0ef11a8d3c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@3x.9.png
new file mode 100644
index 0000000000..f3f8e54796
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@4x.9.png
new file mode 100644
index 0000000000..b24f50e669
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress.9.png
new file mode 100644
index 0000000000..4dd3aec5fe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress@2x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress@2x.9.png
new file mode 100644
index 0000000000..cd422076e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress@3x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress@3x.9.png
new file mode 100644
index 0000000000..08610300be
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/delaybutton-progress@4x.9.png b/src/quickcontrols2/imagine/images/delaybutton-progress@4x.9.png
new file mode 100644
index 0000000000..24cc19ba0a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/delaybutton-progress@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-disabled.png b/src/quickcontrols2/imagine/images/dial-background-disabled.png
new file mode 100644
index 0000000000..d7c4f847ce
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-disabled@2x.png b/src/quickcontrols2/imagine/images/dial-background-disabled@2x.png
new file mode 100644
index 0000000000..56b085df96
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-disabled@3x.png b/src/quickcontrols2/imagine/images/dial-background-disabled@3x.png
new file mode 100644
index 0000000000..4f1e17e7a9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-disabled@4x.png b/src/quickcontrols2/imagine/images/dial-background-disabled@4x.png
new file mode 100644
index 0000000000..4aacbf8222
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-focused.png b/src/quickcontrols2/imagine/images/dial-background-focused.png
new file mode 100644
index 0000000000..fc53d5c407
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-focused@2x.png b/src/quickcontrols2/imagine/images/dial-background-focused@2x.png
new file mode 100644
index 0000000000..6b547a172d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-focused@3x.png b/src/quickcontrols2/imagine/images/dial-background-focused@3x.png
new file mode 100644
index 0000000000..7b8a2582ad
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background-focused@4x.png b/src/quickcontrols2/imagine/images/dial-background-focused@4x.png
new file mode 100644
index 0000000000..406f46b591
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background.png b/src/quickcontrols2/imagine/images/dial-background.png
new file mode 100644
index 0000000000..58aa09edb2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background@2x.png b/src/quickcontrols2/imagine/images/dial-background@2x.png
new file mode 100644
index 0000000000..87cd9a0f6b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background@3x.png b/src/quickcontrols2/imagine/images/dial-background@3x.png
new file mode 100644
index 0000000000..103fb46107
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-background@4x.png b/src/quickcontrols2/imagine/images/dial-background@4x.png
new file mode 100644
index 0000000000..c290f84a8f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-disabled.png b/src/quickcontrols2/imagine/images/dial-handle-disabled.png
new file mode 100644
index 0000000000..a93fd0f2b6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/dial-handle-disabled@2x.png
new file mode 100644
index 0000000000..2cd536be06
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/dial-handle-disabled@3x.png
new file mode 100644
index 0000000000..56b9fe06db
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/dial-handle-disabled@4x.png
new file mode 100644
index 0000000000..5098d6887c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-hovered.png b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered.png
new file mode 100644
index 0000000000..2a143f2afb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@2x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@2x.png
new file mode 100644
index 0000000000..24dfee8284
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@3x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@3x.png
new file mode 100644
index 0000000000..16e128d5cc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@4x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@4x.png
new file mode 100644
index 0000000000..b4523acb70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-pressed.png b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed.png
new file mode 100644
index 0000000000..d43971ff4d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@2x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@2x.png
new file mode 100644
index 0000000000..caa2376e9b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@3x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@3x.png
new file mode 100644
index 0000000000..c291388316
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@4x.png b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@4x.png
new file mode 100644
index 0000000000..50ff1c8bf4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused.png b/src/quickcontrols2/imagine/images/dial-handle-focused.png
new file mode 100644
index 0000000000..d2733474b9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused@2x.png b/src/quickcontrols2/imagine/images/dial-handle-focused@2x.png
new file mode 100644
index 0000000000..c7bc8f743b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused@3x.png b/src/quickcontrols2/imagine/images/dial-handle-focused@3x.png
new file mode 100644
index 0000000000..c0dcd94535
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-focused@4x.png b/src/quickcontrols2/imagine/images/dial-handle-focused@4x.png
new file mode 100644
index 0000000000..b9d2234c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-hovered.png b/src/quickcontrols2/imagine/images/dial-handle-hovered.png
new file mode 100644
index 0000000000..f5d0ac6f7f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-hovered@2x.png b/src/quickcontrols2/imagine/images/dial-handle-hovered@2x.png
new file mode 100644
index 0000000000..da23baaa90
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-hovered@3x.png b/src/quickcontrols2/imagine/images/dial-handle-hovered@3x.png
new file mode 100644
index 0000000000..7287a41923
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-hovered@4x.png b/src/quickcontrols2/imagine/images/dial-handle-hovered@4x.png
new file mode 100644
index 0000000000..9f6982dd56
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-pressed.png b/src/quickcontrols2/imagine/images/dial-handle-pressed.png
new file mode 100644
index 0000000000..3b98e1245c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/dial-handle-pressed@2x.png
new file mode 100644
index 0000000000..454e73644d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/dial-handle-pressed@3x.png
new file mode 100644
index 0000000000..794516da1e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/dial-handle-pressed@4x.png
new file mode 100644
index 0000000000..211b1135be
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle.png b/src/quickcontrols2/imagine/images/dial-handle.png
new file mode 100644
index 0000000000..652b82d30e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle@2x.png b/src/quickcontrols2/imagine/images/dial-handle@2x.png
new file mode 100644
index 0000000000..3c86a59bff
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle@3x.png b/src/quickcontrols2/imagine/images/dial-handle@3x.png
new file mode 100644
index 0000000000..cbfcdbcdc6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dial-handle@4x.png b/src/quickcontrols2/imagine/images/dial-handle@4x.png
new file mode 100644
index 0000000000..2872e006fa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dial-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-background.9.png b/src/quickcontrols2/imagine/images/dialog-background.9.png
new file mode 100644
index 0000000000..c842b5ff58
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-background@2x.9.png b/src/quickcontrols2/imagine/images/dialog-background@2x.9.png
new file mode 100644
index 0000000000..ca23df1f0d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-background@3x.9.png b/src/quickcontrols2/imagine/images/dialog-background@3x.9.png
new file mode 100644
index 0000000000..46cd406536
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-background@4x.9.png b/src/quickcontrols2/imagine/images/dialog-background@4x.9.png
new file mode 100644
index 0000000000..3da74119cc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay-modal.png b/src/quickcontrols2/imagine/images/dialog-overlay-modal.png
new file mode 100644
index 0000000000..d4a43d1c70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay-modal.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay-modal@2x.png b/src/quickcontrols2/imagine/images/dialog-overlay-modal@2x.png
new file mode 100644
index 0000000000..c9a8f4124b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay-modal@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay-modal@3x.png b/src/quickcontrols2/imagine/images/dialog-overlay-modal@3x.png
new file mode 100644
index 0000000000..4a1084a919
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay-modal@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay-modal@4x.png b/src/quickcontrols2/imagine/images/dialog-overlay-modal@4x.png
new file mode 100644
index 0000000000..b92e600dae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay-modal@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay.png b/src/quickcontrols2/imagine/images/dialog-overlay.png
new file mode 100644
index 0000000000..b7da23c00f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay@2x.png b/src/quickcontrols2/imagine/images/dialog-overlay@2x.png
new file mode 100644
index 0000000000..23828d5a1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay@3x.png b/src/quickcontrols2/imagine/images/dialog-overlay@3x.png
new file mode 100644
index 0000000000..d9d5382867
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialog-overlay@4x.png b/src/quickcontrols2/imagine/images/dialog-overlay@4x.png
new file mode 100644
index 0000000000..a76c1a3a71
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialog-overlay@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialogbuttonbox-background.9.png b/src/quickcontrols2/imagine/images/dialogbuttonbox-background.9.png
new file mode 100644
index 0000000000..4b080c7f8b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialogbuttonbox-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialogbuttonbox-background@2x.9.png b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@2x.9.png
new file mode 100644
index 0000000000..38306bea93
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialogbuttonbox-background@3x.9.png b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@3x.9.png
new file mode 100644
index 0000000000..66afaabe22
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/dialogbuttonbox-background@4x.9.png b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@4x.9.png
new file mode 100644
index 0000000000..7d0db539c1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/dialogbuttonbox-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-bottom.9.png b/src/quickcontrols2/imagine/images/drawer-background-bottom.9.png
new file mode 100644
index 0000000000..023d8bf806
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-bottom.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-bottom@2x.9.png b/src/quickcontrols2/imagine/images/drawer-background-bottom@2x.9.png
new file mode 100644
index 0000000000..6b229ce9e7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-bottom@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-bottom@3x.9.png b/src/quickcontrols2/imagine/images/drawer-background-bottom@3x.9.png
new file mode 100644
index 0000000000..c61118b651
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-bottom@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-bottom@4x.9.png b/src/quickcontrols2/imagine/images/drawer-background-bottom@4x.9.png
new file mode 100644
index 0000000000..08b2e25f30
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-bottom@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-left.9.png b/src/quickcontrols2/imagine/images/drawer-background-left.9.png
new file mode 100644
index 0000000000..5145a3a3f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-left.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-left@2x.9.png b/src/quickcontrols2/imagine/images/drawer-background-left@2x.9.png
new file mode 100644
index 0000000000..95a80ab530
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-left@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-left@3x.9.png b/src/quickcontrols2/imagine/images/drawer-background-left@3x.9.png
new file mode 100644
index 0000000000..bd330b7f8e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-left@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-left@4x.9.png b/src/quickcontrols2/imagine/images/drawer-background-left@4x.9.png
new file mode 100644
index 0000000000..10f0702a11
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-left@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-right.9.png b/src/quickcontrols2/imagine/images/drawer-background-right.9.png
new file mode 100644
index 0000000000..37afb73465
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-right.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-right@2x.9.png b/src/quickcontrols2/imagine/images/drawer-background-right@2x.9.png
new file mode 100644
index 0000000000..cfbc8f35a2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-right@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-right@3x.9.png b/src/quickcontrols2/imagine/images/drawer-background-right@3x.9.png
new file mode 100644
index 0000000000..9a49b6d530
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-right@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-right@4x.9.png b/src/quickcontrols2/imagine/images/drawer-background-right@4x.9.png
new file mode 100644
index 0000000000..564057760a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-right@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-top.9.png b/src/quickcontrols2/imagine/images/drawer-background-top.9.png
new file mode 100644
index 0000000000..56da059ff9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-top.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-top@2x.9.png b/src/quickcontrols2/imagine/images/drawer-background-top@2x.9.png
new file mode 100644
index 0000000000..976671ce59
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-top@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-top@3x.9.png b/src/quickcontrols2/imagine/images/drawer-background-top@3x.9.png
new file mode 100644
index 0000000000..7c07deba34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-top@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-background-top@4x.9.png b/src/quickcontrols2/imagine/images/drawer-background-top@4x.9.png
new file mode 100644
index 0000000000..e3b1edf7c2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-background-top@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay-modal.png b/src/quickcontrols2/imagine/images/drawer-overlay-modal.png
new file mode 100644
index 0000000000..d4a43d1c70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay-modal.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay-modal@2x.png b/src/quickcontrols2/imagine/images/drawer-overlay-modal@2x.png
new file mode 100644
index 0000000000..c9a8f4124b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay-modal@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay-modal@3x.png b/src/quickcontrols2/imagine/images/drawer-overlay-modal@3x.png
new file mode 100644
index 0000000000..4a1084a919
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay-modal@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay-modal@4x.png b/src/quickcontrols2/imagine/images/drawer-overlay-modal@4x.png
new file mode 100644
index 0000000000..b92e600dae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay-modal@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay.png b/src/quickcontrols2/imagine/images/drawer-overlay.png
new file mode 100644
index 0000000000..b7da23c00f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay@2x.png b/src/quickcontrols2/imagine/images/drawer-overlay@2x.png
new file mode 100644
index 0000000000..23828d5a1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay@3x.png b/src/quickcontrols2/imagine/images/drawer-overlay@3x.png
new file mode 100644
index 0000000000..d9d5382867
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/drawer-overlay@4x.png b/src/quickcontrols2/imagine/images/drawer-overlay@4x.png
new file mode 100644
index 0000000000..a76c1a3a71
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/drawer-overlay@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/frame-background.9.png b/src/quickcontrols2/imagine/images/frame-background.9.png
new file mode 100644
index 0000000000..8674059de8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/frame-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/frame-background@2x.9.png b/src/quickcontrols2/imagine/images/frame-background@2x.9.png
new file mode 100644
index 0000000000..196614964a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/frame-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/frame-background@3x.9.png b/src/quickcontrols2/imagine/images/frame-background@3x.9.png
new file mode 100644
index 0000000000..07d644be96
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/frame-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/frame-background@4x.9.png b/src/quickcontrols2/imagine/images/frame-background@4x.9.png
new file mode 100644
index 0000000000..8bf47d2a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/frame-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-background.9.png b/src/quickcontrols2/imagine/images/groupbox-background.9.png
new file mode 100644
index 0000000000..8674059de8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-background@2x.9.png b/src/quickcontrols2/imagine/images/groupbox-background@2x.9.png
new file mode 100644
index 0000000000..196614964a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-background@3x.9.png b/src/quickcontrols2/imagine/images/groupbox-background@3x.9.png
new file mode 100644
index 0000000000..07d644be96
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-background@4x.9.png b/src/quickcontrols2/imagine/images/groupbox-background@4x.9.png
new file mode 100644
index 0000000000..8bf47d2a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-title.9.png b/src/quickcontrols2/imagine/images/groupbox-title.9.png
new file mode 100644
index 0000000000..e85e0cb135
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-title.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-title@2x.9.png b/src/quickcontrols2/imagine/images/groupbox-title@2x.9.png
new file mode 100644
index 0000000000..d5359d857d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-title@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-title@3x.9.png b/src/quickcontrols2/imagine/images/groupbox-title@3x.9.png
new file mode 100644
index 0000000000..0e4b5c9f9f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-title@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/groupbox-title@4x.9.png b/src/quickcontrols2/imagine/images/groupbox-title@4x.9.png
new file mode 100644
index 0000000000..908dfe6b90
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/groupbox-title@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-disabled.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled.9.png
new file mode 100644
index 0000000000..23570729d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-focused.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-focused.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted.9.png
new file mode 100644
index 0000000000..e79d8e1d01
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..ea68d35fc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..6d61041599
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..590cca96a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-hovered.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-pressed.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background@2x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background@3x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/itemdelegate-background@4x.9.png b/src/quickcontrols2/imagine/images/itemdelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/itemdelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menu-background.9.png b/src/quickcontrols2/imagine/images/menu-background.9.png
new file mode 100644
index 0000000000..3195fbc336
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menu-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menu-background@2x.9.png b/src/quickcontrols2/imagine/images/menu-background@2x.9.png
new file mode 100644
index 0000000000..454c347ced
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menu-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menu-background@3x.9.png b/src/quickcontrols2/imagine/images/menu-background@3x.9.png
new file mode 100644
index 0000000000..32ed60860f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menu-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menu-background@4x.9.png b/src/quickcontrols2/imagine/images/menu-background@4x.9.png
new file mode 100644
index 0000000000..948cc3e95f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menu-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-disabled.png b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled.png
new file mode 100644
index 0000000000..6cad53f6c8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@2x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@2x.png
new file mode 100644
index 0000000000..bad6fe8c0f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@3x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@3x.png
new file mode 100644
index 0000000000..da420091a9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@4x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@4x.png
new file mode 100644
index 0000000000..2d8e44e2f6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled.png
new file mode 100644
index 0000000000..44ac277145
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@2x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@2x.png
new file mode 100644
index 0000000000..71a9b88a80
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@3x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@3x.png
new file mode 100644
index 0000000000..1e03f2156e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@4x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@4x.png
new file mode 100644
index 0000000000..0f85b409d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored.png
new file mode 100644
index 0000000000..4ac1160bf2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@2x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@2x.png
new file mode 100644
index 0000000000..79b089b654
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@3x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@3x.png
new file mode 100644
index 0000000000..aeb191fdd5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@4x.png b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@4x.png
new file mode 100644
index 0000000000..139fab35e0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow-mirrored@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow.png b/src/quickcontrols2/imagine/images/menuitem-arrow.png
new file mode 100644
index 0000000000..edf1f6bd1a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow@2x.png b/src/quickcontrols2/imagine/images/menuitem-arrow@2x.png
new file mode 100644
index 0000000000..8e6292653e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow@3x.png b/src/quickcontrols2/imagine/images/menuitem-arrow@3x.png
new file mode 100644
index 0000000000..0cef53acf5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-arrow@4x.png b/src/quickcontrols2/imagine/images/menuitem-arrow@4x.png
new file mode 100644
index 0000000000..dbdc83bc16
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-arrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background-highlighted.9.png b/src/quickcontrols2/imagine/images/menuitem-background-highlighted.9.png
new file mode 100644
index 0000000000..7b8fa0f42f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..9edc30793b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..183f6194ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..0a1ab8637d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background.9.png b/src/quickcontrols2/imagine/images/menuitem-background.9.png
new file mode 100644
index 0000000000..aab131eddf
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background@2x.9.png b/src/quickcontrols2/imagine/images/menuitem-background@2x.9.png
new file mode 100644
index 0000000000..c46938c4d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background@3x.9.png b/src/quickcontrols2/imagine/images/menuitem-background@3x.9.png
new file mode 100644
index 0000000000..bac1a83f7f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-background@4x.9.png b/src/quickcontrols2/imagine/images/menuitem-background@4x.9.png
new file mode 100644
index 0000000000..ba77504c27
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered.png
new file mode 100644
index 0000000000..d55a520426
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..7289f63949
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..02d6cdf205
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..3f074dbfa9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed.png
new file mode 100644
index 0000000000..9c03d096e4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..680ba3efca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..974205de54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..2c8b6aabf4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked.png
new file mode 100644
index 0000000000..598b163aaa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@2x.png
new file mode 100644
index 0000000000..06382264f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@3x.png
new file mode 100644
index 0000000000..12a32dcd20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@4x.png
new file mode 100644
index 0000000000..4bc6701d65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-disabled.png b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled.png
new file mode 100644
index 0000000000..0a499f8f2d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@2x.png
new file mode 100644
index 0000000000..db652c5ac9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@3x.png
new file mode 100644
index 0000000000..482f045d32
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@4x.png
new file mode 100644
index 0000000000..a386e27251
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-focused.png b/src/quickcontrols2/imagine/images/menuitem-indicator-focused.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-hovered.png b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered.png
new file mode 100644
index 0000000000..c5eb85276d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@2x.png
new file mode 100644
index 0000000000..8496fb1a88
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@3x.png
new file mode 100644
index 0000000000..30849fd0f0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@4x.png
new file mode 100644
index 0000000000..55ce7c0c1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-pressed.png b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed.png
new file mode 100644
index 0000000000..a1baaf903e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@2x.png
new file mode 100644
index 0000000000..81a7c3647a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@3x.png
new file mode 100644
index 0000000000..9325de38cb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@4x.png
new file mode 100644
index 0000000000..c93b8fb8a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator.png b/src/quickcontrols2/imagine/images/menuitem-indicator.png
new file mode 100644
index 0000000000..2b3e2323d7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator@2x.png b/src/quickcontrols2/imagine/images/menuitem-indicator@2x.png
new file mode 100644
index 0000000000..ce8985dbb1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator@3x.png b/src/quickcontrols2/imagine/images/menuitem-indicator@3x.png
new file mode 100644
index 0000000000..2968731dd7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuitem-indicator@4x.png b/src/quickcontrols2/imagine/images/menuitem-indicator@4x.png
new file mode 100644
index 0000000000..ea8da28498
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuitem-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuseparator-separator.9.png b/src/quickcontrols2/imagine/images/menuseparator-separator.9.png
new file mode 100644
index 0000000000..b8825b99ca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuseparator-separator.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuseparator-separator@2x.9.png b/src/quickcontrols2/imagine/images/menuseparator-separator@2x.9.png
new file mode 100644
index 0000000000..3e5a023d76
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuseparator-separator@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuseparator-separator@3x.9.png b/src/quickcontrols2/imagine/images/menuseparator-separator@3x.9.png
new file mode 100644
index 0000000000..abe775c7a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuseparator-separator@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/menuseparator-separator@4x.9.png b/src/quickcontrols2/imagine/images/menuseparator-separator@4x.9.png
new file mode 100644
index 0000000000..164c8e3e22
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/menuseparator-separator@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/page-background.png b/src/quickcontrols2/imagine/images/page-background.png
new file mode 100644
index 0000000000..2d8d70f288
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/page-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/page-background@2x.png b/src/quickcontrols2/imagine/images/page-background@2x.png
new file mode 100644
index 0000000000..18fbaa4c63
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/page-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/page-background@3x.png b/src/quickcontrols2/imagine/images/page-background@3x.png
new file mode 100644
index 0000000000..241232b1e0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/page-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/page-background@4x.png b/src/quickcontrols2/imagine/images/page-background@4x.png
new file mode 100644
index 0000000000..8eb1b1ecc1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/page-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-current.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-current.png
new file mode 100644
index 0000000000..dc96d72326
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-current.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-current@2x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@2x.png
new file mode 100644
index 0000000000..3e0d794fd5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-current@3x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@3x.png
new file mode 100644
index 0000000000..397501a7db
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-current@4x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@4x.png
new file mode 100644
index 0000000000..f741a8963b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-current@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current.png
new file mode 100644
index 0000000000..848d4351a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@2x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@2x.png
new file mode 100644
index 0000000000..65b5a9d42f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@3x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@3x.png
new file mode 100644
index 0000000000..99e3b644aa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@4x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@4x.png
new file mode 100644
index 0000000000..f1801fffef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled-current@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled.png
new file mode 100644
index 0000000000..848d4351a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@2x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@2x.png
new file mode 100644
index 0000000000..65b5a9d42f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@3x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@3x.png
new file mode 100644
index 0000000000..99e3b644aa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@4x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@4x.png
new file mode 100644
index 0000000000..f1801fffef
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed.png
new file mode 100644
index 0000000000..dc96d72326
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@2x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@2x.png
new file mode 100644
index 0000000000..3e0d794fd5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@3x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@3x.png
new file mode 100644
index 0000000000..397501a7db
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@4x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@4x.png
new file mode 100644
index 0000000000..f741a8963b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate.png b/src/quickcontrols2/imagine/images/pageindicator-delegate.png
new file mode 100644
index 0000000000..84d23cd1ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate@2x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate@2x.png
new file mode 100644
index 0000000000..0e706372c2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate@3x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate@3x.png
new file mode 100644
index 0000000000..85af5a4e4b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pageindicator-delegate@4x.png b/src/quickcontrols2/imagine/images/pageindicator-delegate@4x.png
new file mode 100644
index 0000000000..0aacbab1a9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pageindicator-delegate@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pane-background.9.png b/src/quickcontrols2/imagine/images/pane-background.9.png
new file mode 100644
index 0000000000..658f4863ea
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pane-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pane-background@2x.9.png b/src/quickcontrols2/imagine/images/pane-background@2x.9.png
new file mode 100644
index 0000000000..a84ac04a1f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pane-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pane-background@3x.9.png b/src/quickcontrols2/imagine/images/pane-background@3x.9.png
new file mode 100644
index 0000000000..2b1c4da9de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pane-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/pane-background@4x.9.png b/src/quickcontrols2/imagine/images/pane-background@4x.9.png
new file mode 100644
index 0000000000..90295db412
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/pane-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-background.9.png b/src/quickcontrols2/imagine/images/popup-background.9.png
new file mode 100644
index 0000000000..c842b5ff58
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-background@2x.9.png b/src/quickcontrols2/imagine/images/popup-background@2x.9.png
new file mode 100644
index 0000000000..ca23df1f0d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-background@3x.9.png b/src/quickcontrols2/imagine/images/popup-background@3x.9.png
new file mode 100644
index 0000000000..46cd406536
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-background@4x.9.png b/src/quickcontrols2/imagine/images/popup-background@4x.9.png
new file mode 100644
index 0000000000..3da74119cc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay-modal.png b/src/quickcontrols2/imagine/images/popup-overlay-modal.png
new file mode 100644
index 0000000000..d4a43d1c70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay-modal.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay-modal@2x.png b/src/quickcontrols2/imagine/images/popup-overlay-modal@2x.png
new file mode 100644
index 0000000000..c9a8f4124b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay-modal@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay-modal@3x.png b/src/quickcontrols2/imagine/images/popup-overlay-modal@3x.png
new file mode 100644
index 0000000000..4a1084a919
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay-modal@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay-modal@4x.png b/src/quickcontrols2/imagine/images/popup-overlay-modal@4x.png
new file mode 100644
index 0000000000..b92e600dae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay-modal@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay.png b/src/quickcontrols2/imagine/images/popup-overlay.png
new file mode 100644
index 0000000000..b7da23c00f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay@2x.png b/src/quickcontrols2/imagine/images/popup-overlay@2x.png
new file mode 100644
index 0000000000..23828d5a1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay@3x.png b/src/quickcontrols2/imagine/images/popup-overlay@3x.png
new file mode 100644
index 0000000000..d9d5382867
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/popup-overlay@4x.png b/src/quickcontrols2/imagine/images/popup-overlay@4x.png
new file mode 100644
index 0000000000..a76c1a3a71
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/popup-overlay@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-animation.webp b/src/quickcontrols2/imagine/images/progressbar-animation.webp
new file mode 100644
index 0000000000..51c35c8823
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-animation.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-animation@2x.webp b/src/quickcontrols2/imagine/images/progressbar-animation@2x.webp
new file mode 100644
index 0000000000..ee1206302a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-animation@2x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-animation@3x.webp b/src/quickcontrols2/imagine/images/progressbar-animation@3x.webp
new file mode 100644
index 0000000000..c2f94a74a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-animation@3x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-animation@4x.webp b/src/quickcontrols2/imagine/images/progressbar-animation@4x.webp
new file mode 100644
index 0000000000..d49657e934
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-animation@4x.webp
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-background.9.png b/src/quickcontrols2/imagine/images/progressbar-background.9.png
new file mode 100644
index 0000000000..e1760070b3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-background@2x.9.png b/src/quickcontrols2/imagine/images/progressbar-background@2x.9.png
new file mode 100644
index 0000000000..e69922d57e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-background@3x.9.png b/src/quickcontrols2/imagine/images/progressbar-background@3x.9.png
new file mode 100644
index 0000000000..b3c43205c3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-background@4x.9.png b/src/quickcontrols2/imagine/images/progressbar-background@4x.9.png
new file mode 100644
index 0000000000..905bdc328f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-mask.9.png b/src/quickcontrols2/imagine/images/progressbar-mask.9.png
new file mode 100644
index 0000000000..35a47dc807
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-mask.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-mask@2x.9.png b/src/quickcontrols2/imagine/images/progressbar-mask@2x.9.png
new file mode 100644
index 0000000000..23ed1a8cf1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-mask@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-mask@3x.9.png b/src/quickcontrols2/imagine/images/progressbar-mask@3x.9.png
new file mode 100644
index 0000000000..25bc843e3a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-mask@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-mask@4x.9.png b/src/quickcontrols2/imagine/images/progressbar-mask@4x.9.png
new file mode 100644
index 0000000000..645ff20179
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-mask@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-progress.png b/src/quickcontrols2/imagine/images/progressbar-progress.png
new file mode 100644
index 0000000000..bb31dc9b14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-progress.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-progress@2x.png b/src/quickcontrols2/imagine/images/progressbar-progress@2x.png
new file mode 100644
index 0000000000..6bb464c90b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-progress@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-progress@3x.png b/src/quickcontrols2/imagine/images/progressbar-progress@3x.png
new file mode 100644
index 0000000000..d514c72772
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-progress@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/progressbar-progress@4x.png b/src/quickcontrols2/imagine/images/progressbar-progress@4x.png
new file mode 100644
index 0000000000..abc8fa6753
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/progressbar-progress@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused.png
new file mode 100644
index 0000000000..2f9e5e18e9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..47ec553423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..26cdebf817
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..708e286ea7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered.png
new file mode 100644
index 0000000000..2f9e5e18e9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..47ec553423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..26cdebf817
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..708e286ea7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed.png
new file mode 100644
index 0000000000..1e5ebca46a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..6eaae9bf3e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..e54a1624d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..7a7850bada
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked.png
new file mode 100644
index 0000000000..83c8562379
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@2x.png
new file mode 100644
index 0000000000..4bdeb4566e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@3x.png
new file mode 100644
index 0000000000..2230a8ce09
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@4x.png
new file mode 100644
index 0000000000..e3dce04e56
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled.png
new file mode 100644
index 0000000000..05b8bfcadb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@2x.png
new file mode 100644
index 0000000000..e26fa5de81
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@3x.png
new file mode 100644
index 0000000000..c47e8c7d13
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@4x.png
new file mode 100644
index 0000000000..bc66dde78d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-focused.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused.png
new file mode 100644
index 0000000000..3001638d37
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@2x.png
new file mode 100644
index 0000000000..b98907149e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@3x.png
new file mode 100644
index 0000000000..b6221277d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@4x.png
new file mode 100644
index 0000000000..49ae2206ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered.png
new file mode 100644
index 0000000000..3001638d37
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@2x.png
new file mode 100644
index 0000000000..b98907149e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@3x.png
new file mode 100644
index 0000000000..b6221277d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@4x.png
new file mode 100644
index 0000000000..49ae2206ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed.png
new file mode 100644
index 0000000000..76c7b4ed7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@2x.png
new file mode 100644
index 0000000000..d5d4cac6d1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@3x.png
new file mode 100644
index 0000000000..ca2a1ed169
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@4x.png
new file mode 100644
index 0000000000..1cb753d72f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator.png b/src/quickcontrols2/imagine/images/radiobutton-indicator.png
new file mode 100644
index 0000000000..c05d4bfc05
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator@2x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator@2x.png
new file mode 100644
index 0000000000..62744d2726
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator@3x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator@3x.png
new file mode 100644
index 0000000000..fa5d241e70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiobutton-indicator@4x.png b/src/quickcontrols2/imagine/images/radiobutton-indicator@4x.png
new file mode 100644
index 0000000000..7db85e9432
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiobutton-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-disabled.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled.9.png
new file mode 100644
index 0000000000..23570729d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-focused.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-focused.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted.9.png
new file mode 100644
index 0000000000..e79d8e1d01
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..ea68d35fc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..6d61041599
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..590cca96a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-hovered.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-pressed.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background@2x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background@3x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-background@4x.9.png b/src/quickcontrols2/imagine/images/radiodelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused.png
new file mode 100644
index 0000000000..2f9e5e18e9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..47ec553423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..26cdebf817
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..708e286ea7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered.png
new file mode 100644
index 0000000000..2f9e5e18e9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..47ec553423
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..26cdebf817
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..708e286ea7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed.png
new file mode 100644
index 0000000000..1e5ebca46a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..6eaae9bf3e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..e54a1624d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..7a7850bada
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked.png
new file mode 100644
index 0000000000..83c8562379
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@2x.png
new file mode 100644
index 0000000000..4bdeb4566e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@3x.png
new file mode 100644
index 0000000000..2230a8ce09
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@4x.png
new file mode 100644
index 0000000000..e3dce04e56
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled.png
new file mode 100644
index 0000000000..05b8bfcadb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@2x.png
new file mode 100644
index 0000000000..e26fa5de81
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@3x.png
new file mode 100644
index 0000000000..c47e8c7d13
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@4x.png
new file mode 100644
index 0000000000..bc66dde78d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused.png
new file mode 100644
index 0000000000..3001638d37
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@2x.png
new file mode 100644
index 0000000000..b98907149e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@3x.png
new file mode 100644
index 0000000000..b6221277d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@4x.png
new file mode 100644
index 0000000000..49ae2206ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered.png
new file mode 100644
index 0000000000..3001638d37
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@2x.png
new file mode 100644
index 0000000000..b98907149e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@3x.png
new file mode 100644
index 0000000000..b6221277d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@4x.png
new file mode 100644
index 0000000000..49ae2206ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed.png
new file mode 100644
index 0000000000..76c7b4ed7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@2x.png
new file mode 100644
index 0000000000..d5d4cac6d1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@3x.png
new file mode 100644
index 0000000000..ca2a1ed169
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@4x.png
new file mode 100644
index 0000000000..1cb753d72f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator.png
new file mode 100644
index 0000000000..c05d4bfc05
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator@2x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator@2x.png
new file mode 100644
index 0000000000..62744d2726
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator@3x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator@3x.png
new file mode 100644
index 0000000000..fa5d241e70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/radiodelegate-indicator@4x.png b/src/quickcontrols2/imagine/images/radiodelegate-indicator@4x.png
new file mode 100644
index 0000000000..7db85e9432
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/radiodelegate-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-horizontal.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal.9.png
new file mode 100644
index 0000000000..c4e957ad1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@2x.9.png
new file mode 100644
index 0000000000..6d8391130b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@3x.9.png
new file mode 100644
index 0000000000..6b2e634c97
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@4x.9.png
new file mode 100644
index 0000000000..969c791a38
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-horizontal@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-vertical.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-vertical.9.png
new file mode 100644
index 0000000000..f76e0b21f2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-vertical.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-vertical@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@2x.9.png
new file mode 100644
index 0000000000..fecd0ab2ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-vertical@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@3x.9.png
new file mode 100644
index 0000000000..77a9c830a5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-background-vertical@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@4x.9.png
new file mode 100644
index 0000000000..f1613684c0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-background-vertical@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-disabled.png b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered.png
new file mode 100644
index 0000000000..c2958f1b3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@2x.png
new file mode 100644
index 0000000000..12a4d1f83f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@3x.png
new file mode 100644
index 0000000000..1696ac9507
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@4x.png
new file mode 100644
index 0000000000..e1d1305623
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed.png
new file mode 100644
index 0000000000..c2958f1b3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@2x.png
new file mode 100644
index 0000000000..12a4d1f83f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@3x.png
new file mode 100644
index 0000000000..1696ac9507
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@4x.png
new file mode 100644
index 0000000000..e1d1305623
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused.png
new file mode 100644
index 0000000000..bdf8239a46
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@2x.png
new file mode 100644
index 0000000000..9f887c5ea1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@3x.png
new file mode 100644
index 0000000000..8042d4c2a2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-focused@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@4x.png
new file mode 100644
index 0000000000..e7e68c47e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-hovered.png b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-pressed.png b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle.png b/src/quickcontrols2/imagine/images/rangeslider-handle.png
new file mode 100644
index 0000000000..fd72dedfb0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle@2x.png b/src/quickcontrols2/imagine/images/rangeslider-handle@2x.png
new file mode 100644
index 0000000000..57eed9f8ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle@3x.png b/src/quickcontrols2/imagine/images/rangeslider-handle@3x.png
new file mode 100644
index 0000000000..e217a6444f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-handle@4x.png b/src/quickcontrols2/imagine/images/rangeslider-handle@4x.png
new file mode 100644
index 0000000000..c212b59f55
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled.9.png
new file mode 100644
index 0000000000..7f7e6b935a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@2x.9.png
new file mode 100644
index 0000000000..cbf6fb6352
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@3x.9.png
new file mode 100644
index 0000000000..643776b8c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@4x.9.png
new file mode 100644
index 0000000000..d64acb904d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal.9.png
new file mode 100644
index 0000000000..43192f5416
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@2x.9.png
new file mode 100644
index 0000000000..ebbbbf82f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@3x.9.png
new file mode 100644
index 0000000000..0a029b53e4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@4x.9.png
new file mode 100644
index 0000000000..a13541691a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-horizontal@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled.9.png
new file mode 100644
index 0000000000..a4edafc971
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@2x.9.png
new file mode 100644
index 0000000000..8c38226e61
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@3x.9.png
new file mode 100644
index 0000000000..a939bffde8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@4x.9.png
new file mode 100644
index 0000000000..9f653770e2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical.9.png
new file mode 100644
index 0000000000..d3e877fc34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@2x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@2x.9.png
new file mode 100644
index 0000000000..7790050e64
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@3x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@3x.9.png
new file mode 100644
index 0000000000..039d198751
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@4x.9.png b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@4x.9.png
new file mode 100644
index 0000000000..b3051d1f46
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/rangeslider-progress-vertical@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused.png
new file mode 100644
index 0000000000..032a7caa65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@2x.png
new file mode 100644
index 0000000000..a2944b6ac8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@3x.png
new file mode 100644
index 0000000000..ffd4d210c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@4x.png
new file mode 100644
index 0000000000..35a41fc502
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered.png
new file mode 100644
index 0000000000..032a7caa65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@2x.png
new file mode 100644
index 0000000000..a2944b6ac8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@3x.png
new file mode 100644
index 0000000000..ffd4d210c4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@4x.png
new file mode 100644
index 0000000000..35a41fc502
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked.png
new file mode 100644
index 0000000000..d57d3894fa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked@2x.png
new file mode 100644
index 0000000000..7c37452818
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked@3x.png
new file mode 100644
index 0000000000..b0e0b9bebd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-checked@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-checked@4x.png
new file mode 100644
index 0000000000..748864efb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked.png
new file mode 100644
index 0000000000..e26fa5de81
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@2x.png
new file mode 100644
index 0000000000..bc66dde78d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@3x.png
new file mode 100644
index 0000000000..a0c5f9ad4f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@4x.png
new file mode 100644
index 0000000000..190210c8f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled.png
new file mode 100644
index 0000000000..e26fa5de81
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@2x.png
new file mode 100644
index 0000000000..bc66dde78d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@3x.png
new file mode 100644
index 0000000000..a0c5f9ad4f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-disabled@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@4x.png
new file mode 100644
index 0000000000..190210c8f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-focused.png b/src/quickcontrols2/imagine/images/roundbutton-background-focused.png
new file mode 100644
index 0000000000..832955c4e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-focused@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-focused@2x.png
new file mode 100644
index 0000000000..bb1ed2ac4b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-focused@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-focused@3x.png
new file mode 100644
index 0000000000..cbf0291321
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-focused@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-focused@4x.png
new file mode 100644
index 0000000000..1c765dee15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused.png
new file mode 100644
index 0000000000..269a9d52d5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@2x.png
new file mode 100644
index 0000000000..bd79565126
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@3x.png
new file mode 100644
index 0000000000..5ed0f662b4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@4x.png
new file mode 100644
index 0000000000..5bbb8e7afb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered.png
new file mode 100644
index 0000000000..269a9d52d5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@2x.png
new file mode 100644
index 0000000000..bd79565126
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@3x.png
new file mode 100644
index 0000000000..5ed0f662b4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@4x.png
new file mode 100644
index 0000000000..5bbb8e7afb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed.png
new file mode 100644
index 0000000000..a0fa8df033
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@2x.png
new file mode 100644
index 0000000000..3082a1d9c6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@3x.png
new file mode 100644
index 0000000000..d32e8af040
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@4x.png
new file mode 100644
index 0000000000..f4916e0bca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted.png
new file mode 100644
index 0000000000..f90e29f9cf
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@2x.png
new file mode 100644
index 0000000000..7dce11b40d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@3x.png
new file mode 100644
index 0000000000..436abbddce
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@4x.png
new file mode 100644
index 0000000000..e728d6fa1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-highlighted@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-hovered.png b/src/quickcontrols2/imagine/images/roundbutton-background-hovered.png
new file mode 100644
index 0000000000..832955c4e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-hovered@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@2x.png
new file mode 100644
index 0000000000..bb1ed2ac4b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-hovered@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@3x.png
new file mode 100644
index 0000000000..cbf0291321
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-hovered@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@4x.png
new file mode 100644
index 0000000000..1c765dee15
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-pressed.png b/src/quickcontrols2/imagine/images/roundbutton-background-pressed.png
new file mode 100644
index 0000000000..d57d3894fa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-pressed@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@2x.png
new file mode 100644
index 0000000000..7c37452818
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-pressed@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@3x.png
new file mode 100644
index 0000000000..b0e0b9bebd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background-pressed@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@4x.png
new file mode 100644
index 0000000000..748864efb3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background.png b/src/quickcontrols2/imagine/images/roundbutton-background.png
new file mode 100644
index 0000000000..d5d4cac6d1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background@2x.png b/src/quickcontrols2/imagine/images/roundbutton-background@2x.png
new file mode 100644
index 0000000000..1cb753d72f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background@3x.png b/src/quickcontrols2/imagine/images/roundbutton-background@3x.png
new file mode 100644
index 0000000000..6cc304bf42
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/roundbutton-background@4x.png b/src/quickcontrols2/imagine/images/roundbutton-background@4x.png
new file mode 100644
index 0000000000..56ea82f6de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/roundbutton-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-disabled.png b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled.png
new file mode 100644
index 0000000000..b0b95bed99
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@2x.png
new file mode 100644
index 0000000000..8ab854b0a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@3x.png
new file mode 100644
index 0000000000..f3c97231f5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@4x.png
new file mode 100644
index 0000000000..325469b8d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled.png
new file mode 100644
index 0000000000..236002fff6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@2x.png
new file mode 100644
index 0000000000..abc3d2c05c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@3x.png
new file mode 100644
index 0000000000..e215cf5b7a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@4x.png
new file mode 100644
index 0000000000..c6ec0520bd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered.png
new file mode 100644
index 0000000000..19b48f1d49
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@2x.png
new file mode 100644
index 0000000000..8f5abb8494
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@3x.png
new file mode 100644
index 0000000000..73963d754c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@4x.png
new file mode 100644
index 0000000000..04d6131ec9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed.png
new file mode 100644
index 0000000000..f48f514df2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@2x.png
new file mode 100644
index 0000000000..e31820add9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@3x.png
new file mode 100644
index 0000000000..278ba90007
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@4x.png
new file mode 100644
index 0000000000..01e4e5c85b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive.png
new file mode 100644
index 0000000000..fd7832a6aa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@2x.png
new file mode 100644
index 0000000000..bd63a1b1e8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@3x.png
new file mode 100644
index 0000000000..3145295446
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@4x.png
new file mode 100644
index 0000000000..6db4d81da9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle-interactive@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle.png b/src/quickcontrols2/imagine/images/scrollbar-handle.png
new file mode 100644
index 0000000000..255f6c4d60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle@2x.png b/src/quickcontrols2/imagine/images/scrollbar-handle@2x.png
new file mode 100644
index 0000000000..2b69cef6a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle@3x.png b/src/quickcontrols2/imagine/images/scrollbar-handle@3x.png
new file mode 100644
index 0000000000..6fdfa487d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollbar-handle@4x.png b/src/quickcontrols2/imagine/images/scrollbar-handle@4x.png
new file mode 100644
index 0000000000..cc3205f125
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollbar-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollindicator-handle.png b/src/quickcontrols2/imagine/images/scrollindicator-handle.png
new file mode 100644
index 0000000000..255f6c4d60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollindicator-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollindicator-handle@2x.png b/src/quickcontrols2/imagine/images/scrollindicator-handle@2x.png
new file mode 100644
index 0000000000..2b69cef6a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollindicator-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollindicator-handle@3x.png b/src/quickcontrols2/imagine/images/scrollindicator-handle@3x.png
new file mode 100644
index 0000000000..6fdfa487d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollindicator-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/scrollindicator-handle@4x.png b/src/quickcontrols2/imagine/images/scrollindicator-handle@4x.png
new file mode 100644
index 0000000000..cc3205f125
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/scrollindicator-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-horizontal.9.png b/src/quickcontrols2/imagine/images/slider-background-horizontal.9.png
new file mode 100644
index 0000000000..c4e957ad1b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-horizontal.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-horizontal@2x.9.png b/src/quickcontrols2/imagine/images/slider-background-horizontal@2x.9.png
new file mode 100644
index 0000000000..6d8391130b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-horizontal@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-horizontal@3x.9.png b/src/quickcontrols2/imagine/images/slider-background-horizontal@3x.9.png
new file mode 100644
index 0000000000..6b2e634c97
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-horizontal@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-horizontal@4x.9.png b/src/quickcontrols2/imagine/images/slider-background-horizontal@4x.9.png
new file mode 100644
index 0000000000..969c791a38
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-horizontal@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-vertical.9.png b/src/quickcontrols2/imagine/images/slider-background-vertical.9.png
new file mode 100644
index 0000000000..f76e0b21f2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-vertical.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-vertical@2x.9.png b/src/quickcontrols2/imagine/images/slider-background-vertical@2x.9.png
new file mode 100644
index 0000000000..fecd0ab2ba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-vertical@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-vertical@3x.9.png b/src/quickcontrols2/imagine/images/slider-background-vertical@3x.9.png
new file mode 100644
index 0000000000..77a9c830a5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-vertical@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-background-vertical@4x.9.png b/src/quickcontrols2/imagine/images/slider-background-vertical@4x.9.png
new file mode 100644
index 0000000000..f1613684c0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-background-vertical@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-disabled.png b/src/quickcontrols2/imagine/images/slider-handle-disabled.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/slider-handle-disabled@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/slider-handle-disabled@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/slider-handle-disabled@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-hovered.png b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered.png
new file mode 100644
index 0000000000..c2958f1b3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@2x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@2x.png
new file mode 100644
index 0000000000..12a4d1f83f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@3x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@3x.png
new file mode 100644
index 0000000000..1696ac9507
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@4x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@4x.png
new file mode 100644
index 0000000000..e1d1305623
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-pressed.png b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed.png
new file mode 100644
index 0000000000..c2958f1b3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@2x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@2x.png
new file mode 100644
index 0000000000..12a4d1f83f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@3x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@3x.png
new file mode 100644
index 0000000000..1696ac9507
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@4x.png b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@4x.png
new file mode 100644
index 0000000000..e1d1305623
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused.png b/src/quickcontrols2/imagine/images/slider-handle-focused.png
new file mode 100644
index 0000000000..bdf8239a46
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused@2x.png b/src/quickcontrols2/imagine/images/slider-handle-focused@2x.png
new file mode 100644
index 0000000000..9f887c5ea1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused@3x.png b/src/quickcontrols2/imagine/images/slider-handle-focused@3x.png
new file mode 100644
index 0000000000..8042d4c2a2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-focused@4x.png b/src/quickcontrols2/imagine/images/slider-handle-focused@4x.png
new file mode 100644
index 0000000000..e7e68c47e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-hovered.png b/src/quickcontrols2/imagine/images/slider-handle-hovered.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-hovered@2x.png b/src/quickcontrols2/imagine/images/slider-handle-hovered@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-hovered@3x.png b/src/quickcontrols2/imagine/images/slider-handle-hovered@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-hovered@4x.png b/src/quickcontrols2/imagine/images/slider-handle-hovered@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-pressed.png b/src/quickcontrols2/imagine/images/slider-handle-pressed.png
new file mode 100644
index 0000000000..4934fb77c5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/slider-handle-pressed@2x.png
new file mode 100644
index 0000000000..451b719e60
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/slider-handle-pressed@3x.png
new file mode 100644
index 0000000000..1daffca729
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/slider-handle-pressed@4x.png
new file mode 100644
index 0000000000..6483070710
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle.png b/src/quickcontrols2/imagine/images/slider-handle.png
new file mode 100644
index 0000000000..fd72dedfb0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle@2x.png b/src/quickcontrols2/imagine/images/slider-handle@2x.png
new file mode 100644
index 0000000000..57eed9f8ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle@3x.png b/src/quickcontrols2/imagine/images/slider-handle@3x.png
new file mode 100644
index 0000000000..e217a6444f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-handle@4x.png b/src/quickcontrols2/imagine/images/slider-handle@4x.png
new file mode 100644
index 0000000000..c212b59f55
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled.9.png
new file mode 100644
index 0000000000..7f7e6b935a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@2x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@2x.9.png
new file mode 100644
index 0000000000..cbf6fb6352
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@3x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@3x.9.png
new file mode 100644
index 0000000000..643776b8c9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@4x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@4x.9.png
new file mode 100644
index 0000000000..d64acb904d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal.9.png
new file mode 100644
index 0000000000..43192f5416
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal@2x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal@2x.9.png
new file mode 100644
index 0000000000..ebbbbf82f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal@3x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal@3x.9.png
new file mode 100644
index 0000000000..0a029b53e4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-horizontal@4x.9.png b/src/quickcontrols2/imagine/images/slider-progress-horizontal@4x.9.png
new file mode 100644
index 0000000000..a13541691a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-horizontal@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled.9.png
new file mode 100644
index 0000000000..a4edafc971
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@2x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@2x.9.png
new file mode 100644
index 0000000000..8c38226e61
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@3x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@3x.9.png
new file mode 100644
index 0000000000..a939bffde8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@4x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@4x.9.png
new file mode 100644
index 0000000000..9f653770e2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical.9.png
new file mode 100644
index 0000000000..d3e877fc34
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical@2x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical@2x.9.png
new file mode 100644
index 0000000000..7790050e64
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical@3x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical@3x.9.png
new file mode 100644
index 0000000000..039d198751
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/slider-progress-vertical@4x.9.png b/src/quickcontrols2/imagine/images/slider-progress-vertical@4x.9.png
new file mode 100644
index 0000000000..b3051d1f46
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/slider-progress-vertical@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-disabled.9.png b/src/quickcontrols2/imagine/images/spinbox-background-disabled.9.png
new file mode 100644
index 0000000000..7baaeec525
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-disabled@2x.9.png
new file mode 100644
index 0000000000..e0d5907034
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-disabled@3x.9.png
new file mode 100644
index 0000000000..24b3054ded
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-disabled@4x.9.png
new file mode 100644
index 0000000000..8ac4740a7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-editable.9.png b/src/quickcontrols2/imagine/images/spinbox-background-editable.9.png
new file mode 100644
index 0000000000..995c827659
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-editable.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-editable@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-editable@2x.9.png
new file mode 100644
index 0000000000..42c9dd6ba2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-editable@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-editable@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-editable@3x.9.png
new file mode 100644
index 0000000000..4ee974a144
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-editable@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-editable@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-editable@4x.9.png
new file mode 100644
index 0000000000..59b0091539
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-editable@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-background-focused.9.png
new file mode 100644
index 0000000000..27751eacc8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-focused@2x.9.png
new file mode 100644
index 0000000000..1692578f6c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-focused@3x.9.png
new file mode 100644
index 0000000000..4c44c1bbbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-background-focused@4x.9.png
new file mode 100644
index 0000000000..f8632bf2f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background.9.png b/src/quickcontrols2/imagine/images/spinbox-background.9.png
new file mode 100644
index 0000000000..ae8b043beb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-background@2x.9.png
new file mode 100644
index 0000000000..eaae097e2f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-background@3x.9.png
new file mode 100644
index 0000000000..d8add8117c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-background@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-background@4x.9.png
new file mode 100644
index 0000000000..d954febfc2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled.9.png
new file mode 100644
index 0000000000..b3953398d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@2x.9.png
new file mode 100644
index 0000000000..18e2ca65d4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@3x.9.png
new file mode 100644
index 0000000000..ed6674b47b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@4x.9.png
new file mode 100644
index 0000000000..0da2cf93ff
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused.9.png
new file mode 100644
index 0000000000..46220a8ebe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@2x.9.png
new file mode 100644
index 0000000000..b8ebb7b7eb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@3x.9.png
new file mode 100644
index 0000000000..10561d8dbb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@4x.9.png
new file mode 100644
index 0000000000..ccd09d69a5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered.9.png
new file mode 100644
index 0000000000..46220a8ebe
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@2x.9.png
new file mode 100644
index 0000000000..b8ebb7b7eb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@3x.9.png
new file mode 100644
index 0000000000..10561d8dbb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@4x.9.png
new file mode 100644
index 0000000000..ccd09d69a5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused.9.png
new file mode 100644
index 0000000000..23842de4e6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@2x.9.png
new file mode 100644
index 0000000000..e50789323a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@3x.9.png
new file mode 100644
index 0000000000..7edec0c9b3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@4x.9.png
new file mode 100644
index 0000000000..f6e5ff8201
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered.9.png
new file mode 100644
index 0000000000..23842de4e6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@2x.9.png
new file mode 100644
index 0000000000..e50789323a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@3x.9.png
new file mode 100644
index 0000000000..7edec0c9b3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@4x.9.png
new file mode 100644
index 0000000000..f6e5ff8201
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed.9.png
new file mode 100644
index 0000000000..b6917a036b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@2x.9.png
new file mode 100644
index 0000000000..8999d3e441
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@3x.9.png
new file mode 100644
index 0000000000..77aa004465
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@4x.9.png
new file mode 100644
index 0000000000..4f2fd261ab
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored.9.png
new file mode 100644
index 0000000000..3c3da5b1a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@2x.9.png
new file mode 100644
index 0000000000..e0760e07cd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@3x.9.png
new file mode 100644
index 0000000000..c37080f5b8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@4x.9.png
new file mode 100644
index 0000000000..bdc248231a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-mirrored@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed.9.png
new file mode 100644
index 0000000000..65f2821bcd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@2x.9.png
new file mode 100644
index 0000000000..010dd9d0bb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@3x.9.png
new file mode 100644
index 0000000000..f647f489d2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@4x.9.png
new file mode 100644
index 0000000000..db0486d1fc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable.9.png
new file mode 100644
index 0000000000..c3207f311b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@2x.9.png
new file mode 100644
index 0000000000..c8c2630e83
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@3x.9.png
new file mode 100644
index 0000000000..d0a6c81816
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@4x.9.png
new file mode 100644
index 0000000000..40e897623b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-editable@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused.9.png
new file mode 100644
index 0000000000..6ad31bb0e2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@2x.9.png
new file mode 100644
index 0000000000..6cc60b4b54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@3x.9.png
new file mode 100644
index 0000000000..722c7ec708
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@4x.9.png
new file mode 100644
index 0000000000..64fa4ab6c0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered.9.png
new file mode 100644
index 0000000000..6ad31bb0e2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@2x.9.png
new file mode 100644
index 0000000000..6cc60b4b54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@3x.9.png
new file mode 100644
index 0000000000..722c7ec708
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@4x.9.png
new file mode 100644
index 0000000000..64fa4ab6c0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled.9.png
new file mode 100644
index 0000000000..ac7da20e65
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@2x.9.png
new file mode 100644
index 0000000000..a12f361535
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@3x.9.png
new file mode 100644
index 0000000000..de11317bc1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@4x.9.png
new file mode 100644
index 0000000000..8be41f3898
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused.9.png
new file mode 100644
index 0000000000..6b6e526436
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@2x.9.png
new file mode 100644
index 0000000000..e0c36da35d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@3x.9.png
new file mode 100644
index 0000000000..ca2389dac4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@4x.9.png
new file mode 100644
index 0000000000..7e6c547419
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered.9.png
new file mode 100644
index 0000000000..6b6e526436
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@2x.9.png
new file mode 100644
index 0000000000..e0c36da35d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@3x.9.png
new file mode 100644
index 0000000000..ca2389dac4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@4x.9.png
new file mode 100644
index 0000000000..7e6c547419
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed.9.png
new file mode 100644
index 0000000000..d756679feb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@2x.9.png
new file mode 100644
index 0000000000..e49c7e8985
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@3x.9.png
new file mode 100644
index 0000000000..6041ffdcc0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@4x.9.png
new file mode 100644
index 0000000000..e23dda155e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored.9.png
new file mode 100644
index 0000000000..58be212032
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@2x.9.png
new file mode 100644
index 0000000000..709a1ab6c6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@3x.9.png
new file mode 100644
index 0000000000..ee5b5b8225
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@4x.9.png
new file mode 100644
index 0000000000..1e88d44dba
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-mirrored@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed.9.png
new file mode 100644
index 0000000000..9703314b47
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@2x.9.png
new file mode 100644
index 0000000000..173eccfbe3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@3x.9.png
new file mode 100644
index 0000000000..77737c7593
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@4x.9.png
new file mode 100644
index 0000000000..6a2bb865cb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down.9.png
new file mode 100644
index 0000000000..a6c9679a43
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down@2x.9.png
new file mode 100644
index 0000000000..bd14cdbbfc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down@3x.9.png
new file mode 100644
index 0000000000..02d18c1d8e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-down@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-down@4x.9.png
new file mode 100644
index 0000000000..9ec1bf0459
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-down@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled.9.png
new file mode 100644
index 0000000000..5fe5ab6ad5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@2x.9.png
new file mode 100644
index 0000000000..f7a2a5d56d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@3x.9.png
new file mode 100644
index 0000000000..3244c93f14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@4x.9.png
new file mode 100644
index 0000000000..8248200559
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused.9.png
new file mode 100644
index 0000000000..d291c50a76
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@2x.9.png
new file mode 100644
index 0000000000..06e27b1b8e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@3x.9.png
new file mode 100644
index 0000000000..34b4373558
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@4x.9.png
new file mode 100644
index 0000000000..4a95cca469
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered.9.png
new file mode 100644
index 0000000000..d291c50a76
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@2x.9.png
new file mode 100644
index 0000000000..06e27b1b8e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@3x.9.png
new file mode 100644
index 0000000000..34b4373558
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@4x.9.png
new file mode 100644
index 0000000000..4a95cca469
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused.9.png
new file mode 100644
index 0000000000..a98d5a1d42
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@2x.9.png
new file mode 100644
index 0000000000..4b8458600a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@3x.9.png
new file mode 100644
index 0000000000..da241c07ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@4x.9.png
new file mode 100644
index 0000000000..d1333671ff
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered.9.png
new file mode 100644
index 0000000000..a98d5a1d42
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@2x.9.png
new file mode 100644
index 0000000000..4b8458600a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@3x.9.png
new file mode 100644
index 0000000000..da241c07ae
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@4x.9.png
new file mode 100644
index 0000000000..d1333671ff
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed.9.png
new file mode 100644
index 0000000000..793e009d82
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@2x.9.png
new file mode 100644
index 0000000000..aca00c57c0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@3x.9.png
new file mode 100644
index 0000000000..a49b95498c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@4x.9.png
new file mode 100644
index 0000000000..e0814f3be3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored.9.png
new file mode 100644
index 0000000000..ac4c46d184
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@2x.9.png
new file mode 100644
index 0000000000..b1c335ee53
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@3x.9.png
new file mode 100644
index 0000000000..3f0d9f2f25
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@4x.9.png
new file mode 100644
index 0000000000..cac6eca867
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-mirrored@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed.9.png
new file mode 100644
index 0000000000..87a1ae7a9a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@2x.9.png
new file mode 100644
index 0000000000..95c5ea063d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@3x.9.png
new file mode 100644
index 0000000000..3ed6cddfb8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@4x.9.png
new file mode 100644
index 0000000000..8f5e3f02bd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable.9.png
new file mode 100644
index 0000000000..b3cc7bea02
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@2x.9.png
new file mode 100644
index 0000000000..51313f5953
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@3x.9.png
new file mode 100644
index 0000000000..8db540f593
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@4x.9.png
new file mode 100644
index 0000000000..310400a2b5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-editable@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused.9.png
new file mode 100644
index 0000000000..d88bd00d22
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@2x.9.png
new file mode 100644
index 0000000000..77dbb52a6a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@3x.9.png
new file mode 100644
index 0000000000..0739b1b173
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@4x.9.png
new file mode 100644
index 0000000000..d53ee543e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered.9.png
new file mode 100644
index 0000000000..d88bd00d22
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@2x.9.png
new file mode 100644
index 0000000000..77dbb52a6a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@3x.9.png
new file mode 100644
index 0000000000..0739b1b173
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@4x.9.png
new file mode 100644
index 0000000000..d53ee543e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled.9.png
new file mode 100644
index 0000000000..53f6d7e59c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@2x.9.png
new file mode 100644
index 0000000000..7c7bb214af
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@3x.9.png
new file mode 100644
index 0000000000..5a69027cf3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@4x.9.png
new file mode 100644
index 0000000000..fe2171a546
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused.9.png
new file mode 100644
index 0000000000..cf31f93668
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@2x.9.png
new file mode 100644
index 0000000000..48b8861eac
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@3x.9.png
new file mode 100644
index 0000000000..d6a417202b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@4x.9.png
new file mode 100644
index 0000000000..e0c7e374ad
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered.9.png
new file mode 100644
index 0000000000..cf31f93668
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@2x.9.png
new file mode 100644
index 0000000000..48b8861eac
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@3x.9.png
new file mode 100644
index 0000000000..d6a417202b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@4x.9.png
new file mode 100644
index 0000000000..e0c7e374ad
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed.9.png
new file mode 100644
index 0000000000..4548cddd91
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@2x.9.png
new file mode 100644
index 0000000000..c5fb9d1b3d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@3x.9.png
new file mode 100644
index 0000000000..ffbe520a19
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@4x.9.png
new file mode 100644
index 0000000000..784f9bee96
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored.9.png
new file mode 100644
index 0000000000..f26794570d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@2x.9.png
new file mode 100644
index 0000000000..7f07e625ad
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@3x.9.png
new file mode 100644
index 0000000000..0b060816ec
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@4x.9.png
new file mode 100644
index 0000000000..df76dfcec1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-mirrored@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed.9.png
new file mode 100644
index 0000000000..cbba897fc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@2x.9.png
new file mode 100644
index 0000000000..a49e11fa4e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@3x.9.png
new file mode 100644
index 0000000000..720e454326
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@4x.9.png
new file mode 100644
index 0000000000..46333e3df8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up.9.png
new file mode 100644
index 0000000000..67cbe4345b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up@2x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up@2x.9.png
new file mode 100644
index 0000000000..8e804b8735
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up@3x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up@3x.9.png
new file mode 100644
index 0000000000..15baec74c8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/spinbox-indicator-up@4x.9.png b/src/quickcontrols2/imagine/images/spinbox-indicator-up@4x.9.png
new file mode 100644
index 0000000000..7112de67e3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/spinbox-indicator-up@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-disabled.png b/src/quickcontrols2/imagine/images/splitview-handle-disabled.png
new file mode 100644
index 0000000000..8ab854b0a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/splitview-handle-disabled@2x.png
new file mode 100644
index 0000000000..325469b8d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/splitview-handle-disabled@3x.png
new file mode 100644
index 0000000000..5357e84783
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/splitview-handle-disabled@4x.png
new file mode 100644
index 0000000000..e215cf5b7a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-hovered.png b/src/quickcontrols2/imagine/images/splitview-handle-hovered.png
new file mode 100644
index 0000000000..429d55081f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-hovered@2x.png b/src/quickcontrols2/imagine/images/splitview-handle-hovered@2x.png
new file mode 100644
index 0000000000..6f17b06ef3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-hovered@3x.png b/src/quickcontrols2/imagine/images/splitview-handle-hovered@3x.png
new file mode 100644
index 0000000000..11dcfa261c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-hovered@4x.png b/src/quickcontrols2/imagine/images/splitview-handle-hovered@4x.png
new file mode 100644
index 0000000000..73963d754c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-pressed.png b/src/quickcontrols2/imagine/images/splitview-handle-pressed.png
new file mode 100644
index 0000000000..6e00db20e6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/splitview-handle-pressed@2x.png
new file mode 100644
index 0000000000..e1392de62b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/splitview-handle-pressed@3x.png
new file mode 100644
index 0000000000..ff6a397f69
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/splitview-handle-pressed@4x.png
new file mode 100644
index 0000000000..278ba90007
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle.png b/src/quickcontrols2/imagine/images/splitview-handle.png
new file mode 100644
index 0000000000..2b69cef6a3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle@2x.png b/src/quickcontrols2/imagine/images/splitview-handle@2x.png
new file mode 100644
index 0000000000..cc3205f125
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle@3x.png b/src/quickcontrols2/imagine/images/splitview-handle@3x.png
new file mode 100644
index 0000000000..b8be2b4d8f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/splitview-handle@4x.png b/src/quickcontrols2/imagine/images/splitview-handle@4x.png
new file mode 100644
index 0000000000..3145295446
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/splitview-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-disabled.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled.9.png
new file mode 100644
index 0000000000..23570729d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-focused.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-focused.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted.9.png
new file mode 100644
index 0000000000..e79d8e1d01
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..ea68d35fc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..6d61041599
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..590cca96a1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-hovered.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-pressed.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background@2x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background@3x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/swipedelegate-background@4x.9.png b/src/quickcontrols2/imagine/images/swipedelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/swipedelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-disabled.png b/src/quickcontrols2/imagine/images/switch-handle-disabled.png
new file mode 100644
index 0000000000..595dd5465d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/switch-handle-disabled@2x.png
new file mode 100644
index 0000000000..5be736aafa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/switch-handle-disabled@3x.png
new file mode 100644
index 0000000000..c8002ca3d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/switch-handle-disabled@4x.png
new file mode 100644
index 0000000000..00e70c1ba5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-pressed.png b/src/quickcontrols2/imagine/images/switch-handle-pressed.png
new file mode 100644
index 0000000000..595dd5465d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/switch-handle-pressed@2x.png
new file mode 100644
index 0000000000..5be736aafa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/switch-handle-pressed@3x.png
new file mode 100644
index 0000000000..c8002ca3d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/switch-handle-pressed@4x.png
new file mode 100644
index 0000000000..00e70c1ba5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle.png b/src/quickcontrols2/imagine/images/switch-handle.png
new file mode 100644
index 0000000000..15649c34c7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle@2x.png b/src/quickcontrols2/imagine/images/switch-handle@2x.png
new file mode 100644
index 0000000000..04f84ed920
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle@3x.png b/src/quickcontrols2/imagine/images/switch-handle@3x.png
new file mode 100644
index 0000000000..e0cfb63718
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-handle@4x.png b/src/quickcontrols2/imagine/images/switch-handle@4x.png
new file mode 100644
index 0000000000..73fa381a4a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused.png
new file mode 100644
index 0000000000..7f5ba5dfc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..a0090df49f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..0c7e526459
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..3a5e1d36ca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered.png
new file mode 100644
index 0000000000..7f5ba5dfc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..a0090df49f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..0c7e526459
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..3a5e1d36ca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed.png
new file mode 100644
index 0000000000..ecbc552a17
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..07fe7241d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..8c65c27f4e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..f6a1e47658
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked.png b/src/quickcontrols2/imagine/images/switch-indicator-checked.png
new file mode 100644
index 0000000000..2b7265cd0f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked@2x.png
new file mode 100644
index 0000000000..6ec88c7fc8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked@3x.png
new file mode 100644
index 0000000000..48c979856a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-checked@4x.png
new file mode 100644
index 0000000000..e9f81807da
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-disabled.png b/src/quickcontrols2/imagine/images/switch-indicator-disabled.png
new file mode 100644
index 0000000000..9cfab79197
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-disabled@2x.png
new file mode 100644
index 0000000000..3bbbb8dfbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-disabled@3x.png
new file mode 100644
index 0000000000..80d9a74685
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-disabled@4x.png
new file mode 100644
index 0000000000..9ee7bfabbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-focused.png b/src/quickcontrols2/imagine/images/switch-indicator-focused.png
new file mode 100644
index 0000000000..4867bcac54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-focused@2x.png
new file mode 100644
index 0000000000..d833a0cdb4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-focused@3x.png
new file mode 100644
index 0000000000..a632b6ae1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-focused@4x.png
new file mode 100644
index 0000000000..b5affab772
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-hovered.png b/src/quickcontrols2/imagine/images/switch-indicator-hovered.png
new file mode 100644
index 0000000000..4867bcac54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-hovered@2x.png
new file mode 100644
index 0000000000..d833a0cdb4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-hovered@3x.png
new file mode 100644
index 0000000000..a632b6ae1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-hovered@4x.png
new file mode 100644
index 0000000000..b5affab772
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-pressed.png b/src/quickcontrols2/imagine/images/switch-indicator-pressed.png
new file mode 100644
index 0000000000..4fbbc060e8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/switch-indicator-pressed@2x.png
new file mode 100644
index 0000000000..7939f943e5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/switch-indicator-pressed@3x.png
new file mode 100644
index 0000000000..adcbe45bb7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/switch-indicator-pressed@4x.png
new file mode 100644
index 0000000000..74c0c77e6f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator.png b/src/quickcontrols2/imagine/images/switch-indicator.png
new file mode 100644
index 0000000000..b6b4f1cd79
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator@2x.png b/src/quickcontrols2/imagine/images/switch-indicator@2x.png
new file mode 100644
index 0000000000..bfeedeb720
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator@3x.png b/src/quickcontrols2/imagine/images/switch-indicator@3x.png
new file mode 100644
index 0000000000..19e5ba2ca7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switch-indicator@4x.png b/src/quickcontrols2/imagine/images/switch-indicator@4x.png
new file mode 100644
index 0000000000..9345cd4fdb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switch-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-disabled.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled.9.png
new file mode 100644
index 0000000000..23570729d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-focused.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-focused.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-hovered.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-pressed.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed.9.png
new file mode 100644
index 0000000000..6ae574d55a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background.9.png
new file mode 100644
index 0000000000..b8749743d0
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background@2x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background@3x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-background@4x.9.png b/src/quickcontrols2/imagine/images/switchdelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled.png
new file mode 100644
index 0000000000..595dd5465d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@2x.png
new file mode 100644
index 0000000000..5be736aafa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@3x.png
new file mode 100644
index 0000000000..c8002ca3d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@4x.png
new file mode 100644
index 0000000000..00e70c1ba5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed.png
new file mode 100644
index 0000000000..595dd5465d
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@2x.png
new file mode 100644
index 0000000000..5be736aafa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@3x.png
new file mode 100644
index 0000000000..c8002ca3d9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@4x.png
new file mode 100644
index 0000000000..00e70c1ba5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle.png b/src/quickcontrols2/imagine/images/switchdelegate-handle.png
new file mode 100644
index 0000000000..15649c34c7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle@2x.png
new file mode 100644
index 0000000000..04f84ed920
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle@3x.png
new file mode 100644
index 0000000000..e0cfb63718
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-handle@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-handle@4x.png
new file mode 100644
index 0000000000..73fa381a4a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-handle@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused.png
new file mode 100644
index 0000000000..7f5ba5dfc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@2x.png
new file mode 100644
index 0000000000..a0090df49f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@3x.png
new file mode 100644
index 0000000000..0c7e526459
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@4x.png
new file mode 100644
index 0000000000..3a5e1d36ca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered.png
new file mode 100644
index 0000000000..7f5ba5dfc4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@2x.png
new file mode 100644
index 0000000000..a0090df49f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@3x.png
new file mode 100644
index 0000000000..0c7e526459
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@4x.png
new file mode 100644
index 0000000000..3a5e1d36ca
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed.png
new file mode 100644
index 0000000000..ecbc552a17
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@2x.png
new file mode 100644
index 0000000000..07fe7241d8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@3x.png
new file mode 100644
index 0000000000..8c65c27f4e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@4x.png
new file mode 100644
index 0000000000..f6a1e47658
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked.png
new file mode 100644
index 0000000000..2b7265cd0f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@2x.png
new file mode 100644
index 0000000000..6ec88c7fc8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@3x.png
new file mode 100644
index 0000000000..48c979856a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@4x.png
new file mode 100644
index 0000000000..e9f81807da
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-checked@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled.png
new file mode 100644
index 0000000000..9cfab79197
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@2x.png
new file mode 100644
index 0000000000..3bbbb8dfbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@3x.png
new file mode 100644
index 0000000000..80d9a74685
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@4x.png
new file mode 100644
index 0000000000..9ee7bfabbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-disabled@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused.png
new file mode 100644
index 0000000000..4867bcac54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@2x.png
new file mode 100644
index 0000000000..d833a0cdb4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@3x.png
new file mode 100644
index 0000000000..a632b6ae1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@4x.png
new file mode 100644
index 0000000000..b5affab772
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-focused@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered.png
new file mode 100644
index 0000000000..4867bcac54
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@2x.png
new file mode 100644
index 0000000000..d833a0cdb4
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@3x.png
new file mode 100644
index 0000000000..a632b6ae1c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@4x.png
new file mode 100644
index 0000000000..b5affab772
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-hovered@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed.png
new file mode 100644
index 0000000000..4fbbc060e8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@2x.png
new file mode 100644
index 0000000000..7939f943e5
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@3x.png
new file mode 100644
index 0000000000..adcbe45bb7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@4x.png
new file mode 100644
index 0000000000..74c0c77e6f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator-pressed@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator.png
new file mode 100644
index 0000000000..b6b4f1cd79
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator@2x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator@2x.png
new file mode 100644
index 0000000000..bfeedeb720
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator@3x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator@3x.png
new file mode 100644
index 0000000000..19e5ba2ca7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/switchdelegate-indicator@4x.png b/src/quickcontrols2/imagine/images/switchdelegate-indicator@4x.png
new file mode 100644
index 0000000000..9345cd4fdb
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/switchdelegate-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbar-background.png b/src/quickcontrols2/imagine/images/tabbar-background.png
new file mode 100644
index 0000000000..002efdedde
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbar-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbar-background@2x.png b/src/quickcontrols2/imagine/images/tabbar-background@2x.png
new file mode 100644
index 0000000000..aaa1cbaf4b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbar-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbar-background@3x.png b/src/quickcontrols2/imagine/images/tabbar-background@3x.png
new file mode 100644
index 0000000000..c4eb9e1f02
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbar-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbar-background@4x.png b/src/quickcontrols2/imagine/images/tabbar-background@4x.png
new file mode 100644
index 0000000000..4a4e234a6a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbar-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-checked.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-checked.9.png
new file mode 100644
index 0000000000..d2f0fa76a6
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-checked@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-checked@2x.9.png
new file mode 100644
index 0000000000..bee1329202
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-checked@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-checked@3x.9.png
new file mode 100644
index 0000000000..70afb7d337
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-checked@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-checked@4x.9.png
new file mode 100644
index 0000000000..3a2015c464
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked.9.png
new file mode 100644
index 0000000000..a6d3011bd9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@2x.9.png
new file mode 100644
index 0000000000..8ebfa02686
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@3x.9.png
new file mode 100644
index 0000000000..1d5a1d5149
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@4x.9.png
new file mode 100644
index 0000000000..f06dc55f9b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled.9.png
new file mode 100644
index 0000000000..a6d3011bd9
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@2x.9.png
new file mode 100644
index 0000000000..8ebfa02686
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@3x.9.png
new file mode 100644
index 0000000000..1d5a1d5149
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f06dc55f9b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-hovered.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-hovered.9.png
new file mode 100644
index 0000000000..3f945184f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@2x.9.png
new file mode 100644
index 0000000000..8a19720a2a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@3x.9.png
new file mode 100644
index 0000000000..eadcf45714
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@4x.9.png
new file mode 100644
index 0000000000..8bf8e992aa
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-pressed.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-pressed.9.png
new file mode 100644
index 0000000000..d48733ed81
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@2x.9.png
new file mode 100644
index 0000000000..fbbaad7bec
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@3x.9.png
new file mode 100644
index 0000000000..3a0ba70e63
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@4x.9.png
new file mode 100644
index 0000000000..c04f124e5e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background.9.png b/src/quickcontrols2/imagine/images/tabbutton-background.9.png
new file mode 100644
index 0000000000..2266c72223
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background@2x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background@2x.9.png
new file mode 100644
index 0000000000..b7adb7adc3
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background@3x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background@3x.9.png
new file mode 100644
index 0000000000..d8f4eae55f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tabbutton-background@4x.9.png b/src/quickcontrols2/imagine/images/tabbutton-background@4x.9.png
new file mode 100644
index 0000000000..066d35b38c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tabbutton-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-disabled.9.png b/src/quickcontrols2/imagine/images/textarea-background-disabled.9.png
new file mode 100644
index 0000000000..97d48f8c00
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/textarea-background-disabled@2x.9.png
new file mode 100644
index 0000000000..f9ea1d49dd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/textarea-background-disabled@3x.9.png
new file mode 100644
index 0000000000..04e7ef6f07
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/textarea-background-disabled@4x.9.png
new file mode 100644
index 0000000000..feaaa3bcbc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-focused.9.png b/src/quickcontrols2/imagine/images/textarea-background-focused.9.png
new file mode 100644
index 0000000000..1d73acfa0a
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/textarea-background-focused@2x.9.png
new file mode 100644
index 0000000000..5be4cd6f8c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/textarea-background-focused@3x.9.png
new file mode 100644
index 0000000000..6ba3e24610
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/textarea-background-focused@4x.9.png
new file mode 100644
index 0000000000..366aa5112f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background.9.png b/src/quickcontrols2/imagine/images/textarea-background.9.png
new file mode 100644
index 0000000000..0b9ca9f3ec
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background@2x.9.png b/src/quickcontrols2/imagine/images/textarea-background@2x.9.png
new file mode 100644
index 0000000000..a806ed1b11
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background@3x.9.png b/src/quickcontrols2/imagine/images/textarea-background@3x.9.png
new file mode 100644
index 0000000000..547ef33c41
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textarea-background@4x.9.png b/src/quickcontrols2/imagine/images/textarea-background@4x.9.png
new file mode 100644
index 0000000000..b759b1e80b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textarea-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-disabled.9.png b/src/quickcontrols2/imagine/images/textfield-background-disabled.9.png
new file mode 100644
index 0000000000..312a1294d1
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-disabled.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-disabled@2x.9.png b/src/quickcontrols2/imagine/images/textfield-background-disabled@2x.9.png
new file mode 100644
index 0000000000..2c6c7e9165
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-disabled@3x.9.png b/src/quickcontrols2/imagine/images/textfield-background-disabled@3x.9.png
new file mode 100644
index 0000000000..1d1aca7177
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-disabled@4x.9.png b/src/quickcontrols2/imagine/images/textfield-background-disabled@4x.9.png
new file mode 100644
index 0000000000..ed93182a70
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-focused.9.png b/src/quickcontrols2/imagine/images/textfield-background-focused.9.png
new file mode 100644
index 0000000000..1251f4e4cc
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/textfield-background-focused@2x.9.png
new file mode 100644
index 0000000000..d535e8bc98
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/textfield-background-focused@3x.9.png
new file mode 100644
index 0000000000..9fca3bb239
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/textfield-background-focused@4x.9.png
new file mode 100644
index 0000000000..a275a52e89
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background.9.png b/src/quickcontrols2/imagine/images/textfield-background.9.png
new file mode 100644
index 0000000000..7ea6096880
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background@2x.9.png b/src/quickcontrols2/imagine/images/textfield-background@2x.9.png
new file mode 100644
index 0000000000..0a4c3f2a9f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background@3x.9.png b/src/quickcontrols2/imagine/images/textfield-background@3x.9.png
new file mode 100644
index 0000000000..e855274187
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/textfield-background@4x.9.png b/src/quickcontrols2/imagine/images/textfield-background@4x.9.png
new file mode 100644
index 0000000000..29ef5bb9d2
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/textfield-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbar-background.png b/src/quickcontrols2/imagine/images/toolbar-background.png
new file mode 100644
index 0000000000..9c67cf2702
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbar-background.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbar-background@2x.png b/src/quickcontrols2/imagine/images/toolbar-background@2x.png
new file mode 100644
index 0000000000..b0602519a7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbar-background@2x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbar-background@3x.png b/src/quickcontrols2/imagine/images/toolbar-background@3x.png
new file mode 100644
index 0000000000..7f227ca343
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbar-background@3x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbar-background@4x.png b/src/quickcontrols2/imagine/images/toolbar-background@4x.png
new file mode 100644
index 0000000000..4788ecc743
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbar-background@4x.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-checked@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-checked@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-disabled-checked@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-focused.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-focused.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-focused.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-focused@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-focused@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-focused@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-focused@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-focused@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-focused@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-hovered.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-hovered.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-hovered.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-hovered@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-hovered@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-hovered@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-hovered@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-pressed.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-pressed.9.png
new file mode 100644
index 0000000000..287a2872de
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-pressed.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-pressed@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@2x.9.png
new file mode 100644
index 0000000000..aa84416561
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-pressed@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@3x.9.png
new file mode 100644
index 0000000000..8c6822555b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background-pressed@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@4x.9.png
new file mode 100644
index 0000000000..89bdd096f8
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background.9.png b/src/quickcontrols2/imagine/images/toolbutton-background.9.png
new file mode 100644
index 0000000000..5a72a62128
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background@2x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background@2x.9.png
new file mode 100644
index 0000000000..688a071a84
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background@3x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background@3x.9.png
new file mode 100644
index 0000000000..64375a7e5b
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolbutton-background@4x.9.png b/src/quickcontrols2/imagine/images/toolbutton-background@4x.9.png
new file mode 100644
index 0000000000..96004a103c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolbutton-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal.9.png
new file mode 100644
index 0000000000..75e3e66229
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@2x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@2x.9.png
new file mode 100644
index 0000000000..3662dec944
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@3x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@3x.9.png
new file mode 100644
index 0000000000..2771470175
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@4x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@4x.9.png
new file mode 100644
index 0000000000..deeda9f5fd
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-horizontal@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-vertical.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical.9.png
new file mode 100644
index 0000000000..5b607aaf5c
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@2x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@2x.9.png
new file mode 100644
index 0000000000..f5a11e0467
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@3x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@3x.9.png
new file mode 100644
index 0000000000..c957280f37
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@4x.9.png b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@4x.9.png
new file mode 100644
index 0000000000..c888689df7
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/toolseparator-separator-vertical@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tooltip-background.9.png b/src/quickcontrols2/imagine/images/tooltip-background.9.png
new file mode 100644
index 0000000000..2e0dc67c3e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tooltip-background.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tooltip-background@2x.9.png b/src/quickcontrols2/imagine/images/tooltip-background@2x.9.png
new file mode 100644
index 0000000000..dd5609982f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tooltip-background@2x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tooltip-background@3x.9.png b/src/quickcontrols2/imagine/images/tooltip-background@3x.9.png
new file mode 100644
index 0000000000..fed465427e
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tooltip-background@3x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/images/tooltip-background@4x.9.png b/src/quickcontrols2/imagine/images/tooltip-background@4x.9.png
new file mode 100644
index 0000000000..9bc964908f
--- /dev/null
+++ b/src/quickcontrols2/imagine/images/tooltip-background@4x.9.png
Binary files differ
diff --git a/src/quickcontrols2/imagine/imagine.pri b/src/quickcontrols2/imagine/imagine.pri
new file mode 100644
index 0000000000..18a2ee6f92
--- /dev/null
+++ b/src/quickcontrols2/imagine/imagine.pri
@@ -0,0 +1,59 @@
+HEADERS += \
+ $$PWD/qquickimaginestyle_p.h \
+ $$PWD/qquickimaginetheme_p.h
+
+SOURCES += \
+ $$PWD/qquickimaginestyle.cpp \
+ $$PWD/qquickimaginetheme.cpp
+
+QML_FILES += \
+ $$PWD/ApplicationWindow.qml \
+ $$PWD/BusyIndicator.qml \
+ $$PWD/Button.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/CheckDelegate.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/DelayButton.qml \
+ $$PWD/Dial.qml \
+ $$PWD/Dialog.qml \
+ $$PWD/DialogButtonBox.qml \
+ $$PWD/Drawer.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/HorizontalHeaderView.qml \
+ $$PWD/ItemDelegate.qml \
+ $$PWD/Label.qml \
+ $$PWD/Menu.qml \
+ $$PWD/MenuItem.qml \
+ $$PWD/MenuSeparator.qml \
+ $$PWD/PageIndicator.qml \
+ $$PWD/Page.qml \
+ $$PWD/Pane.qml \
+ $$PWD/Popup.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/RadioDelegate.qml \
+ $$PWD/RangeSlider.qml \
+ $$PWD/RoundButton.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollIndicator.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/SplitView.qml \
+ $$PWD/StackView.qml \
+ $$PWD/SwipeDelegate.qml \
+ $$PWD/SwipeView.qml \
+ $$PWD/Switch.qml \
+ $$PWD/SwitchDelegate.qml \
+ $$PWD/TextField.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TabBar.qml \
+ $$PWD/TabButton.qml \
+ $$PWD/ToolBar.qml \
+ $$PWD/ToolButton.qml \
+ $$PWD/ToolSeparator.qml \
+ $$PWD/ToolTip.qml \
+ $$PWD/Tumbler.qml \
+ $$PWD/VerticalHeaderView.qml
diff --git a/src/quickcontrols2/imagine/impl/CMakeLists.txt b/src/quickcontrols2/imagine/impl/CMakeLists.txt
new file mode 100644
index 0000000000..7c576dbad6
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/CMakeLists.txt
@@ -0,0 +1,44 @@
+#####################################################################
+## qtquickcontrols2imaginestyleimplplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "OpacityMask.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2imaginestyleimplplugin
+ URI "QtQuick.Controls.Imagine.impl"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickControls2ImagineStyleImplPlugin
+ PLUGIN_TARGET qtquickcontrols2imaginestyleimplplugin
+ NO_PLUGIN_OPTIONAL
+ SOURCES
+ qquickimageselector.cpp qquickimageselector_p.h
+ qquickninepatchimage.cpp qquickninepatchimage_p.h
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+# Resources:
+set(qmake_qtquickcontrols2imaginestyleimplplugin_resource_files
+ "shaders/+glslcore/OpacityMask.frag"
+ "shaders/+qsb/OpacityMask.frag"
+ "shaders/OpacityMask.frag"
+)
+
+qt_internal_add_resource(qtquickcontrols2imaginestyleimplplugin "qmake_qtquickcontrols2imaginestyleimplplugin"
+ PREFIX
+ "qt-project.org/imports/QtQuick/Controls/Imagine/impl"
+ FILES
+ ${qmake_qtquickcontrols2imaginestyleimplplugin_resource_files}
+)
diff --git a/src/quickcontrols2/imagine/impl/OpacityMask.qml b/src/quickcontrols2/imagine/impl/OpacityMask.qml
new file mode 100644
index 0000000000..26663a1b53
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/OpacityMask.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+
+/*
+ A cross-graphics API implementation of QtGraphicalEffects' OpacityMask.
+ */
+Item {
+ id: rootItem
+
+ property variant source
+ property variant maskSource
+ property bool cached: false
+
+ ShaderEffectSource {
+ id: cacheItem
+ anchors.fill: parent
+ visible: rootItem.cached
+ smooth: true
+ sourceItem: shaderItem
+ live: true
+ hideSource: visible
+ }
+
+ ShaderEffect {
+ id: shaderItem
+ property variant source: rootItem.source
+ property variant maskSource: rootItem.maskSource
+
+ anchors.fill: parent
+
+ fragmentShader: "qrc:/qt-project.org/imports/QtQuick/Controls/Imagine/impl/shaders/OpacityMask.frag"
+ }
+}
diff --git a/src/quickcontrols2/imagine/impl/qquickimageselector.cpp b/src/quickcontrols2/imagine/impl/qquickimageselector.cpp
new file mode 100644
index 0000000000..dcb7738c4f
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/qquickimageselector.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickimageselector_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qcache.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qfileselector.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQml/private/qqmlproperty_p.h>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQtQuickControlsImagine, "qt.quick.controls.imagine")
+
+static const int DEFAULT_CACHE = 500;
+
+static inline int cacheSize()
+{
+ static bool ok = false;
+ static const int size = qEnvironmentVariableIntValue("QT_QUICK_CONTROLS_IMAGINE_CACHE", &ok);
+ return ok ? size : DEFAULT_CACHE;
+}
+
+// input: [focused, pressed]
+// => [[focused, pressed], [pressed, focused], [focused], [pressed]]
+static QList<QStringList> permutations(const QStringList &input, int count = -1)
+{
+ if (count == -1)
+ count = input.count();
+
+ QList<QStringList> output;
+ for (int i = 0; i < input.count(); ++i) {
+ QStringList sub = input.mid(i, count);
+
+ if (count > 1) {
+ if (i + count > input.count())
+ sub += input.mid(0, count - i + 1);
+
+ std::sort(sub.begin(), sub.end());
+ do {
+ if (!sub.isEmpty())
+ output += sub;
+ } while (std::next_permutation(sub.begin(), sub.end()));
+ } else {
+ output += sub;
+ }
+
+ if (count == input.count())
+ break;
+ }
+
+ if (count > 1)
+ output += permutations(input, --count);
+
+ return output;
+}
+
+static QString findFile(const QDir &dir, const QString &baseName, const QStringList &extensions)
+{
+ for (const QString &ext : extensions) {
+ QString filePath = dir.filePath(baseName + QLatin1Char('.') + ext);
+ if (QFile::exists(filePath))
+ return QFileSelector().select(filePath);
+ }
+ // return an empty string to indicate that the lookup has been done
+ // even if no matching asset was found
+ return QLatin1String("");
+}
+
+QQuickImageSelector::QQuickImageSelector(QObject *parent)
+ : QObject(parent),
+ m_cache(cacheSize() > 0)
+{
+}
+
+QUrl QQuickImageSelector::source() const
+{
+ return m_source;
+}
+
+void QQuickImageSelector::setSource(const QUrl &source)
+{
+ if (m_property.isValid())
+ QQmlPropertyPrivate::write(m_property, source, QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding);
+ if (m_source == source)
+ return;
+
+ m_source = source;
+ emit sourceChanged();
+}
+
+QString QQuickImageSelector::name() const
+{
+ return m_name;
+}
+
+void QQuickImageSelector::setName(const QString &name)
+{
+ if (m_name == name)
+ return;
+
+ m_name = name;
+ if (m_complete)
+ updateSource();
+}
+
+QString QQuickImageSelector::path() const
+{
+ return m_path;
+}
+
+void QQuickImageSelector::setPath(const QString &path)
+{
+ if (m_path == path)
+ return;
+
+ m_path = path;
+ if (m_complete)
+ updateSource();
+}
+
+QVariantList QQuickImageSelector::states() const
+{
+ return m_allStates;
+}
+
+void QQuickImageSelector::setStates(const QVariantList &states)
+{
+ if (m_allStates == states)
+ return;
+
+ m_allStates = states;
+ if (updateActiveStates() && m_complete)
+ updateSource();
+}
+
+QString QQuickImageSelector::separator() const
+{
+ return m_separator;
+}
+
+void QQuickImageSelector::setSeparator(const QString &separator)
+{
+ if (m_separator == separator)
+ return;
+
+ m_separator = separator;
+ if (m_complete)
+ updateSource();
+}
+
+bool QQuickImageSelector::cache() const
+{
+ return m_cache;
+}
+
+void QQuickImageSelector::setCache(bool cache)
+{
+ m_cache = cache;
+}
+
+void QQuickImageSelector::write(const QVariant &value)
+{
+ setUrl(value.toUrl());
+}
+
+void QQuickImageSelector::setTarget(const QQmlProperty &property)
+{
+ m_property = property;
+}
+
+void QQuickImageSelector::classBegin()
+{
+}
+
+void QQuickImageSelector::componentComplete()
+{
+ setUrl(m_property.read().toUrl());
+ m_complete = true;
+ updateSource();
+}
+
+QStringList QQuickImageSelector::fileExtensions() const
+{
+ static const QStringList extensions = QStringList() << QStringLiteral("png");
+ return extensions;
+}
+
+QString QQuickImageSelector::cacheKey() const
+{
+ if (!m_cache)
+ return QString();
+
+ return m_path + m_name + m_activeStates.join(m_separator);
+}
+
+void QQuickImageSelector::updateSource()
+{
+ static QCache<QString, QString> cache(cacheSize());
+
+ const QString key = cacheKey();
+
+ QString bestFilePath;
+
+ if (m_cache) {
+ QString *cachedPath = cache.object(key);
+ if (cachedPath)
+ bestFilePath = *cachedPath;
+ }
+
+ // note: a cached file path may be empty
+ if (bestFilePath.isNull()) {
+ QDir dir(m_path);
+ int bestScore = -1;
+
+ const QStringList extensions = fileExtensions();
+
+ const QList<QStringList> statePerms = permutations(m_activeStates);
+ for (const QStringList &perm : statePerms) {
+ const QString filePath = findFile(dir, m_name + m_separator + perm.join(m_separator), extensions);
+ if (!filePath.isEmpty()) {
+ int score = calculateScore(perm);
+ if (score > bestScore) {
+ bestScore = score;
+ bestFilePath = filePath;
+ }
+ }
+ }
+
+ if (bestFilePath.isEmpty())
+ bestFilePath = findFile(dir, m_name, extensions);
+
+ if (m_cache)
+ cache.insert(key, new QString(bestFilePath));
+ }
+
+ qCDebug(lcQtQuickControlsImagine) << m_name << m_activeStates << "->" << bestFilePath;
+
+ if (bestFilePath.startsWith(QLatin1Char(':')))
+ setSource(QUrl(QLatin1String("qrc") + bestFilePath));
+ else
+ setSource(QUrl::fromLocalFile(bestFilePath));
+}
+
+void QQuickImageSelector::setUrl(const QUrl &url)
+{
+ QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(url));
+ setName(fileInfo.fileName());
+ setPath(fileInfo.path());
+}
+
+bool QQuickImageSelector::updateActiveStates()
+{
+ QStringList active;
+ for (const QVariant &v : qAsConst(m_allStates)) {
+ const QVariantMap state = v.toMap();
+ if (state.isEmpty())
+ continue;
+ auto it = state.begin();
+ if (it.value().toBool())
+ active += it.key();
+ }
+
+ if (m_activeStates == active)
+ return false;
+
+ m_activeStates = active;
+ return true;
+}
+
+int QQuickImageSelector::calculateScore(const QStringList &states) const
+{
+ int score = 0;
+ for (int i = 0; i < states.count(); ++i)
+ score += (m_activeStates.count() - m_activeStates.indexOf(states.at(i))) << 1;
+ return score;
+}
+
+QQuickNinePatchImageSelector::QQuickNinePatchImageSelector(QObject *parent)
+ : QQuickImageSelector(parent)
+{
+}
+
+QStringList QQuickNinePatchImageSelector::fileExtensions() const
+{
+ static const QStringList extensions = QStringList() << QStringLiteral("9.png") << QStringLiteral("png");
+ return extensions;
+}
+
+QQuickAnimatedImageSelector::QQuickAnimatedImageSelector(QObject *parent)
+ : QQuickImageSelector(parent)
+{
+}
+
+QStringList QQuickAnimatedImageSelector::fileExtensions() const
+{
+ static const QStringList extensions = QStringList() << QStringLiteral("webp") << QStringLiteral("gif");
+ return extensions;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/imagine/impl/qquickimageselector_p.h b/src/quickcontrols2/imagine/impl/qquickimageselector_p.h
new file mode 100644
index 0000000000..351caefbef
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/qquickimageselector_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKIMAGESELECTOR_P_H
+#define QQUICKIMAGESELECTOR_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/qobject.h>
+#include <QtCore/qvariant.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/private/qqmlpropertyvalueinterceptor_p.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickImageSelector : public QObject, public QQmlParserStatus, public QQmlPropertyValueInterceptor
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source NOTIFY sourceChanged FINAL)
+ Q_PROPERTY(QString name READ name WRITE setName FINAL)
+ Q_PROPERTY(QString path READ path WRITE setPath FINAL)
+ Q_PROPERTY(QVariantList states READ states WRITE setStates FINAL)
+ Q_PROPERTY(QString separator READ separator WRITE setSeparator FINAL)
+ Q_PROPERTY(bool cache READ cache WRITE setCache FINAL)
+ Q_INTERFACES(QQmlParserStatus QQmlPropertyValueInterceptor)
+ QML_NAMED_ELEMENT(ImageSelector)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickImageSelector(QObject *parent = nullptr);
+
+ QUrl source() const;
+ void setSource(const QUrl &source);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QString path() const;
+ void setPath(const QString &path);
+
+ QVariantList states() const;
+ void setStates(const QVariantList &states);
+
+ QString separator() const;
+ void setSeparator(const QString &separator);
+
+ bool cache() const;
+ void setCache(bool cache);
+
+ void write(const QVariant &value) override;
+ void setTarget(const QQmlProperty &property) override;
+
+Q_SIGNALS:
+ void sourceChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ virtual QStringList fileExtensions() const;
+
+ QString cacheKey() const;
+ void updateSource();
+ void setUrl(const QUrl &url);
+ bool updateActiveStates();
+ int calculateScore(const QStringList &states) const;
+
+private:
+ bool m_cache = false;
+ bool m_complete = false;
+ QUrl m_source;
+ QString m_path;
+ QString m_name;
+ QString m_separator = QLatin1String("-");
+ QVariantList m_allStates;
+ QStringList m_activeStates;
+ QQmlProperty m_property;
+};
+
+class QQuickNinePatchImageSelector : public QQuickImageSelector
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(NinePatchImageSelector)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickNinePatchImageSelector(QObject *parent = nullptr);
+
+protected:
+ QStringList fileExtensions() const override;
+};
+
+class QQuickAnimatedImageSelector : public QQuickImageSelector
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(AnimatedImageSelector)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickAnimatedImageSelector(QObject *parent = nullptr);
+
+protected:
+ QStringList fileExtensions() const override;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickImageSelector)
+QML_DECLARE_TYPE(QQuickAnimatedImageSelector)
+
+#endif // QQUICKIMAGESELECTOR_P_H
diff --git a/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp b/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp
new file mode 100644
index 0000000000..934eb887d6
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/qquickninepatchimage.cpp
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickninepatchimage_p.h"
+
+#include <QtCore/qfileinfo.h>
+#include <QtQuick/qsggeometry.h>
+#include <QtQuick/qsgtexturematerial.h>
+#include <QtQuick/private/qsgnode_p.h>
+#include <QtQuick/private/qquickimage_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQuickNinePatchData
+{
+ QList<qreal> coordsForSize(qreal count) const;
+
+ inline bool isNull() const { return data.isEmpty(); }
+ inline int count() const { return data.size(); }
+ inline qreal at(int index) const { return data.at(index); }
+ inline qreal size() const { return data.last(); }
+
+ void fill(const QList<qreal> &coords, qreal count);
+ void clear();
+
+private:
+ bool inverted = false;
+ QList<qreal> data;
+};
+
+QList<qreal> QQuickNinePatchData::coordsForSize(qreal size) const
+{
+ // n = number of stretchable sections
+ // We have to compensate when adding 0 and/or
+ // the source image width to the divs vector.
+ const int l = data.size();
+ const int n = (inverted ? l - 1 : l) / 2;
+ const qreal stretch = (size - data.last()) / n;
+
+ QList<qreal> coords;
+ coords.reserve(l);
+ coords.append(0);
+
+ bool stretched = !inverted;
+ for (int i = 1; i < l; ++i) {
+ qreal advance = data[i] - data[i - 1];
+ if (stretched)
+ advance += stretch;
+ coords.append(coords.last() + advance);
+
+ stretched = !stretched;
+ }
+
+ return coords;
+}
+
+/*
+ Adds the 0 index coordinate if appropriate, and the one at "size".
+*/
+void QQuickNinePatchData::fill(const QList<qreal> &coords, qreal size)
+{
+ data.clear();
+ inverted = coords.isEmpty() || coords.first() != 0;
+
+ // Reserve an extra item in case we need to add the image width/height
+ if (inverted) {
+ data.reserve(coords.size() + 2);
+ data.append(0);
+ } else {
+ data.reserve(coords.size() + 1);
+ }
+
+ data += coords;
+ data.append(size);
+}
+
+void QQuickNinePatchData::clear()
+{
+ data.clear();
+}
+
+class QQuickNinePatchNode : public QSGGeometryNode
+{
+public:
+ QQuickNinePatchNode();
+ ~QQuickNinePatchNode();
+
+ void initialize(QSGTexture *texture, const QSizeF &targetSize, const QSize &sourceSize,
+ const QQuickNinePatchData &xDivs, const QQuickNinePatchData &yDivs, qreal dpr);
+
+private:
+ QSGGeometry m_geometry;
+ QSGTextureMaterial m_material;
+};
+
+QQuickNinePatchNode::QQuickNinePatchNode()
+ : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
+{
+ m_geometry.setDrawingMode(QSGGeometry::DrawTriangles);
+ setGeometry(&m_geometry);
+ setMaterial(&m_material);
+}
+
+QQuickNinePatchNode::~QQuickNinePatchNode()
+{
+ delete m_material.texture();
+}
+
+void QQuickNinePatchNode::initialize(QSGTexture *texture, const QSizeF &targetSize, const QSize &sourceSize,
+ const QQuickNinePatchData &xDivs, const QQuickNinePatchData &yDivs, qreal dpr)
+{
+ delete m_material.texture();
+ m_material.setTexture(texture);
+
+ const int xlen = xDivs.count();
+ const int ylen = yDivs.count();
+
+ if (xlen > 0 && ylen > 0) {
+ const int quads = (xlen - 1) * (ylen - 1);
+ static const int verticesPerQuad = 6;
+ m_geometry.allocate(xlen * ylen, verticesPerQuad * quads);
+
+ QSGGeometry::TexturedPoint2D *vertices = m_geometry.vertexDataAsTexturedPoint2D();
+ QList<qreal> xCoords = xDivs.coordsForSize(targetSize.width());
+ QList<qreal> yCoords = yDivs.coordsForSize(targetSize.height());
+
+ for (int y = 0; y < ylen; ++y) {
+ for (int x = 0; x < xlen; ++x, ++vertices)
+ vertices->set(xCoords[x] / dpr, yCoords[y] / dpr,
+ xDivs.at(x) / sourceSize.width(),
+ yDivs.at(y) / sourceSize.height());
+ }
+
+ quint16 *indices = m_geometry.indexDataAsUShort();
+ int n = quads;
+ for (int q = 0; n--; ++q) {
+ if ((q + 1) % xlen == 0) // next row
+ ++q;
+ // Bottom-left half quad triangle
+ indices[0] = q;
+ indices[1] = q + xlen;
+ indices[2] = q + xlen + 1;
+
+ // Top-right half quad triangle
+ indices[3] = q;
+ indices[4] = q + xlen + 1;
+ indices[5] = q + 1;
+
+ indices += verticesPerQuad;
+ }
+ }
+
+ markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
+}
+
+class QQuickNinePatchImagePrivate : public QQuickImagePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickNinePatchImage)
+
+public:
+ void updatePatches();
+ void updatePaddings(const QSizeF &size, const QList<qreal> &horizontal, const QList<qreal> &vertical);
+ void updateInsets(const QList<qreal> &horizontal, const QList<qreal> &vertical);
+
+ bool resetNode = false;
+ qreal topPadding = 0;
+ qreal leftPadding = 0;
+ qreal rightPadding = 0;
+ qreal bottomPadding = 0;
+ qreal topInset = 0;
+ qreal leftInset = 0;
+ qreal rightInset = 0;
+ qreal bottomInset = 0;
+
+ QImage ninePatch;
+ QQuickNinePatchData xDivs;
+ QQuickNinePatchData yDivs;
+};
+
+/*
+ Examines each pixel in a horizontal or vertical (if offset is equal to the image's width)
+ line, storing the start and end index ("coordinate") of each 9-patch line.
+
+ For instance, in the 7x3 (9x5 actual size) 9-patch image below, which has no horizontal
+ stretchable area, it would return {}:
+
+ +-----+
+ | |
+ +-----+
+
+ If indices 3 to 5 were marked, it would return {2, 5}:
+
+ xxx
+ +-----+
+ | |
+ +-----+
+
+ If indices 3 and 5 were marked, it would store {0, 2, 3, 4, 5, 7}:
+
+ x x
+ +-----+
+ | |
+ +-----+
+*/
+static QList<qreal> readCoords(const QRgb *data, int from, int count, int offset, QRgb color)
+{
+ int p1 = -1;
+ QList<qreal> coords;
+ for (int i = 0; i < count; ++i) {
+ int p2 = from + i * offset;
+ if (data[p2] == color) {
+ // colored pixel
+ if (p1 == -1) {
+ // This is the start of a 9-patch line.
+ p1 = i;
+ }
+ } else {
+ // empty pixel
+ if (p1 != -1) {
+ // This is the end of a 9-patch line; add the start and end indices as coordinates...
+ coords << p1 << i;
+ // ... and reset p1 so that we can search for the next one.
+ p1 = -1;
+ }
+ }
+ }
+ return coords;
+}
+
+/*
+ Called whenever a 9-patch image is set as the image's source.
+
+ Reads the 9-patch lines from the source image and sets the
+ inset and padding properties accordingly.
+*/
+void QQuickNinePatchImagePrivate::updatePatches()
+{
+ if (ninePatch.isNull())
+ return;
+
+ int w = ninePatch.width();
+ int h = ninePatch.height();
+ const QRgb *data = reinterpret_cast<const QRgb *>(ninePatch.constBits());
+
+ const QRgb black = qRgb(0,0,0);
+ const QRgb red = qRgb(255,0,0);
+
+ xDivs.fill(readCoords(data, 1, w - 1, 1, black), w - 2); // top left -> top right
+ yDivs.fill(readCoords(data, w, h - 1, w, black), h - 2); // top left -> bottom left
+
+ QList<qreal> hInsets = readCoords(data, (h - 1) * w + 1, w - 1, 1, red); // bottom left -> bottom right
+ QList<qreal> vInsets = readCoords(data, 2 * w - 1, h - 1, w, red); // top right -> bottom right
+ updateInsets(hInsets, vInsets);
+
+ const QSizeF sz(w - leftInset - rightInset, h - topInset - bottomInset);
+ QList<qreal> hPaddings = readCoords(data, (h - 1) * w + leftInset + 1, sz.width() - 2, 1, black); // bottom left -> bottom right
+ QList<qreal> vPaddings = readCoords(data, (2 + topInset) * w - 1, sz.height() - 2, w, black); // top right -> bottom right
+ updatePaddings(sz, hPaddings, vPaddings);
+}
+
+void QQuickNinePatchImagePrivate::updatePaddings(const QSizeF &size, const QList<qreal> &horizontal, const QList<qreal> &vertical)
+{
+ Q_Q(QQuickNinePatchImage);
+ qreal oldTopPadding = topPadding;
+ qreal oldLeftPadding = leftPadding;
+ qreal oldRightPadding = rightPadding;
+ qreal oldBottomPadding = bottomPadding;
+
+ if (horizontal.count() >= 2) {
+ leftPadding = horizontal.first();
+ rightPadding = size.width() - horizontal.last() - 2;
+ } else {
+ leftPadding = 0;
+ rightPadding = 0;
+ }
+
+ if (vertical.count() >= 2) {
+ topPadding = vertical.first();
+ bottomPadding = size.height() - vertical.last() - 2;
+ } else {
+ topPadding = 0;
+ bottomPadding = 0;
+ }
+
+ if (!qFuzzyCompare(oldTopPadding, topPadding))
+ emit q->topPaddingChanged();
+ if (!qFuzzyCompare(oldBottomPadding, bottomPadding))
+ emit q->bottomPaddingChanged();
+ if (!qFuzzyCompare(oldLeftPadding, leftPadding))
+ emit q->leftPaddingChanged();
+ if (!qFuzzyCompare(oldRightPadding, rightPadding))
+ emit q->rightPaddingChanged();
+}
+
+void QQuickNinePatchImagePrivate::updateInsets(const QList<qreal> &horizontal, const QList<qreal> &vertical)
+{
+ Q_Q(QQuickNinePatchImage);
+ qreal oldTopInset = topInset;
+ qreal oldLeftInset = leftInset;
+ qreal oldRightInset = rightInset;
+ qreal oldBottomInset = bottomInset;
+
+ if (horizontal.count() >= 2 && horizontal.first() == 0)
+ leftInset = horizontal.at(1);
+ else
+ leftInset = 0;
+
+ if (horizontal.count() == 2 && horizontal.first() > 0)
+ rightInset = horizontal.last() - horizontal.first();
+ else if (horizontal.count() == 4)
+ rightInset = horizontal.last() - horizontal.at(2);
+ else
+ rightInset = 0;
+
+ if (vertical.count() >= 2 && vertical.first() == 0)
+ topInset = vertical.at(1);
+ else
+ topInset = 0;
+
+ if (vertical.count() == 2 && vertical.first() > 0)
+ bottomInset = vertical.last() - vertical.first();
+ else if (vertical.count() == 4)
+ bottomInset = vertical.last() - vertical.at(2);
+ else
+ bottomInset = 0;
+
+ if (!qFuzzyCompare(oldTopInset, topInset))
+ emit q->topInsetChanged();
+ if (!qFuzzyCompare(oldBottomInset, bottomInset))
+ emit q->bottomInsetChanged();
+ if (!qFuzzyCompare(oldLeftInset, leftInset))
+ emit q->leftInsetChanged();
+ if (!qFuzzyCompare(oldRightInset, rightInset))
+ emit q->rightInsetChanged();
+}
+
+QQuickNinePatchImage::QQuickNinePatchImage(QQuickItem *parent)
+ : QQuickImage(*(new QQuickNinePatchImagePrivate), parent)
+{
+ Q_D(QQuickNinePatchImage);
+ d->smooth = qEnvironmentVariableIntValue("QT_QUICK_CONTROLS_IMAGINE_SMOOTH");
+}
+
+qreal QQuickNinePatchImage::topPadding() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->topPadding / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::leftPadding() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->leftPadding / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::rightPadding() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->rightPadding / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::bottomPadding() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->bottomPadding / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::topInset() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->topInset / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::leftInset() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->leftInset / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::rightInset() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->rightInset / d->devicePixelRatio;
+}
+
+qreal QQuickNinePatchImage::bottomInset() const
+{
+ Q_D(const QQuickNinePatchImage);
+ return d->bottomInset / d->devicePixelRatio;
+}
+
+void QQuickNinePatchImage::pixmapChange()
+{
+ Q_D(QQuickNinePatchImage);
+ if (QFileInfo(d->url.fileName()).completeSuffix().toLower() == QLatin1String("9.png")) {
+ // Keep resetNode if it is already set, we do not want to miss an
+ // ImageNode->NinePatchNode change. Without this there's a chance one gets
+ // an incorrect cast on oldNode every once in a while with source changes.
+ if (!d->resetNode)
+ d->resetNode = d->ninePatch.isNull();
+
+ d->ninePatch = d->pix.image();
+ if (d->ninePatch.depth() != 32)
+ d->ninePatch = 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->updatePatches();
+ } else {
+ /*
+ Only change resetNode when it's false; i.e. when no reset is pending.
+ updatePaintNode() will take care of setting it to false if it's true.
+
+ Consider the following changes in source:
+
+ normal.png => press.9.png => normal.png => focus.png
+
+ If the last two events happen quickly, pixmapChange() can be called
+ twice with no call to updatePaintNode() inbetween. On the first call,
+ resetNode will be true (because ninePatch is not null since it is still
+ in the process of going from a 9-patch image to a regular image),
+ and on the second call, resetNode would be false if we didn't have this check.
+ This results in the oldNode never being deleted, and QQuickImage
+ tries to static_cast a QQuickNinePatchImage to a QSGInternalImageNode.
+ */
+ if (!d->resetNode)
+ d->resetNode = !d->ninePatch.isNull();
+ d->ninePatch = QImage();
+ }
+ QQuickImage::pixmapChange();
+}
+
+QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_D(QQuickNinePatchImage);
+ Q_UNUSED(data);
+
+ if (d->resetNode) {
+ delete oldNode;
+ oldNode = nullptr;
+ d->resetNode = false;
+ }
+
+ QSizeF sz = size();
+ QImage image = d->pix.image();
+ if (!sz.isValid() || image.isNull()) {
+ if (d->provider)
+ d->provider->updateTexture(nullptr);
+ delete oldNode;
+ return nullptr;
+ }
+
+ if (d->ninePatch.isNull())
+ return QQuickImage::updatePaintNode(oldNode, data);
+
+ QQuickNinePatchNode *patchNode = static_cast<QQuickNinePatchNode *>(oldNode);
+ if (!patchNode)
+ patchNode = new QQuickNinePatchNode;
+
+#ifdef QSG_RUNTIME_DESCRIPTION
+ qsgnode_set_description(patchNode, QString::fromLatin1("QQuickNinePatchImage: '%1'").arg(d->url.toString()));
+#endif
+
+ // The image may wrap non-owned data (due to pixmapChange). Ensure we never
+ // pass such an image to the scenegraph, because with a separate render
+ // thread the data may become invalid (in a subsequent pixmapChange on the
+ // gui thread) by the time the renderer gets to do something with the QImage
+ // passed in here.
+ image.detach();
+
+ QSGTexture *texture = window()->createTextureFromImage(image);
+ patchNode->initialize(texture, sz * d->devicePixelRatio, image.size(), d->xDivs, d->yDivs, d->devicePixelRatio);
+ auto patchNodeMaterial = static_cast<QSGTextureMaterial *>(patchNode->material());
+ patchNodeMaterial->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest);
+ return patchNode;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/imagine/impl/qquickninepatchimage_p.h b/src/quickcontrols2/imagine/impl/qquickninepatchimage_p.h
new file mode 100644
index 0000000000..78cc306885
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/qquickninepatchimage_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKNINEPATCHIMAGE_P_H
+#define QQUICKNINEPATCHIMAGE_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/qquickimage_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickNinePatchImagePrivate;
+
+class QQuickNinePatchImage : public QQuickImage
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal topPadding READ topPadding NOTIFY topPaddingChanged FINAL)
+ Q_PROPERTY(qreal leftPadding READ leftPadding NOTIFY leftPaddingChanged FINAL)
+ Q_PROPERTY(qreal rightPadding READ rightPadding NOTIFY rightPaddingChanged FINAL)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding NOTIFY bottomPaddingChanged FINAL)
+ Q_PROPERTY(qreal topInset READ topInset NOTIFY topInsetChanged FINAL)
+ Q_PROPERTY(qreal leftInset READ leftInset NOTIFY leftInsetChanged FINAL)
+ Q_PROPERTY(qreal rightInset READ rightInset NOTIFY rightInsetChanged FINAL)
+ Q_PROPERTY(qreal bottomInset READ bottomInset NOTIFY bottomInsetChanged FINAL)
+ QML_NAMED_ELEMENT(NinePatchImage)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickNinePatchImage(QQuickItem *parent = nullptr);
+
+ qreal topPadding() const;
+ qreal leftPadding() const;
+ qreal rightPadding() const;
+ qreal bottomPadding() const;
+
+ qreal topInset() const;
+ qreal leftInset() const;
+ qreal rightInset() const;
+ qreal bottomInset() const;
+
+Q_SIGNALS:
+ void topPaddingChanged();
+ void leftPaddingChanged();
+ void rightPaddingChanged();
+ void bottomPaddingChanged();
+
+ void topInsetChanged();
+ void leftInsetChanged();
+ void rightInsetChanged();
+ void bottomInsetChanged();
+
+protected:
+ void pixmapChange() override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;
+
+private:
+ Q_DISABLE_COPY(QQuickNinePatchImage)
+ Q_DECLARE_PRIVATE(QQuickNinePatchImage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickNinePatchImage)
+
+#endif // QQUICKNINEPATCHIMAGE_P_H
diff --git a/src/quickcontrols2/imagine/impl/shaders/+glslcore/OpacityMask.frag b/src/quickcontrols2/imagine/impl/shaders/+glslcore/OpacityMask.frag
new file mode 100644
index 0000000000..529e269614
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/shaders/+glslcore/OpacityMask.frag
@@ -0,0 +1,13 @@
+#version 150
+
+uniform float qt_Opacity;
+uniform sampler2D source;
+uniform sampler2D maskSource;
+
+in vec2 qt_TexCoord0;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = texture(source, qt_TexCoord0.st) * (texture(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
+}
diff --git a/src/quickcontrols2/imagine/impl/shaders/+qsb/OpacityMask.frag b/src/quickcontrols2/imagine/impl/shaders/+qsb/OpacityMask.frag
new file mode 100644
index 0000000000..331b30b807
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/shaders/+qsb/OpacityMask.frag
Binary files differ
diff --git a/src/quickcontrols2/imagine/impl/shaders/OpacityMask.frag b/src/quickcontrols2/imagine/impl/shaders/OpacityMask.frag
new file mode 100644
index 0000000000..84f9bc3ee6
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/shaders/OpacityMask.frag
@@ -0,0 +1,7 @@
+varying highp vec2 qt_TexCoord0;
+uniform highp float qt_Opacity;
+uniform lowp sampler2D source;
+uniform lowp sampler2D maskSource;
+void main(void) {
+ gl_FragColor = texture2D(source, qt_TexCoord0.st) * (texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity;
+}
diff --git a/src/quickcontrols2/imagine/impl/shaders/OpacityMask_rhi.frag b/src/quickcontrols2/imagine/impl/shaders/OpacityMask_rhi.frag
new file mode 100644
index 0000000000..9ae3249978
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/shaders/OpacityMask_rhi.frag
@@ -0,0 +1,17 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+} ubuf;
+
+layout(binding = 1) uniform sampler2D source;
+layout(binding = 2) uniform sampler2D maskSource;
+
+void main()
+{
+ fragColor = texture(source, qt_TexCoord0.st) * (texture(maskSource, qt_TexCoord0.st).a) * ubuf.qt_Opacity;
+}
diff --git a/src/quickcontrols2/imagine/impl/shaders/compile.bat b/src/quickcontrols2/imagine/impl/shaders/compile.bat
new file mode 100644
index 0000000000..8f16d7acf0
--- /dev/null
+++ b/src/quickcontrols2/imagine/impl/shaders/compile.bat
@@ -0,0 +1,40 @@
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Copyright (C) 2020 The Qt Company Ltd.
+:: Contact: https://www.qt.io/licensing/
+::
+:: This file is part of the QtQuick module of the Qt Toolkit.
+::
+:: $QT_BEGIN_LICENSE:LGPL$
+:: Commercial License Usage
+:: Licensees holding valid commercial Qt licenses may use this file in
+:: accordance with the commercial license agreement provided with the
+:: Software or, alternatively, in accordance with the terms contained in
+:: a written agreement between you and The Qt Company. For licensing terms
+:: and conditions see https://www.qt.io/terms-conditions. For further
+:: information use the contact form at https://www.qt.io/contact-us.
+::
+:: GNU Lesser General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU Lesser
+:: General Public License version 3 as published by the Free Software
+:: Foundation and appearing in the file LICENSE.LGPL3 included in the
+:: packaging of this file. Please review the following information to
+:: ensure the GNU Lesser General Public License version 3 requirements
+:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+::
+:: GNU General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU
+:: General Public License version 2.0 or (at your option) the GNU General
+:: Public license version 3 or any later version approved by the KDE Free
+:: Qt Foundation. The licenses are as published by the Free Software
+:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+:: included in the packaging of this file. Please review the following
+:: information to ensure the GNU General Public License requirements will
+:: be met: https://www.gnu.org/licenses/gpl-2.0.html and
+:: https://www.gnu.org/licenses/gpl-3.0.html.
+::
+:: $QT_END_LICENSE$
+::
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/OpacityMask.frag OpacityMask_rhi.frag
diff --git a/src/quickcontrols2/imagine/qquickimaginestyle.cpp b/src/quickcontrols2/imagine/qquickimaginestyle.cpp
new file mode 100644
index 0000000000..6152b66285
--- /dev/null
+++ b/src/quickcontrols2/imagine/qquickimaginestyle.cpp
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickimaginestyle_p.h"
+
+#include <QtCore/qsettings.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QString, GlobalPath, (QLatin1String("qrc:/qt-project.org/imports/QtQuick/Controls/Imagine/images/")))
+
+static QString ensureSlash(const QString &path)
+{
+ const QChar slash = QLatin1Char('/');
+ return path.endsWith(slash) ? path : path + slash;
+}
+
+QQuickImagineStyle::QQuickImagineStyle(QObject *parent)
+ : QQuickAttachedObject(parent),
+ m_path(*GlobalPath())
+{
+ init();
+}
+
+QQuickImagineStyle *QQuickImagineStyle::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickImagineStyle(object);
+}
+
+QString QQuickImagineStyle::path() const
+{
+ return m_path;
+}
+
+void QQuickImagineStyle::setPath(const QString &path)
+{
+ m_explicitPath = true;
+ if (m_path == path)
+ return;
+
+ m_path = path;
+ propagatePath();
+
+ emit pathChanged();
+}
+
+void QQuickImagineStyle::inheritPath(const QString &path)
+{
+ if (m_explicitPath || m_path == path)
+ return;
+
+ m_path = path;
+ propagatePath();
+ emit pathChanged();
+}
+
+void QQuickImagineStyle::propagatePath()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickImagineStyle *imagine = qobject_cast<QQuickImagineStyle *>(child);
+ if (imagine)
+ imagine->inheritPath(m_path);
+ }
+}
+
+void QQuickImagineStyle::resetPath()
+{
+ if (!m_explicitPath)
+ return;
+
+ m_explicitPath = false;
+ QQuickImagineStyle *imagine = qobject_cast<QQuickImagineStyle *>(attachedParent());
+ inheritPath(imagine ? imagine->path() : *GlobalPath());
+}
+
+QUrl QQuickImagineStyle::url() const
+{
+ // Using ApplicationWindow as an example, its NinePatchImage url
+ // was previously assigned like this:
+ //
+ // soruce: Imagine.path + "applicationwindow-background"
+ //
+ // If Imagine.path is set to ":/images" by the user, then the final URL would be:
+ //
+ // QUrl("file:///home/user/qt/qtbase/qml/QtQuick/Controls/Imagine/:/images/applicationwindow-background")
+ //
+ // To ensure that the correct URL is constructed, we do it ourselves here,
+ // and then the control QML files use the "url" property instead.
+ const QString path = ensureSlash(m_path);
+ if (path.startsWith(QLatin1String("qrc")))
+ return QUrl(path);
+
+ if (path.startsWith(QLatin1String(":/")))
+ return QUrl(QLatin1String("qrc") + path);
+
+ return QUrl::fromLocalFile(path);
+}
+
+void QQuickImagineStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+{
+ Q_UNUSED(oldParent);
+ QQuickImagineStyle *imagine = qobject_cast<QQuickImagineStyle *>(newParent);
+ if (imagine)
+ inheritPath(imagine->path());
+}
+
+static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
+{
+ QByteArray value = qgetenv(env);
+#if QT_CONFIG(settings)
+ if (value.isNull() && !settings.isNull())
+ value = settings->value(name).toByteArray();
+#endif
+ return value;
+}
+
+void QQuickImagineStyle::init()
+{
+ static bool globalsInitialized = false;
+ if (!globalsInitialized) {
+ QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Imagine"));
+
+ QString path = QString::fromUtf8(resolveSetting("QT_QUICK_CONTROLS_IMAGINE_PATH", settings, QStringLiteral("Path")));
+ if (!path.isEmpty())
+ *GlobalPath() = m_path = ensureSlash(path);
+
+ globalsInitialized = true;
+ }
+
+ QQuickAttachedObject::init(); // TODO: lazy init?
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickimaginestyle_p.cpp"
diff --git a/src/quickcontrols2/imagine/qquickimaginestyle_p.h b/src/quickcontrols2/imagine/qquickimaginestyle_p.h
new file mode 100644
index 0000000000..212096b93b
--- /dev/null
+++ b/src/quickcontrols2/imagine/qquickimaginestyle_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKIMAGINESTYLE_P_H
+#define QQUICKIMAGINESTYLE_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/qvariant.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickImagineStyle : public QQuickAttachedObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString path READ path WRITE setPath RESET resetPath NOTIFY pathChanged FINAL)
+ Q_PROPERTY(QUrl url READ url NOTIFY pathChanged FINAL)
+ QML_NAMED_ELEMENT(Imagine)
+ QML_ATTACHED(QQuickImagineStyle)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickImagineStyle(QObject *parent = nullptr);
+
+ static QQuickImagineStyle *qmlAttachedProperties(QObject *object);
+
+ QString path() const;
+ void setPath(const QString &path);
+ void inheritPath(const QString &path);
+ void propagatePath();
+ void resetPath();
+
+ QUrl url() const;
+
+Q_SIGNALS:
+ void pathChanged();
+
+protected:
+ void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+
+private:
+ void init();
+
+ bool m_explicitPath = false;
+ QString m_path;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QQuickImagineStyle, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKIMAGINESTYLE_P_H
diff --git a/src/quickcontrols2/imagine/qquickimaginetheme.cpp b/src/quickcontrols2/imagine/qquickimaginetheme.cpp
new file mode 100644
index 0000000000..7bae036a83
--- /dev/null
+++ b/src/quickcontrols2/imagine/qquickimaginetheme.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickimaginetheme_p.h"
+
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickImagineTheme::initialize(QQuickTheme *theme)
+{
+ QFont systemFont;
+ systemFont.setFamilies(QStringList{QLatin1String("Open Sans")});
+ theme->setFont(QQuickTheme::System, systemFont);
+
+ const QColor accentColor = QColor::fromRgb(0x4fc1e9);
+ const QColor windowTextColor = QColor::fromRgb(0x434a54);
+ const QColor disabledWindowTextColor = QColor::fromRgb(0xccd1d9);
+
+ QPalette systemPalette;
+ systemPalette.setColor(QPalette::ButtonText, Qt::white);
+ systemPalette.setColor(QPalette::BrightText, Qt::white);
+ systemPalette.setColor(QPalette::Highlight, accentColor);
+ systemPalette.setColor(QPalette::HighlightedText, Qt::white);
+ systemPalette.setColor(QPalette::Text, windowTextColor);
+ systemPalette.setColor(QPalette::ToolTipText, Qt::white);
+ systemPalette.setColor(QPalette::WindowText, windowTextColor);
+ systemPalette.setColor(QPalette::Disabled, QPalette::Text, disabledWindowTextColor);
+ systemPalette.setColor(QPalette::Disabled, QPalette::WindowText, disabledWindowTextColor);
+ theme->setPalette(QQuickTheme::System, systemPalette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/imagine/qquickimaginetheme_p.h b/src/quickcontrols2/imagine/qquickimaginetheme_p.h
new file mode 100644
index 0000000000..d3d43074af
--- /dev/null
+++ b/src/quickcontrols2/imagine/qquickimaginetheme_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKIMAGINETHEME_P_H
+#define QQUICKIMAGINETHEME_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 QQuickImagineTheme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKIMAGINETHEME_P_H
diff --git a/src/quickcontrols2/imagine/qtquickcontrols2imaginestyleplugin.cpp b/src/quickcontrols2/imagine/qtquickcontrols2imaginestyleplugin.cpp
new file mode 100644
index 0000000000..43d04ce8c2
--- /dev/null
+++ b/src/quickcontrols2/imagine/qtquickcontrols2imaginestyleplugin.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickimaginestyle_p.h"
+#include "qquickimaginetheme_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+extern void qml_register_types_QtQuick_Controls_Imagine();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Imagine);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2ImagineStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2ImagineStylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+
+ QQuickImagineTheme theme;
+};
+
+QtQuickControls2ImagineStylePlugin::QtQuickControls2ImagineStylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Imagine;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2ImagineStylePlugin::name() const
+{
+ return QStringLiteral("Imagine");
+}
+
+void QtQuickControls2ImagineStylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ this->theme.initialize(theme);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2imaginestyleplugin.moc"
diff --git a/src/quickcontrols2/macos/Button.qml b/src/quickcontrols2/macos/Button.qml
new file mode 100644
index 0000000000..bddaa89ca4
--- /dev/null
+++ b/src/quickcontrols2/macos/Button.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultButton {
+ id: control
+ readonly property Item __focusFrameTarget: control
+
+ font.pixelSize: background.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/CMakeLists.txt b/src/quickcontrols2/macos/CMakeLists.txt
new file mode 100644
index 0000000000..ef608b4460
--- /dev/null
+++ b/src/quickcontrols2/macos/CMakeLists.txt
@@ -0,0 +1,55 @@
+#####################################################################
+## qtquickcontrols2macosstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "Button.qml"
+ "Slider.qml"
+ "GroupBox.qml"
+ "CheckBox.qml"
+ "RadioButton.qml"
+ "SelectionRectangle.qml"
+ "SpinBox.qml"
+ "TextField.qml"
+ "Frame.qml"
+ "TextArea.qml"
+ "ComboBox.qml"
+ "ScrollView.qml"
+ "ScrollBar.qml"
+ "ProgressBar.qml"
+ "Dial.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2macosstyleplugin
+ URI "QtQuick.Controls.macOS"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickControls2MacOSStylePlugin
+ IMPORTS
+ QtQuick.Controls.Fusion/auto
+ PAST_MAJOR_VERSIONS 2
+ PLUGIN_TARGET qtquickcontrols2macosstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qtquickcontrols2macosstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+# Native style is a dependency of the macOS style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2macosstyleplugin
+ qtquickcontrols2nativestyleplugin)
+
+# Fusion style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2macosstyleplugin
+ qtquickcontrols2fusionstyleplugin)
diff --git a/src/quickcontrols2/macos/CheckBox.qml b/src/quickcontrols2/macos/CheckBox.qml
new file mode 100644
index 0000000000..71c880a72e
--- /dev/null
+++ b/src/quickcontrols2/macos/CheckBox.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultCheckBox {
+ id: control
+ readonly property Item __focusFrameTarget: indicator
+ readonly property Item __focusFrameStyleItem: indicator
+
+ font.pixelSize: indicator.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/ComboBox.qml b/src/quickcontrols2/macos/ComboBox.qml
new file mode 100644
index 0000000000..798148e65f
--- /dev/null
+++ b/src/quickcontrols2/macos/ComboBox.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultComboBox {
+ id: control
+ readonly property Item __focusFrameTarget: control
+ font.pixelSize: background.styleFont(control).pixelSize
+
+ contentItem: T.TextField {
+ implicitWidth: contentWidth
+ implicitHeight: contentHeight
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+
+ readonly property Item __focusFrameControl: control
+ }
+}
diff --git a/src/quickcontrols2/macos/Dial.qml b/src/quickcontrols2/macos/Dial.qml
new file mode 100644
index 0000000000..1628bae633
--- /dev/null
+++ b/src/quickcontrols2/macos/Dial.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultDial {
+ id: control
+ font.pixelSize: background.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/Frame.qml b/src/quickcontrols2/macos/Frame.qml
new file mode 100644
index 0000000000..f16a083517
--- /dev/null
+++ b/src/quickcontrols2/macos/Frame.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultFrame {
+}
diff --git a/src/quickcontrols2/macos/GroupBox.qml b/src/quickcontrols2/macos/GroupBox.qml
new file mode 100644
index 0000000000..c066a1577a
--- /dev/null
+++ b/src/quickcontrols2/macos/GroupBox.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultGroupBox {
+ id: control
+ font.pixelSize: background.styleFont(control).pixelSize
+ label: Item {
+ readonly property point labelPos : control.__nativeBackground
+ ? background.labelPos
+ : Qt.point(0,0)
+ x: labelPos.x + background.x
+ y: labelPos.y + background.y - groupBoxPadding.top
+ width: children[0].implicitWidth
+ height: children[0].implicitHeight
+ Text {
+ width: parent.width
+ height: parent.height
+ text: control.title
+ font: control.font
+ color: control.palette.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+}
diff --git a/src/quickcontrols2/macos/ProgressBar.qml b/src/quickcontrols2/macos/ProgressBar.qml
new file mode 100644
index 0000000000..d9c5c02f4f
--- /dev/null
+++ b/src/quickcontrols2/macos/ProgressBar.qml
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultProgressBar {
+ id: control
+ font.pixelSize: background.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/RadioButton.qml b/src/quickcontrols2/macos/RadioButton.qml
new file mode 100644
index 0000000000..38aabae7f5
--- /dev/null
+++ b/src/quickcontrols2/macos/RadioButton.qml
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultRadioButton {
+ id: control
+ readonly property Item __focusFrameTarget: indicator
+ readonly property Item __focusFrameStyleItem: indicator
+ font.pixelSize: indicator.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/ScrollBar.qml b/src/quickcontrols2/macos/ScrollBar.qml
new file mode 100644
index 0000000000..64992346b7
--- /dev/null
+++ b/src/quickcontrols2/macos/ScrollBar.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultScrollBar {
+ id: controlRoot
+ font.pixelSize: background.styleFont(controlRoot).pixelSize
+
+ contentItem: NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.Handle
+ overrideState: NativeStyle.ScrollBar.NeverHovered
+ }
+
+ NativeStyle.ScrollBar {
+ // Fade a hovered-looking version of the handle
+ // on top of the default handle when hovering it
+ x: contentItem.x
+ y: contentItem.y
+ width: contentItem.width
+ height: contentItem.height
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.Handle
+ overrideState: NativeStyle.StyleItem.AlwaysHovered
+ opacity: controlRoot.hovered || control.pressed ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } }
+ }
+
+}
diff --git a/src/quickcontrols2/macos/ScrollView.qml b/src/quickcontrols2/macos/ScrollView.qml
new file mode 100644
index 0000000000..954c5d8aed
--- /dev/null
+++ b/src/quickcontrols2/macos/ScrollView.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ rightPadding: ScrollBar.vertical.visible ? ScrollBar.vertical.width : 0
+ bottomPadding: ScrollBar.horizontal.visible ? ScrollBar.horizontal.height : 0
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: 0
+ height: control.height - (control.ScrollBar.horizontal.visible ? control.ScrollBar.horizontal.height : 0)
+ active: control.ScrollBar.horizontal.active
+
+ NativeStyle.ScrollViewCorner {
+ y: parent.height
+ control: control
+ visible: control.ScrollBar.horizontal.visible
+ useNinePatchImage: false
+ }
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: 0
+ y: control.height - height
+ width: control.width - (control.ScrollBar.vertical.visible ? control.ScrollBar.vertical.width : 0)
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/macos/SelectionRectangle.qml b/src/quickcontrols2/macos/SelectionRectangle.qml
new file mode 100644
index 0000000000..d54b6e9b42
--- /dev/null
+++ b/src/quickcontrols2/macos/SelectionRectangle.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Shapes
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+
+ bottomRightHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+
+}
diff --git a/src/quickcontrols2/macos/Slider.qml b/src/quickcontrols2/macos/Slider.qml
new file mode 100644
index 0000000000..c4c1a8aa36
--- /dev/null
+++ b/src/quickcontrols2/macos/Slider.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultSlider {
+ id: control
+ readonly property Item __focusFrameTarget: handle
+ readonly property Item __focusFrameStyleItem: handle
+ font.pixelSize: background.styleFont(control).pixelSize
+
+ background: NativeStyle.Slider {
+ control: control
+ subControl: NativeStyle.Slider.Groove | NativeStyle.Slider.Handle
+ // We normally cannot use a nine patch image for the
+ // groove if we draw tickmarks (since then the scaling
+ // would scale the tickmarks too). The groove might
+ // also use a different background color before, and
+ // after, the handle.
+ useNinePatchImage: false
+ }
+
+ handle: NativeStyle.Slider {
+ // The handle is hidden, since it will be drawn as a part
+ // of the background. But will still needs it to be here so
+ // that we can place the focus rect correctly.
+ visible: false
+
+ control: control
+ subControl: NativeStyle.Slider.Handle
+ x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+ useNinePatchImage: false
+ }
+}
diff --git a/src/quickcontrols2/macos/SpinBox.qml b/src/quickcontrols2/macos/SpinBox.qml
new file mode 100644
index 0000000000..8816d0ce67
--- /dev/null
+++ b/src/quickcontrols2/macos/SpinBox.qml
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.SpinBox {
+ id: control
+
+ property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+ property bool nativeIndicators: up.indicator.hasOwnProperty("_qt_default")
+ && down.indicator.hasOwnProperty("_qt_default")
+
+ font.pixelSize: background.styleFont(control).pixelSize
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ 90 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight, up.implicitIndicatorHeight + down.implicitIndicatorHeight)
+ + topInset + bottomInset
+
+ spacing: 2
+
+ // Push the background right to make room for the indicators
+ rightInset: nativeIndicators ? up.implicitIndicatorWidth + spacing : 0
+
+ leftPadding: __nativeBackground ? background.contentPadding.left: 0
+ topPadding: __nativeBackground ? background.contentPadding.top: 0
+ rightPadding: (__nativeBackground ? background.contentPadding.right : 0) + rightInset
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom: 0
+
+ readonly property Item __focusFrameTarget: contentItem
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ text: control.displayText
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignLeft
+ verticalAlignment: Qt.AlignVCenter
+
+ topPadding: 2
+ bottomPadding: 2
+ leftPadding: 10
+ rightPadding: 10
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+
+ readonly property Item __focusFrameControl: control
+ }
+
+ NativeStyle.SpinBox {
+ id: upAndDown
+ control: control
+ subControl: NativeStyle.SpinBox.Up
+ visible: nativeIndicators
+ x: up.indicator.x
+ y: up.indicator.y
+ useNinePatchImage: false
+ }
+
+ up.indicator: Item {
+ x: parent.width - width
+ y: (parent.height / 2) - height
+ implicitWidth: upAndDown.width
+ implicitHeight: upAndDown.height / 2
+ property bool _qt_default
+ }
+
+ down.indicator: Item {
+ x: parent.width - width
+ y: up.indicator.y + upAndDown.height / 2
+ implicitWidth: upAndDown.width
+ implicitHeight: upAndDown.height / 2
+ property bool _qt_default
+ }
+
+ background: NativeStyle.SpinBox {
+ control: control
+ subControl: NativeStyle.SpinBox.Frame
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ }
+}
diff --git a/src/quickcontrols2/macos/TextArea.qml b/src/quickcontrols2/macos/TextArea.qml
new file mode 100644
index 0000000000..f6b883038b
--- /dev/null
+++ b/src/quickcontrols2/macos/TextArea.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultTextArea {
+}
diff --git a/src/quickcontrols2/macos/TextField.qml b/src/quickcontrols2/macos/TextField.qml
new file mode 100644
index 0000000000..36567616c1
--- /dev/null
+++ b/src/quickcontrols2/macos/TextField.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultTextField {
+ id: control
+ readonly property Item __focusFrameTarget: control
+ font.pixelSize: background.styleFont(control).pixelSize
+}
diff --git a/src/quickcontrols2/macos/macos.pri b/src/quickcontrols2/macos/macos.pri
new file mode 100644
index 0000000000..4aa939e03a
--- /dev/null
+++ b/src/quickcontrols2/macos/macos.pri
@@ -0,0 +1,16 @@
+QML_FILES += \
+ $$PWD/Button.qml \
+ $$PWD/Slider.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/TextField.qml \
+ $$PWD/Frame.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/Dial.qml \
diff --git a/src/quickcontrols2/macos/qtquickcontrols2macosstyleplugin.cpp b/src/quickcontrols2/macos/qtquickcontrols2macosstyleplugin.cpp
new file mode 100644
index 0000000000..adec72bb2c
--- /dev/null
+++ b/src/quickcontrols2/macos/qtquickcontrols2macosstyleplugin.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+extern void qml_register_types_QtQuick_Controls_macOS();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_macOS);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2MacOSStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2MacOSStylePlugin(QObject *parent = nullptr);
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+};
+
+
+QtQuickControls2MacOSStylePlugin::QtQuickControls2MacOSStylePlugin(QObject *parent):
+ QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_macOS;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2MacOSStylePlugin::name() const
+{
+ return QStringLiteral("macOS");
+}
+
+void QtQuickControls2MacOSStylePlugin::initializeTheme(QQuickTheme */*theme*/)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2macosstyleplugin.moc"
diff --git a/src/quickcontrols2/material/ApplicationWindow.qml b/src/quickcontrols2/material/ApplicationWindow.qml
new file mode 100644
index 0000000000..82a0da8b3a
--- /dev/null
+++ b/src/quickcontrols2/material/ApplicationWindow.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.ApplicationWindow {
+ id: window
+
+ color: Material.backgroundColor
+}
diff --git a/src/quickcontrols2/material/BusyIndicator.qml b/src/quickcontrols2/material/BusyIndicator.qml
new file mode 100644
index 0000000000..621b2b434a
--- /dev/null
+++ b/src/quickcontrols2/material/BusyIndicator.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.BusyIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ contentItem: BusyIndicatorImpl {
+ implicitWidth: control.Material.touchTarget
+ implicitHeight: control.Material.touchTarget
+ color: control.Material.accentColor
+
+ running: control.running
+ opacity: control.running ? 1 : 0
+ Behavior on opacity { OpacityAnimator { duration: 250 } }
+ }
+}
diff --git a/src/quickcontrols2/material/Button.qml b/src/quickcontrols2/material/Button.qml
new file mode 100644
index 0000000000..80454c6493
--- /dev/null
+++ b/src/quickcontrols2/material/Button.qml
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topInset: 6
+ bottomInset: 6
+ padding: 12
+ horizontalPadding: padding - 4
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: !enabled ? Material.hintTextColor :
+ flat && highlighted ? Material.accentColor :
+ highlighted ? Material.primaryHighlightedTextColor : Material.foreground
+
+ Material.elevation: flat ? control.down || (enabled && control.hovered) ? 2 : 0
+ : control.down ? 8 : 2
+ Material.background: flat ? "transparent" : undefined
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Material.hintTextColor :
+ control.flat && control.highlighted ? control.Material.accentColor :
+ control.highlighted ? control.Material.primaryHighlightedTextColor : control.Material.foreground
+ }
+
+ background: Rectangle {
+ implicitWidth: 64
+ implicitHeight: control.Material.buttonHeight
+
+ radius: 2
+ color: !control.enabled ? control.Material.buttonDisabledColor :
+ control.highlighted ? (control.checked ? control.Material.highlightedCheckedButtonColor :
+ control.Material.highlightedButtonColor) : control.Material.buttonColor
+
+ PaddedRectangle {
+ y: parent.height - 4
+ width: parent.width
+ height: 4
+ radius: 2
+ topPadding: -2
+ clip: true
+ visible: control.checkable && (!control.highlighted || control.flat)
+ color: control.checked && control.enabled ? control.Material.accentColor : control.Material.secondaryTextColor
+ }
+
+ // The layer is disabled when the button color is transparent so you can do
+ // Material.background: "transparent" and get a proper flat button without needing
+ // to set Material.elevation as well
+ layer.enabled: control.enabled && control.Material.buttonColor.a > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+
+ Ripple {
+ clipRadius: 2
+ width: parent.width
+ height: parent.height
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.flat && control.highlighted ? control.Material.highlightedRippleColor : control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/CMakeLists.txt b/src/quickcontrols2/material/CMakeLists.txt
new file mode 100644
index 0000000000..cd2a71c508
--- /dev/null
+++ b/src/quickcontrols2/material/CMakeLists.txt
@@ -0,0 +1,152 @@
+#####################################################################
+## qtquickcontrols2materialstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "BusyIndicator.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "CheckDelegate.qml"
+ "ComboBox.qml"
+ "DelayButton.qml"
+ "Dial.qml"
+ "Dialog.qml"
+ "DialogButtonBox.qml"
+ "Drawer.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "HorizontalHeaderView.qml"
+ "ItemDelegate.qml"
+ "Label.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
+ "Page.qml"
+ "PageIndicator.qml"
+ "Pane.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RadioDelegate.qml"
+ "RangeSlider.qml"
+ "RoundButton.qml"
+ "ScrollView.qml"
+ "ScrollBar.qml"
+ "ScrollIndicator.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "SplitView.qml"
+ "StackView.qml"
+ "SwipeDelegate.qml"
+ "SwipeView.qml"
+ "Switch.qml"
+ "SwitchDelegate.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "TextArea.qml"
+ "TextField.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "ToolSeparator.qml"
+ "ToolTip.qml"
+ "Tumbler.qml"
+ "VerticalHeaderView.qml"
+)
+set_source_files_properties(DelayButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(Dialog.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(DialogButtonBox.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(HorizontalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+set_source_files_properties(MenuBar.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuBarItem.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(RoundButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(SplitView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.13;6.0"
+)
+set_source_files_properties(ToolSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(VerticalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2materialstyleplugin
+ URI "QtQuick.Controls.Material"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2MaterialStylePlugin
+ IMPORTS
+ QtQuick.Controls.Basic/auto
+ PLUGIN_TARGET qtquickcontrols2materialstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickmaterialstyle.cpp qquickmaterialstyle_p.h
+ qquickmaterialtheme.cpp qquickmaterialtheme_p.h
+ qtquickcontrols2materialstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_internal_add_resource(qtquickcontrols2materialstyleplugin "qtquickcontrols2materialstyleplugin"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/Material"
+ FILES
+ "images/arrow-indicator.png"
+ "images/arrow-indicator@2x.png"
+ "images/arrow-indicator@3x.png"
+ "images/arrow-indicator@4x.png"
+ "images/check.png"
+ "images/check@2x.png"
+ "images/check@3x.png"
+ "images/check@4x.png"
+ "images/drop-indicator.png"
+ "images/drop-indicator@2x.png"
+ "images/drop-indicator@3x.png"
+ "images/drop-indicator@4x.png"
+ "shaders/+glslcore/RectangularGlow.frag"
+ "shaders/+hlsl/RectangularGlow.frag"
+ "shaders/+qsb/RectangularGlow.frag"
+ "shaders/RectangularGlow.frag"
+)
+
+add_subdirectory(impl)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2materialstyleplugin quickwindow)
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2materialstyleplugin
+ qtquickcontrols2materialstyleimplplugin)
+
+# Basic style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2materialstyleplugin
+ qtquickcontrols2basicstyleplugin)
diff --git a/src/quickcontrols2/material/CheckBox.qml b/src/quickcontrols2/material/CheckBox.qml
new file mode 100644
index 0000000000..02f195cad6
--- /dev/null
+++ b/src/quickcontrols2/material/CheckBox.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+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: 8
+ padding: 8
+ verticalPadding: padding + 7
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+
+ Ripple {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 28; height: 28
+
+ z: -1
+ anchor: control
+ pressed: control.pressed
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.checked ? control.Material.highlightedRippleColor : control.Material.rippleColor
+ }
+ }
+
+ 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.enabled ? control.Material.foreground : control.Material.hintTextColor
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/material/CheckDelegate.qml b/src/quickcontrols2/material/CheckDelegate.qml
new file mode 100644
index 0000000000..15bf74fbf9
--- /dev/null
+++ b/src/quickcontrols2/material/CheckDelegate.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.CheckDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: 8
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/ComboBox.qml b/src/quickcontrols2/material/ComboBox.qml
new file mode 100644
index 0000000000..6f09ae3ce3
--- /dev/null
+++ b/src/quickcontrols2/material/ComboBox.qml
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ topInset: 6
+ bottomInset: 6
+
+ leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+ rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+
+ Material.elevation: flat ? control.pressed || (enabled && control.hovered) ? 2 : 0
+ : control.pressed ? 8 : 2
+ Material.background: flat ? "transparent" : undefined
+ Material.foreground: flat ? undefined : Material.primaryTextColor
+
+ delegate: MenuItem {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ Material.foreground: control.currentIndex === index ? ListView.view.contentItem.Material.accent : ListView.view.contentItem.Material.foreground
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Material/images/drop-indicator.png"
+ }
+
+ contentItem: T.TextField {
+ padding: 6
+ leftPadding: control.editable ? 2 : control.mirrored ? 0 : 12
+ rightPadding: control.editable ? 2 : control.mirrored ? 12 : 0
+
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ selectionColor: control.Material.accentColor
+ selectedTextColor: control.Material.primaryHighlightedTextColor
+ verticalAlignment: Text.AlignVCenter
+
+ cursorDelegate: CursorDelegate { }
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: control.Material.buttonHeight
+
+ radius: control.flat ? 0 : 2
+ color: !control.editable ? control.Material.dialogColor : "transparent"
+
+ layer.enabled: control.enabled && !control.editable && control.Material.background.a > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+
+ Rectangle {
+ visible: control.editable
+ y: parent.y + control.baselineOffset
+ width: parent.width
+ height: control.activeFocus ? 2 : 1
+ color: control.editable && control.activeFocus ? control.Material.accentColor : control.Material.hintTextColor
+ }
+
+ Ripple {
+ clip: control.flat
+ clipRadius: control.flat ? 0 : 2
+ x: control.editable && control.indicator ? control.indicator.x : 0
+ width: control.editable && control.indicator ? control.indicator.width : parent.width
+ height: parent.height
+ pressed: control.pressed
+ anchor: control.editable && control.indicator ? control.indicator : control
+ active: enabled && (control.pressed || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+ }
+
+ popup: T.Popup {
+ y: control.editable ? control.height - 5 : 0
+ width: control.width
+ height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
+ transformOrigin: Item.Top
+ topMargin: 12
+ bottomMargin: 12
+
+ Material.theme: control.Material.theme
+ Material.accent: control.Material.accent
+ Material.primary: control.Material.primary
+
+ enter: Transition {
+ // grow_fade_in
+ NumberAnimation { property: "scale"; from: 0.9; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 0.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ exit: Transition {
+ // shrink_fade_out
+ NumberAnimation { property: "scale"; to: 0.9; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; to: 0.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ radius: 2
+ color: parent.Material.dialogColor
+
+ layer.enabled: control.enabled
+ layer.effect: ElevationEffect {
+ elevation: 8
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/DelayButton.qml b/src/quickcontrols2/material/DelayButton.qml
new file mode 100644
index 0000000000..57d1d2733a
--- /dev/null
+++ b/src/quickcontrols2/material/DelayButton.qml
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.DelayButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topInset: 6
+ bottomInset: 6
+ padding: 12
+ horizontalPadding: padding - 4
+
+ Material.elevation: control.down ? 8 : 2
+
+ transition: Transition {
+ NumberAnimation {
+ duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress)
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Material.hintTextColor : control.Material.foreground
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ elide: Text.ElideRight
+ }
+
+ // TODO: Add a proper ripple/ink effect for mouse/touch input and focus state
+ background: Rectangle {
+ implicitWidth: 64
+ implicitHeight: control.Material.buttonHeight
+
+ radius: 2
+ color: !control.enabled ? control.Material.buttonDisabledColor : control.Material.buttonColor
+
+ PaddedRectangle {
+ y: parent.height - 4
+ width: parent.width
+ height: 4
+ radius: 2
+ topPadding: -2
+ clip: true
+ color: control.checked && control.enabled ? control.Material.accentColor : control.Material.secondaryTextColor
+
+ PaddedRectangle {
+ width: parent.width * control.progress
+ height: 4
+ radius: 2
+ topPadding: -2
+ rightPadding: Math.max(-2, width - parent.width)
+ clip: true
+ color: control.Material.accentColor
+ }
+ }
+
+ layer.enabled: control.enabled && control.Material.buttonColor.a > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+
+ Ripple {
+ clipRadius: 2
+ width: parent.width
+ height: parent.height
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/Dial.qml b/src/quickcontrols2/material/Dial.qml
new file mode 100644
index 0000000000..2731436f60
--- /dev/null
+++ b/src/quickcontrols2/material/Dial.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Dial {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+
+ x: control.width / 2 - width / 2
+ y: control.height / 2 - height / 2
+ width: Math.max(64, Math.min(control.width, control.height))
+ height: width
+ color: "transparent"
+ radius: width / 2
+
+ border.color: control.enabled ? control.Material.accentColor : control.Material.hintTextColor
+ }
+
+ handle: SliderHandle {
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+ transform: [
+ Translate {
+ y: -control.background.height * 0.4 + control.handle.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: control.handle.width / 2
+ origin.y: control.handle.height / 2
+ }
+ ]
+ implicitWidth: 10
+ implicitHeight: 10
+
+ value: control.value
+ handleHasFocus: control.visualFocus
+ handlePressed: control.pressed
+ handleHovered: control.hovered
+ }
+}
diff --git a/src/quickcontrols2/material/Dialog.qml b/src/quickcontrols2/material/Dialog.qml
new file mode 100644
index 0000000000..1cb7f8c186
--- /dev/null
+++ b/src/quickcontrols2/material/Dialog.qml
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Dialog {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 24
+ topPadding: 20
+
+ Material.elevation: 24
+
+ enter: Transition {
+ // grow_fade_in
+ NumberAnimation { property: "scale"; from: 0.9; to: 1.0; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ exit: Transition {
+ // shrink_fade_out
+ NumberAnimation { property: "scale"; from: 1.0; to: 0.9; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ background: Rectangle {
+ radius: 2
+ color: control.Material.dialogColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title
+ elide: Label.ElideRight
+ padding: 24
+ bottomPadding: 0
+ // TODO: QPlatformTheme::TitleBarFont
+ font.bold: true
+ font.pixelSize: 16
+ background: PaddedRectangle {
+ radius: 2
+ color: control.Material.dialogColor
+ bottomPadding: -2
+ clip: true
+ }
+ }
+
+ footer: DialogButtonBox {
+ visible: count > 0
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+}
diff --git a/src/quickcontrols2/material/DialogButtonBox.qml b/src/quickcontrols2/material/DialogButtonBox.qml
new file mode 100644
index 0000000000..fac209c87b
--- /dev/null
+++ b/src/quickcontrols2/material/DialogButtonBox.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.DialogButtonBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 8
+ padding: 8
+ verticalPadding: 2
+ alignment: Qt.AlignRight
+ buttonLayout: T.DialogButtonBox.AndroidLayout
+
+ Material.foreground: Material.accent
+
+ delegate: Button { flat: true }
+
+ contentItem: ListView {
+ implicitWidth: contentWidth
+ model: control.contentModel
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ snapMode: ListView.SnapToItem
+ }
+
+ background: PaddedRectangle {
+ implicitHeight: control.Material.dialogButtonBoxHeight
+ radius: 2
+ color: control.Material.dialogColor
+ // Rounded corners should be only at the top or at the bottom
+ topPadding: control.position === T.DialogButtonBox.Footer ? -2 : 0
+ bottomPadding: control.position === T.DialogButtonBox.Header ? -2 : 0
+ clip: true
+ }
+}
diff --git a/src/quickcontrols2/material/Drawer.qml b/src/quickcontrols2/material/Drawer.qml
new file mode 100644
index 0000000000..93c4bf5698
--- /dev/null
+++ b/src/quickcontrols2/material/Drawer.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Drawer {
+ id: control
+
+ parent: T.Overlay.overlay
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: !dim && edge === Qt.BottomEdge && Material.elevation === 0
+ leftPadding: !dim && edge === Qt.RightEdge && Material.elevation === 0
+ rightPadding: !dim && edge === Qt.LeftEdge && Material.elevation === 0
+ bottomPadding: !dim && edge === Qt.TopEdge && Material.elevation === 0
+
+ enter: Transition { SmoothedAnimation { velocity: 5 } }
+ exit: Transition { SmoothedAnimation { velocity: 5 } }
+
+ Material.elevation: !interactive && !dim ? 0 : 16
+
+ background: Rectangle {
+ color: control.Material.dialogColor
+
+ Rectangle {
+ readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge
+ width: horizontal ? 1 : parent.width
+ height: horizontal ? parent.height : 1
+ color: control.Material.dividerColor
+ x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0
+ y: control.edge === Qt.TopEdge ? parent.height - 1 : 0
+ visible: !control.dim && control.Material.elevation === 0
+ }
+
+ layer.enabled: control.position > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ fullHeight: true
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+}
diff --git a/src/quickcontrols2/material/Frame.qml b/src/quickcontrols2/material/Frame.qml
new file mode 100644
index 0000000000..8626f7661a
--- /dev/null
+++ b/src/quickcontrols2/material/Frame.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+ verticalPadding: Material.frameVerticalPadding
+
+ background: Rectangle {
+ radius: 2
+ color: control.Material.elevation > 0 ? control.Material.backgroundColor : "transparent"
+ border.color: control.Material.frameColor
+
+ layer.enabled: control.enabled && control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/GroupBox.qml b/src/quickcontrols2/material/GroupBox.qml
new file mode 100644
index 0000000000..4a27b83241
--- /dev/null
+++ b/src/quickcontrols2/material/GroupBox.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 6
+ padding: 12
+ topPadding: Material.frameVerticalPadding + (implicitLabelWidth > 0 ? implicitLabelHeight + spacing : 0)
+ bottomPadding: Material.frameVerticalPadding
+
+ label: Text {
+ x: control.leftPadding
+ width: control.availableWidth
+
+ text: control.title
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ y: control.topPadding - control.bottomPadding
+ width: parent.width
+ height: parent.height - control.topPadding + control.bottomPadding
+
+ radius: 2
+ color: control.Material.elevation > 0 ? control.Material.backgroundColor : "transparent"
+ border.color: control.Material.frameColor
+
+ layer.enabled: control.enabled && control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/HorizontalHeaderView.qml b/src/quickcontrols2/material/HorizontalHeaderView.qml
new file mode 100644
index 0000000000..d2608c76bc
--- /dev/null
+++ b/src/quickcontrols2/material/HorizontalHeaderView.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.HorizontalHeaderView {
+ id: control
+
+ implicitWidth: syncView ? syncView.width : 0
+ implicitHeight: contentHeight
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: text.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(control.height, text.implicitHeight + (cellPadding * 2))
+ color: control.Material.backgroundColor
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/ItemDelegate.qml b/src/quickcontrols2/material/ItemDelegate.qml
new file mode 100644
index 0000000000..4230bccf2f
--- /dev/null
+++ b/src/quickcontrols2/material/ItemDelegate.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: 8
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/LICENSE_ANGULARJS.txt b/src/quickcontrols2/material/LICENSE_ANGULARJS.txt
new file mode 100644
index 0000000000..c1f2a826bb
--- /dev/null
+++ b/src/quickcontrols2/material/LICENSE_ANGULARJS.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2014-2016 Google, Inc. http://angularjs.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/quickcontrols2/material/Label.qml b/src/quickcontrols2/material/Label.qml
new file mode 100644
index 0000000000..77e85f4297
--- /dev/null
+++ b/src/quickcontrols2/material/Label.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.Label {
+ id: control
+
+ color: enabled ? Material.foreground : Material.hintTextColor
+ linkColor: Material.accentColor
+}
diff --git a/src/quickcontrols2/material/Menu.qml b/src/quickcontrols2/material/Menu.qml
new file mode 100644
index 0000000000..b7e80c92ef
--- /dev/null
+++ b/src/quickcontrols2/material/Menu.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+import QtQuick.Window
+
+T.Menu {
+ id: control
+
+ Material.elevation: 8
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 0
+ verticalPadding: 8
+
+ transformOrigin: !cascade ? Item.Top : (mirrored ? Item.TopRight : Item.TopLeft)
+
+ delegate: MenuItem { }
+
+ enter: Transition {
+ // grow_fade_in
+ NumberAnimation { property: "scale"; from: 0.9; to: 1.0; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ exit: Transition {
+ // shrink_fade_out
+ NumberAnimation { property: "scale"; from: 1.0; to: 0.9; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height
+ : false
+ clip: true
+ currentIndex: control.currentIndex
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: control.Material.menuItemHeight
+
+ radius: 3
+ color: control.Material.dialogColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+}
diff --git a/src/quickcontrols2/material/MenuBar.qml b/src/quickcontrols2/material/MenuBar.qml
new file mode 100644
index 0000000000..a0c3bd3fc5
--- /dev/null
+++ b/src/quickcontrols2/material/MenuBar.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: control.Material.dialogColor
+ }
+}
diff --git a/src/quickcontrols2/material/MenuBarItem.qml b/src/quickcontrols2/material/MenuBarItem.qml
new file mode 100644
index 0000000000..f1d4e87d8a
--- /dev/null
+++ b/src/quickcontrols2/material/MenuBarItem.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.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)
+
+ padding: 16
+ verticalPadding: 12
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ 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.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: control.down || control.highlighted
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/MenuItem.qml b/src/quickcontrols2/material/MenuItem.qml
new file mode 100644
index 0000000000..fab2de2696
--- /dev/null
+++ b/src/quickcontrols2/material/MenuItem.qml
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.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)
+
+ padding: 16
+ verticalPadding: Material.menuItemVerticalPadding
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ visible: control.checkable
+ control: control
+ checkState: control.checked ? Qt.Checked : Qt.Unchecked
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.subMenu
+ mirror: control.mirrored
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Material/images/arrow-indicator.png"
+ }
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+ leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
+ rightPadding: control.mirrored ? indicatorPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: control.Material.menuItemHeight
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: control.down || control.highlighted
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/MenuSeparator.qml b/src/quickcontrols2/material/MenuSeparator.qml
new file mode 100644
index 0000000000..08a33ffe15
--- /dev/null
+++ b/src/quickcontrols2/material/MenuSeparator.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ verticalPadding: 8
+
+ contentItem: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 1
+ color: control.Material.dividerColor
+ }
+}
diff --git a/src/quickcontrols2/material/Page.qml b/src/quickcontrols2/material/Page.qml
new file mode 100644
index 0000000000..711fac2ddb
--- /dev/null
+++ b/src/quickcontrols2/material/Page.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.Page {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ background: Rectangle {
+ color: control.Material.backgroundColor
+ }
+}
diff --git a/src/quickcontrols2/material/PageIndicator.qml b/src/quickcontrols2/material/PageIndicator.qml
new file mode 100644
index 0000000000..161b7b2d83
--- /dev/null
+++ b/src/quickcontrols2/material/PageIndicator.qml
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.PageIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ delegate: Rectangle {
+ implicitWidth: 8
+ implicitHeight: 8
+
+ radius: width / 2
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+
+ // qmllint disable unqualified
+ // We can't make "pressed" a required property, as QQuickPageIndicator doesn't create
+ // the delegates, and so it can't set it as an initial property.
+ opacity: index === control.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
+
+ required property int index
+
+ Behavior on opacity { OpacityAnimator { duration: 100 } }
+ }
+
+ contentItem: Row {
+ spacing: control.spacing
+
+ Repeater {
+ model: control.count
+ delegate: control.delegate
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/Pane.qml b/src/quickcontrols2/material/Pane.qml
new file mode 100644
index 0000000000..055a8d236d
--- /dev/null
+++ b/src/quickcontrols2/material/Pane.qml
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Pane {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.Material.backgroundColor
+ radius: control.Material.elevation > 0 ? 2 : 0
+
+ layer.enabled: control.enabled && control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/Popup.qml b/src/quickcontrols2/material/Popup.qml
new file mode 100644
index 0000000000..cb5b62ece7
--- /dev/null
+++ b/src/quickcontrols2/material/Popup.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Popup {
+ id: control
+
+ Material.elevation: 24
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ enter: Transition {
+ // grow_fade_in
+ NumberAnimation { property: "scale"; from: 0.9; to: 1.0; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ exit: Transition {
+ // shrink_fade_out
+ NumberAnimation { property: "scale"; from: 1.0; to: 0.9; easing.type: Easing.OutQuint; duration: 220 }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.OutCubic; duration: 150 }
+ }
+
+ background: Rectangle {
+ radius: 2
+ color: control.Material.dialogColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Material.backgroundDimColor
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+}
diff --git a/src/quickcontrols2/material/ProgressBar.qml b/src/quickcontrols2/material/ProgressBar.qml
new file mode 100644
index 0000000000..dd4fae0e36
--- /dev/null
+++ b/src/quickcontrols2/material/ProgressBar.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: ProgressBarImpl {
+ implicitHeight: 4
+
+ scale: control.mirrored ? -1 : 1
+ color: control.Material.accentColor
+ progress: control.position
+ indeterminate: control.visible && control.indeterminate
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 4
+ y: (control.height - height) / 2
+ height: 4
+
+ color: Qt.rgba(control.Material.accentColor.r, control.Material.accentColor.g, control.Material.accentColor.b, 0.25)
+ }
+}
diff --git a/src/quickcontrols2/material/RadioButton.qml b/src/quickcontrols2/material/RadioButton.qml
new file mode 100644
index 0000000000..664cb19ecd
--- /dev/null
+++ b/src/quickcontrols2/material/RadioButton.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+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: 8
+ padding: 8
+ verticalPadding: padding + 6
+
+ indicator: RadioIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+
+ Ripple {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 28; height: 28
+
+ z: -1
+ anchor: control
+ pressed: control.pressed
+ active: control.down || control.visualFocus || control.hovered
+ color: control.checked ? control.Material.highlightedRippleColor : control.Material.rippleColor
+ }
+ }
+
+ 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.enabled ? control.Material.foreground : control.Material.hintTextColor
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/material/RadioDelegate.qml b/src/quickcontrols2/material/RadioDelegate.qml
new file mode 100644
index 0000000000..334e570bbf
--- /dev/null
+++ b/src/quickcontrols2/material/RadioDelegate.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.RadioDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: 8
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ indicator: RadioIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: control.down || control.visualFocus || control.hovered
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/RangeSlider.qml b/src/quickcontrols2/material/RangeSlider.qml
new file mode 100644
index 0000000000..a6bb0c69a2
--- /dev/null
+++ b/src/quickcontrols2/material/RangeSlider.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+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)
+
+ padding: 6
+
+ first.handle: SliderHandle {
+ x: control.leftPadding + (control.horizontal ? control.first.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.first.visualPosition * (control.availableHeight - height))
+ value: control.first.value
+ handleHasFocus: activeFocus
+ handlePressed: control.first.pressed
+ handleHovered: control.first.hovered
+ }
+
+ second.handle: SliderHandle {
+ x: control.leftPadding + (control.horizontal ? control.second.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.second.visualPosition * (control.availableHeight - height))
+ value: control.second.value
+ handleHasFocus: activeFocus
+ handlePressed: control.second.pressed
+ handleHovered: control.second.hovered
+ }
+
+ background: Rectangle {
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ implicitWidth: control.horizontal ? 200 : 48
+ implicitHeight: control.horizontal ? 48 : 200
+ width: control.horizontal ? control.availableWidth : 4
+ height: control.horizontal ? 4 : control.availableHeight
+ scale: control.horizontal && control.mirrored ? -1 : 1
+ color: control.enabled ? Color.transparent(control.Material.accentColor, 0.33) : control.Material.sliderDisabledColor
+
+ Rectangle {
+ x: control.horizontal ? control.first.position * parent.width : 0
+ y: control.horizontal ? 0 : control.second.visualPosition * parent.height
+ width: control.horizontal ? control.second.position * parent.width - control.first.position * parent.width : 4
+ height: control.horizontal ? 4 : control.second.position * parent.height - control.first.position * parent.height
+
+ color: control.enabled ? control.Material.accentColor : control.Material.sliderDisabledColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/RoundButton.qml b/src/quickcontrols2/material/RoundButton.qml
new file mode 100644
index 0000000000..ff54b2699b
--- /dev/null
+++ b/src/quickcontrols2/material/RoundButton.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.RoundButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ topInset: 6
+ leftInset: 6
+ rightInset: 6
+ bottomInset: 6
+ padding: 12
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: !enabled ? Material.hintTextColor :
+ flat && highlighted ? Material.accentColor :
+ highlighted ? Material.primaryHighlightedTextColor : Material.foreground
+
+ Material.elevation: flat ? control.down || control.hovered ? 2 : 0
+ : control.down ? 12 : 6
+ Material.background: flat ? "transparent" : undefined
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Material.hintTextColor :
+ control.flat && control.highlighted ? control.Material.accentColor :
+ control.highlighted ? control.Material.primaryHighlightedTextColor : control.Material.foreground
+ }
+
+ // TODO: Add a proper ripple/ink effect for mouse/touch input and focus state
+ background: Rectangle {
+ implicitWidth: control.Material.buttonHeight
+ implicitHeight: control.Material.buttonHeight
+
+ radius: control.radius
+ color: !control.enabled ? control.Material.buttonDisabledColor
+ : control.checked || control.highlighted ? control.Material.highlightedButtonColor : control.Material.buttonColor
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ radius: control.radius
+ visible: enabled && (control.hovered || control.visualFocus)
+ color: control.Material.rippleColor
+ }
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ radius: control.radius
+ visible: control.down
+ color: control.Material.rippleColor
+ }
+
+ // The layer is disabled when the button color is transparent so that you can do
+ // Material.background: "transparent" and get a proper flat button without needing
+ // to set Material.elevation as well
+ layer.enabled: control.enabled && control.Material.buttonColor.a > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/ScrollBar.qml b/src/quickcontrols2/material/ScrollBar.qml
new file mode 100644
index 0000000000..e89452174c
--- /dev/null
+++ b/src/quickcontrols2/material/ScrollBar.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.ScrollBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: control.interactive ? 1 : 2
+ visible: control.policy !== T.ScrollBar.AlwaysOff
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ contentItem: Rectangle {
+ implicitWidth: control.interactive ? 13 : 4
+ implicitHeight: control.interactive ? 13 : 4
+
+ color: control.pressed ? control.Material.scrollBarPressedColor :
+ control.interactive && control.hovered ? control.Material.scrollBarHoveredColor : control.Material.scrollBarColor
+ opacity: 0.0
+ }
+
+ background: Rectangle {
+ implicitWidth: control.interactive ? 16 : 4
+ implicitHeight: control.interactive ? 16 : 4
+ color: "#0e000000"
+ opacity: 0.0
+ visible: control.interactive
+ }
+
+ states: State {
+ name: "active"
+ when: control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
+ }
+
+ transitions: [
+ Transition {
+ to: "active"
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 1.0 }
+ },
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PropertyAction{ targets: [control.contentItem, control.background]; property: "opacity"; value: 1.0 }
+ PauseAnimation { duration: 2450 }
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+}
diff --git a/src/quickcontrols2/material/ScrollIndicator.qml b/src/quickcontrols2/material/ScrollIndicator.qml
new file mode 100644
index 0000000000..bc81c630ee
--- /dev/null
+++ b/src/quickcontrols2/material/ScrollIndicator.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+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: 4
+ implicitHeight: 4
+
+ color: control.Material.scrollBarColor
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: State {
+ name: "active"
+ when: control.active
+ PropertyChanges { target: 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/quickcontrols2/material/ScrollView.qml b/src/quickcontrols2/material/ScrollView.qml
new file mode 100644
index 0000000000..a6bba9de05
--- /dev/null
+++ b/src/quickcontrols2/material/ScrollView.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/material/SelectionRectangle.qml b/src/quickcontrols2/material/SelectionRectangle.qml
new file mode 100644
index 0000000000..f31057dc7b
--- /dev/null
+++ b/src/quickcontrols2/material/SelectionRectangle.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: handle
+ bottomRightHandle: handle
+
+ Component {
+ id: handle
+ SliderHandle {
+ palette: SelectionRectangle.control.palette
+ handlePressed: tapHandler.pressed || SelectionRectangle.dragging
+ handleHovered: hoverHandler.hovered
+ visible: SelectionRectangle.control.active
+
+ HoverHandler {
+ id: hoverHandler
+ }
+
+ TapHandler {
+ id: tapHandler
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/Slider.qml b/src/quickcontrols2/material/Slider.qml
new file mode 100644
index 0000000000..2a36673434
--- /dev/null
+++ b/src/quickcontrols2/material/Slider.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ handle: SliderHandle {
+ x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+ value: control.value
+ handleHasFocus: control.visualFocus
+ handlePressed: control.pressed
+ handleHovered: control.hovered
+ }
+
+ background: Rectangle {
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ implicitWidth: control.horizontal ? 200 : 48
+ implicitHeight: control.horizontal ? 48 : 200
+ width: control.horizontal ? control.availableWidth : 4
+ height: control.horizontal ? 4 : control.availableHeight
+ scale: control.horizontal && control.mirrored ? -1 : 1
+ color: control.enabled ? Color.transparent(control.Material.accentColor, 0.33) : control.Material.sliderDisabledColor
+
+ Rectangle {
+ x: control.horizontal ? 0 : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : control.visualPosition * parent.height
+ width: control.horizontal ? control.position * parent.width : 4
+ height: control.horizontal ? 4 : control.position * parent.height
+
+ color: control.enabled ? control.Material.accentColor : control.Material.sliderDisabledColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/SpinBox.qml b/src/quickcontrols2/material/SpinBox.qml
new file mode 100644
index 0000000000..9ea6fd9260
--- /dev/null
+++ b/src/quickcontrols2/material/SpinBox.qml
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth +
+ up.implicitIndicatorWidth +
+ down.implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight,
+ up.implicitIndicatorHeight,
+ down.implicitIndicatorHeight)
+
+ spacing: 6
+ topPadding: 8
+ bottomPadding: 16
+ leftPadding: (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ text: control.displayText
+
+ font: control.font
+ color: enabled ? control.Material.foreground : control.Material.hintTextColor
+ selectionColor: control.Material.textSelectionColor
+ selectedTextColor: control.Material.foreground
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+
+ cursorDelegate: CursorDelegate { }
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+ }
+
+ up.indicator: Item {
+ x: control.mirrored ? 0 : control.width - width
+ implicitWidth: control.Material.touchTarget
+ implicitHeight: control.Material.touchTarget
+ height: control.height
+ width: height
+
+ Ripple {
+ clipRadius: 2
+ x: control.spacing
+ y: control.spacing
+ width: parent.width - 2 * control.spacing
+ height: parent.height - 2 * control.spacing
+ pressed: control.up.pressed
+ active: control.up.pressed || control.up.hovered || control.visualFocus
+ color: control.Material.rippleColor
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: Math.min(parent.width / 3, parent.height / 3)
+ height: 2
+ color: enabled ? control.Material.foreground : control.Material.spinBoxDisabledIconColor
+ }
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 2
+ height: Math.min(parent.width / 3, parent.height / 3)
+ color: enabled ? control.Material.foreground : control.Material.spinBoxDisabledIconColor
+ }
+ }
+
+ down.indicator: Item {
+ x: control.mirrored ? control.width - width : 0
+ implicitWidth: control.Material.touchTarget
+ implicitHeight: control.Material.touchTarget
+ height: control.height
+ width: height
+
+ Ripple {
+ clipRadius: 2
+ x: control.spacing
+ y: control.spacing
+ width: parent.width - 2 * control.spacing
+ height: parent.height - 2 * control.spacing
+ pressed: control.down.pressed
+ active: control.down.pressed || control.down.hovered || control.visualFocus
+ color: control.Material.rippleColor
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 3
+ height: 2
+ color: enabled ? control.Material.foreground : control.Material.spinBoxDisabledIconColor
+ }
+ }
+
+ background: Item {
+ implicitWidth: 192
+ implicitHeight: control.Material.touchTarget
+
+ Rectangle {
+ x: parent.width / 2 - width / 2
+ y: parent.y + parent.height - height - control.bottomPadding / 2
+ width: control.availableWidth
+ height: control.activeFocus ? 2 : 1
+ color: control.activeFocus ? control.Material.accentColor : control.Material.hintTextColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/SplitView.qml b/src/quickcontrols2/material/SplitView.qml
new file mode 100644
index 0000000000..95556cd091
--- /dev/null
+++ b/src/quickcontrols2/material/SplitView.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+
+T.SplitView {
+ id: control
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ handle: Rectangle {
+ implicitWidth: control.orientation === Qt.Horizontal ? 6 : control.width
+ implicitHeight: control.orientation === Qt.Horizontal ? control.height : 6
+ color: T.SplitHandle.pressed ? control.Material.background
+ : Qt.lighter(control.Material.background, T.SplitHandle.hovered ? 1.2 : 1.1)
+
+ Rectangle {
+ color: control.Material.secondaryTextColor
+ width: control.orientation === Qt.Horizontal ? thickness : length
+ height: control.orientation === Qt.Horizontal ? length : thickness
+ radius: thickness
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ property int length: parent.T.SplitHandle.pressed ? 3 : 8
+ readonly property int thickness: parent.T.SplitHandle.pressed ? 3 : 1
+
+ Behavior on length {
+ NumberAnimation {
+ duration: 100
+ }
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/StackView.qml b/src/quickcontrols2/material/StackView.qml
new file mode 100644
index 0000000000..4c3e6749ac
--- /dev/null
+++ b/src/quickcontrols2/material/StackView.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.StackView {
+ id: control
+
+ popEnter: Transition {
+ // slide_in_left
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.5 : 0.5) * -control.width; to: 0; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+
+ popExit: Transition {
+ // slide_out_right
+ NumberAnimation { property: "x"; from: 0; to: (control.mirrored ? -0.5 : 0.5) * control.width; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+
+ pushEnter: Transition {
+ // slide_in_right
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.5 : 0.5) * control.width; to: 0; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+
+ pushExit: Transition {
+ // slide_out_left
+ NumberAnimation { property: "x"; from: 0; to: (control.mirrored ? -0.5 : 0.5) * -control.width; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+
+ replaceEnter: Transition {
+ // slide_in_right
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.5 : 0.5) * control.width; to: 0; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+
+ replaceExit: Transition {
+ // slide_out_left
+ NumberAnimation { property: "x"; from: 0; to: (control.mirrored ? -0.5 : 0.5) * -control.width; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; duration: 200; easing.type: Easing.OutCubic }
+ }
+}
diff --git a/src/quickcontrols2/material/SwipeDelegate.qml b/src/quickcontrols2/material/SwipeDelegate.qml
new file mode 100644
index 0000000000..f5e103c0d9
--- /dev/null
+++ b/src/quickcontrols2/material/SwipeDelegate.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.SwipeDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: 8
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ swipe.transition: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.Material.backgroundColor
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.highlighted
+ color: control.Material.listHighlightColor
+ }
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ enabled: control.swipe.position === 0
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/SwipeView.qml b/src/quickcontrols2/material/SwipeView.qml
new file mode 100644
index 0000000000..cd4da229c2
--- /dev/null
+++ b/src/quickcontrols2/material/SwipeView.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.SwipeView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ contentItem: ListView {
+ model: control.contentModel
+ interactive: control.interactive
+ currentIndex: control.currentIndex
+ focus: control.focus
+
+ spacing: control.spacing
+ orientation: control.orientation
+ snapMode: ListView.SnapOneItem
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ preferredHighlightBegin: 0
+ preferredHighlightEnd: 0
+ highlightMoveDuration: 250
+ maximumFlickVelocity: 4 * (control.orientation === Qt.Horizontal ? width : height)
+ }
+}
diff --git a/src/quickcontrols2/material/Switch.qml b/src/quickcontrols2/material/Switch.qml
new file mode 100644
index 0000000000..dc8a14347d
--- /dev/null
+++ b/src/quickcontrols2/material/Switch.qml
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+import QtQuick.Templates as T
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 8
+ spacing: 8
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+
+ Ripple {
+ x: parent.handle.x + parent.handle.width / 2 - width / 2
+ y: parent.handle.y + parent.handle.height / 2 - height / 2
+ width: 28; height: 28
+ pressed: control.pressed
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.checked ? control.Material.highlightedRippleColor : control.Material.rippleColor
+ }
+ }
+
+ 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.enabled ? control.Material.foreground : control.Material.hintTextColor
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+}
diff --git a/src/quickcontrols2/material/SwitchDelegate.qml b/src/quickcontrols2/material/SwitchDelegate.qml
new file mode 100644
index 0000000000..29e49032d8
--- /dev/null
+++ b/src/quickcontrols2/material/SwitchDelegate.qml
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.SwitchDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: Material.switchDelegateVerticalPadding
+ spacing: 16
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.highlighted ? control.Material.listHighlightColor : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/TabBar.qml b/src/quickcontrols2/material/TabBar.qml
new file mode 100644
index 0000000000..9e9585f31b
--- /dev/null
+++ b/src/quickcontrols2/material/TabBar.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 1
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 250
+ highlightResizeDuration: 0
+ highlightFollowsCurrentItem: true
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 48
+ preferredHighlightEnd: width - 48
+
+ highlight: Item {
+ z: 2
+ Rectangle {
+ height: 2
+ width: parent.width
+ y: control.position === T.TabBar.Footer ? 0 : parent.height - height
+ color: control.Material.accentColor
+ }
+ }
+ }
+
+ background: Rectangle {
+ color: control.Material.backgroundColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ fullWidth: true
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/TabButton.qml b/src/quickcontrols2/material/TabButton.qml
new file mode 100644
index 0000000000..40e10d9f33
--- /dev/null
+++ b/src/quickcontrols2/material/TabButton.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: !enabled ? Material.hintTextColor : down || checked ? Material.accentColor : Material.foreground
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Material.hintTextColor : control.down || control.checked ? control.Material.accentColor : control.Material.foreground
+ }
+
+ background: Ripple {
+ implicitHeight: control.Material.touchTarget
+
+ clip: true
+ pressed: control.pressed
+ anchor: control
+ active: enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+}
diff --git a/src/quickcontrols2/material/TextArea.qml b/src/quickcontrols2/material/TextArea.qml
new file mode 100644
index 0000000000..a213bd7ab0
--- /dev/null
+++ b/src/quickcontrols2/material/TextArea.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + 1 + topPadding + bottomPadding)
+
+ topPadding: 8
+ bottomPadding: 16
+
+ color: enabled ? Material.foreground : Material.hintTextColor
+ selectionColor: Material.accentColor
+ selectedTextColor: Material.primaryHighlightedTextColor
+ placeholderTextColor: Material.hintTextColor
+ cursorDelegate: CursorDelegate { }
+
+ 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
+ elide: Text.ElideRight
+ renderType: control.renderType
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ }
+
+ background: Rectangle {
+ y: parent.height - height - control.bottomPadding / 2
+ implicitWidth: 120
+ height: control.activeFocus ? 2 : 1
+ color: control.activeFocus ? control.Material.accentColor : control.Material.hintTextColor
+ }
+}
diff --git a/src/quickcontrols2/material/TextField.qml b/src/quickcontrols2/material/TextField.qml
new file mode 100644
index 0000000000..3ca1881a94
--- /dev/null
+++ b/src/quickcontrols2/material/TextField.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.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)
+
+ topPadding: 8
+ bottomPadding: 16
+
+ color: enabled ? Material.foreground : Material.hintTextColor
+ selectionColor: Material.accentColor
+ selectedTextColor: Material.primaryHighlightedTextColor
+ placeholderTextColor: Material.hintTextColor
+ verticalAlignment: TextInput.AlignVCenter
+
+ cursorDelegate: CursorDelegate { }
+
+ 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
+ elide: Text.ElideRight
+ renderType: control.renderType
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ }
+
+ background: Rectangle {
+ y: control.height - height - control.bottomPadding + 8
+ implicitWidth: 120
+ height: control.activeFocus || (enabled && control.hovered) ? 2 : 1
+ color: control.activeFocus ? control.Material.accentColor
+ : ((enabled && control.hovered) ? control.Material.primaryTextColor : control.Material.hintTextColor)
+ }
+}
diff --git a/src/quickcontrols2/material/ToolBar.qml b/src/quickcontrols2/material/ToolBar.qml
new file mode 100644
index 0000000000..a1aa82bda5
--- /dev/null
+++ b/src/quickcontrols2/material/ToolBar.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.ToolBar {
+ id: control
+
+ Material.elevation: 4
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ Material.foreground: Material.toolTextColor
+
+ spacing: 16
+
+ background: Rectangle {
+ implicitHeight: 48
+ color: control.Material.toolBarColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ fullWidth: true
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/ToolButton.qml b/src/quickcontrols2/material/ToolButton.qml
new file mode 100644
index 0000000000..be7ae332be
--- /dev/null
+++ b/src/quickcontrols2/material/ToolButton.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: !enabled ? Material.hintTextColor : checked || highlighted ? Material.accent : Material.foreground
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Material.hintTextColor :
+ control.checked || control.highlighted ? control.Material.accent : control.Material.foreground
+ }
+
+ background: Ripple {
+ implicitWidth: control.Material.touchTarget
+ implicitHeight: control.Material.touchTarget
+
+ readonly property bool square: control.contentItem.width <= control.contentItem.height
+
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ clip: !square
+ width: square ? parent.height / 2 : parent.width
+ height: square ? parent.height / 2 : parent.height
+ pressed: control.pressed
+ anchor: control
+ active: control.enabled && (control.down || control.visualFocus || control.hovered)
+ color: control.Material.rippleColor
+ }
+}
diff --git a/src/quickcontrols2/material/ToolSeparator.qml b/src/quickcontrols2/material/ToolSeparator.qml
new file mode 100644
index 0000000000..3d084d2b9b
--- /dev/null
+++ b/src/quickcontrols2/material/ToolSeparator.qml
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.ToolSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ horizontalPadding: vertical ? 12 : 5
+ verticalPadding: vertical ? 5 : 12
+
+ contentItem: Rectangle {
+ implicitWidth: control.vertical ? 1 : 38
+ implicitHeight: control.vertical ? 38 : 1
+ color: control.Material.hintTextColor
+ }
+}
diff --git a/src/quickcontrols2/material/ToolTip.qml b/src/quickcontrols2/material/ToolTip.qml
new file mode 100644
index 0000000000..033e48a3fa
--- /dev/null
+++ b/src/quickcontrols2/material/ToolTip.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.ToolTip {
+ id: control
+
+ x: parent ? (parent.width - implicitWidth) / 2 : 0
+ y: -implicitHeight - 24
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 12
+ padding: 8
+ horizontalPadding: padding + 8
+
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+
+ Material.theme: Material.Dark
+
+ enter: Transition {
+ // toast_enter
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.OutQuad; duration: 500 }
+ }
+
+ exit: Transition {
+ // toast_exit
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.InQuad; duration: 500 }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ wrapMode: Text.Wrap
+ color: control.Material.foreground
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.tooltipHeight
+ color: control.Material.tooltipColor
+ opacity: 0.9
+ radius: 2
+ }
+}
diff --git a/src/quickcontrols2/material/Tumbler.qml b/src/quickcontrols2/material/Tumbler.qml
new file mode 100644
index 0000000000..18ae06cb76
--- /dev/null
+++ b/src/quickcontrols2/material/Tumbler.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+
+T.Tumbler {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ delegate: Text {
+ text: modelData
+ color: control.Material.foreground
+ font: control.font
+ opacity: (1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)) * (control.enabled ? 1 : 0.6)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ required property var modelData
+ required property int index
+ }
+
+ contentItem: TumblerView {
+ implicitWidth: 60
+ implicitHeight: 200
+ model: control.model
+ delegate: control.delegate
+ path: Path {
+ startX: control.contentItem.width / 2
+ startY: -control.contentItem.delegateHeight / 2
+ PathLine {
+ x: control.contentItem.width / 2
+ y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: control.availableHeight / control.visibleItemCount
+ }
+}
diff --git a/src/quickcontrols2/material/VerticalHeaderView.qml b/src/quickcontrols2/material/VerticalHeaderView.qml
new file mode 100644
index 0000000000..9769627ea5
--- /dev/null
+++ b/src/quickcontrols2/material/VerticalHeaderView.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+T.VerticalHeaderView {
+ id: control
+
+ implicitWidth: contentWidth
+ implicitHeight: syncView ? syncView.height : 0
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: Math.max(control.width, text.implicitWidth + (cellPadding * 2))
+ implicitHeight: text.implicitHeight + (cellPadding * 2)
+ color: control.Material.backgroundColor
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: enabled ? control.Material.foreground : control.Material.hintTextColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/images/arrow-indicator.png b/src/quickcontrols2/material/images/arrow-indicator.png
new file mode 100644
index 0000000000..5a9780015b
--- /dev/null
+++ b/src/quickcontrols2/material/images/arrow-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/arrow-indicator.svg b/src/quickcontrols2/material/images/arrow-indicator.svg
new file mode 100644
index 0000000000..1e7217c855
--- /dev/null
+++ b/src/quickcontrols2/material/images/arrow-indicator.svg
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="5"
+ height="10"
+ viewBox="0 0 5 10"
+ version="1.1"
+ id="svg2"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="arrow-indicator.svg">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="2560"
+ inkscape:window-height="1571"
+ id="namedview6"
+ showgrid="false"
+ inkscape:zoom="27.812867"
+ inkscape:cx="13.137558"
+ inkscape:cy="12.83583"
+ inkscape:window-x="0"
+ inkscape:window-y="55"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <path
+ d="M 0,10 5,5 0,0 Z"
+ id="path4"
+ inkscape:connector-curvature="0"
+ style="fill:#757575" />
+</svg>
diff --git a/src/quickcontrols2/material/images/arrow-indicator@2x.png b/src/quickcontrols2/material/images/arrow-indicator@2x.png
new file mode 100644
index 0000000000..37ce3a957e
--- /dev/null
+++ b/src/quickcontrols2/material/images/arrow-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/arrow-indicator@3x.png b/src/quickcontrols2/material/images/arrow-indicator@3x.png
new file mode 100644
index 0000000000..57abd97295
--- /dev/null
+++ b/src/quickcontrols2/material/images/arrow-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/arrow-indicator@4x.png b/src/quickcontrols2/material/images/arrow-indicator@4x.png
new file mode 100644
index 0000000000..26d3d7c1f1
--- /dev/null
+++ b/src/quickcontrols2/material/images/arrow-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/check.png b/src/quickcontrols2/material/images/check.png
new file mode 100644
index 0000000000..756a43a579
--- /dev/null
+++ b/src/quickcontrols2/material/images/check.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/check@2x.png b/src/quickcontrols2/material/images/check@2x.png
new file mode 100644
index 0000000000..9d1d6a32b6
--- /dev/null
+++ b/src/quickcontrols2/material/images/check@2x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/check@3x.png b/src/quickcontrols2/material/images/check@3x.png
new file mode 100644
index 0000000000..32ed72f017
--- /dev/null
+++ b/src/quickcontrols2/material/images/check@3x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/check@4x.png b/src/quickcontrols2/material/images/check@4x.png
new file mode 100644
index 0000000000..1767cee617
--- /dev/null
+++ b/src/quickcontrols2/material/images/check@4x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/drop-indicator.png b/src/quickcontrols2/material/images/drop-indicator.png
new file mode 100644
index 0000000000..93560f507a
--- /dev/null
+++ b/src/quickcontrols2/material/images/drop-indicator.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/drop-indicator.svg b/src/quickcontrols2/material/images/drop-indicator.svg
new file mode 100644
index 0000000000..94b5ca1514
--- /dev/null
+++ b/src/quickcontrols2/material/images/drop-indicator.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" version="1.1">
+ <path d="M7,10l5,5,5-5z" fill="#757575"/>
+</svg>
diff --git a/src/quickcontrols2/material/images/drop-indicator@2x.png b/src/quickcontrols2/material/images/drop-indicator@2x.png
new file mode 100644
index 0000000000..d32f81604c
--- /dev/null
+++ b/src/quickcontrols2/material/images/drop-indicator@2x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/drop-indicator@3x.png b/src/quickcontrols2/material/images/drop-indicator@3x.png
new file mode 100644
index 0000000000..34c3e7d115
--- /dev/null
+++ b/src/quickcontrols2/material/images/drop-indicator@3x.png
Binary files differ
diff --git a/src/quickcontrols2/material/images/drop-indicator@4x.png b/src/quickcontrols2/material/images/drop-indicator@4x.png
new file mode 100644
index 0000000000..0613f6dd0d
--- /dev/null
+++ b/src/quickcontrols2/material/images/drop-indicator@4x.png
Binary files differ
diff --git a/src/quickcontrols2/material/impl/BoxShadow.qml b/src/quickcontrols2/material/impl/BoxShadow.qml
new file mode 100644
index 0000000000..5289452780
--- /dev/null
+++ b/src/quickcontrols2/material/impl/BoxShadow.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+/*
+ A implementation of CSS's box-shadow, used by ElevationEffect for a Material Design
+ elevation shadow effect.
+ */
+RectangularGlow {
+ // The 4 properties from CSS box-shadow, plus the inherited color property
+ property int offsetX
+ property int offsetY
+ property int blurRadius
+ property int spreadRadius
+
+ // The source item the shadow is being applied to, used for correctly
+ // calculating the corner radious
+ property Item source
+
+ property bool fullWidth
+ property bool fullHeight
+
+ x: (parent.width - width)/2 + offsetX
+ y: (parent.height - height)/2 + offsetY
+
+ implicitWidth: source ? source.width : parent.width
+ implicitHeight: source ? source.height : parent.height
+
+ width: implicitWidth + 2 * spreadRadius + (fullWidth ? 2 * cornerRadius : 0)
+ height: implicitHeight + 2 * spreadRadius + (fullHeight ? 2 * cornerRadius : 0)
+ glowRadius: blurRadius/2
+ spread: 0.05
+ // qmllint disable unqualified
+ // Intentionally duck-typed (QTBUG-94807)
+ cornerRadius: blurRadius + (source && source.radius || 0)
+}
diff --git a/src/quickcontrols2/material/impl/CMakeLists.txt b/src/quickcontrols2/material/impl/CMakeLists.txt
new file mode 100644
index 0000000000..16243e3036
--- /dev/null
+++ b/src/quickcontrols2/material/impl/CMakeLists.txt
@@ -0,0 +1,41 @@
+#####################################################################
+## qtquickcontrols2materialstyleimplplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "BoxShadow.qml"
+ "CheckIndicator.qml"
+ "CursorDelegate.qml"
+ "ElevationEffect.qml"
+ "RadioIndicator.qml"
+ "RectangularGlow.qml"
+ "SliderHandle.qml"
+ "SwitchIndicator.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2materialstyleimplplugin
+ URI "QtQuick.Controls.Material.impl"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2MaterialStyleImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2materialstyleimplplugin
+ NO_PLUGIN_OPTIONAL
+ SOURCES
+ qquickmaterialbusyindicator.cpp qquickmaterialbusyindicator_p.h
+ qquickmaterialprogressbar.cpp qquickmaterialprogressbar_p.h
+ qquickmaterialripple.cpp qquickmaterialripple_p.h
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
diff --git a/src/quickcontrols2/material/impl/CheckIndicator.qml b/src/quickcontrols2/material/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..b6593fab8a
--- /dev/null
+++ b/src/quickcontrols2/material/impl/CheckIndicator.qml
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+Rectangle {
+ id: indicatorItem
+ implicitWidth: 18
+ implicitHeight: 18
+ color: "transparent"
+ border.color: !control.enabled ? control.Material.hintTextColor
+ : checkState !== Qt.Unchecked ? control.Material.accentColor : control.Material.secondaryTextColor
+ border.width: checkState !== Qt.Unchecked ? width / 2 : 2
+ radius: 2
+
+ property Item control
+ property int checkState: control.checkState
+
+ Behavior on border.width {
+ NumberAnimation {
+ duration: 100
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ Behavior on border.color {
+ ColorAnimation {
+ duration: 100
+ easing.type: Easing.OutCubic
+ }
+ }
+
+ // TODO: This needs to be transparent
+ Image {
+ id: checkImage
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 14
+ height: 14
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Material/images/check.png"
+ fillMode: Image.PreserveAspectFit
+
+ scale: indicatorItem.checkState === Qt.Checked ? 1 : 0
+ Behavior on scale { NumberAnimation { duration: 100 } }
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 12
+ height: 3
+
+ scale: indicatorItem.checkState === Qt.PartiallyChecked ? 1 : 0
+ Behavior on scale { NumberAnimation { duration: 100 } }
+ }
+
+ states: [
+ State {
+ name: "checked"
+ when: indicatorItem.checkState === Qt.Checked
+ },
+ State {
+ name: "partiallychecked"
+ when: indicatorItem.checkState === Qt.PartiallyChecked
+ }
+ ]
+
+ transitions: Transition {
+ SequentialAnimation {
+ NumberAnimation {
+ target: indicatorItem
+ property: "scale"
+ // Go down 2 pixels in size.
+ to: 1 - 2 / indicatorItem.width
+ duration: 120
+ }
+ NumberAnimation {
+ target: indicatorItem
+ property: "scale"
+ to: 1
+ duration: 120
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/impl/CursorDelegate.qml b/src/quickcontrols2/material/impl/CursorDelegate.qml
new file mode 100644
index 0000000000..a913ab849d
--- /dev/null
+++ b/src/quickcontrols2/material/impl/CursorDelegate.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+
+Rectangle {
+ id: cursor
+
+ color: parent.Material.accentColor
+ width: 2
+ visible: parent.activeFocus && !parent.readOnly && parent.selectionStart === parent.selectionEnd
+
+ Connections {
+ target: cursor.parent
+ function onCursorPositionChanged() {
+ // keep a moving cursor visible
+ cursor.opacity = 1
+ timer.restart()
+ }
+ }
+
+ Timer {
+ id: timer
+ running: cursor.parent.activeFocus && !cursor.parent.readOnly && interval != 0
+ repeat: true
+ interval: Qt.styleHints.cursorFlashTime / 2
+ onTriggered: cursor.opacity = !cursor.opacity ? 1 : 0
+ // force the cursor visible when gaining focus
+ onRunningChanged: cursor.opacity = 1
+ }
+}
diff --git a/src/quickcontrols2/material/impl/ElevationEffect.qml b/src/quickcontrols2/material/impl/ElevationEffect.qml
new file mode 100644
index 0000000000..8a4e98e320
--- /dev/null
+++ b/src/quickcontrols2/material/impl/ElevationEffect.qml
@@ -0,0 +1,279 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+/*
+ An effect for standard Material Design elevation shadows. Useful for using as \c layer.effect.
+ */
+Item {
+ id: effect
+
+ /*
+ The source the effect is applied to.
+ */
+ property var source
+
+ /*
+ The elevation of the \l source Item.
+ */
+ property int elevation: 0
+
+ /*
+ Set to \c true if the \l source Item is the same width as its parent and the shadow
+ should be full width instead of rounding around the corner of the Item.
+
+ \sa fullHeight
+ */
+ property bool fullWidth: false
+
+ /*
+ Set to \c true if the \l source Item is the same height as its parent and the shadow
+ should be full height instead of rounding around the corner of the Item.
+
+ \sa fullWidth
+ */
+ property bool fullHeight: false
+
+ /*
+ \internal
+
+ The actual source Item the effect is applied to.
+ */
+ readonly property Item sourceItem: source.sourceItem
+
+ /*
+ * The following shadow values are taken from Angular Material
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2014-2016 Google, Inc. http://angularjs.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+ /*
+ \internal
+
+ The shadows to use for each possible elevation. There are three shadows that when combined
+ make up the elevation.
+ */
+ readonly property var _shadows: [
+ [{offset: 0, blur: 0, spread: 0},
+ {offset: 0, blur: 0, spread: 0},
+ {offset: 0, blur: 0, spread: 0}],
+
+ [{offset: 1, blur: 3, spread: 0},
+ {offset: 1, blur: 1, spread: 0},
+ {offset: 2, blur: 1, spread: -1}],
+
+ [{offset: 1, blur: 5, spread: 0},
+ {offset: 2, blur: 2, spread: 0},
+ {offset: 3, blur: 1, spread: -2}],
+
+ [{offset: 1, blur: 8, spread: 0},
+ {offset: 3, blur: 4, spread: 0},
+ {offset: 3, blur: 3, spread: -2}],
+
+ [{offset: 2, blur: 4, spread: -1},
+ {offset: 4, blur: 5, spread: 0},
+ {offset: 1, blur: 10, spread: 0}],
+
+ [{offset: 3, blur: 5, spread: -1},
+ {offset: 5, blur: 8, spread: 0},
+ {offset: 1, blur: 14, spread: 0}],
+
+ [{offset: 3, blur: 5, spread: -1},
+ {offset: 6, blur: 10, spread: 0},
+ {offset: 1, blur: 18, spread: 0}],
+
+ [{offset: 4, blur: 5, spread: -2},
+ {offset: 7, blur: 10, spread: 1},
+ {offset: 2, blur: 16, spread: 1}],
+
+ [{offset: 5, blur: 5, spread: -3},
+ {offset: 8, blur: 10, spread: 1},
+ {offset: 3, blur: 14, spread: 2}],
+
+ [{offset: 5, blur: 6, spread: -3},
+ {offset: 9, blur: 12, spread: 1},
+ {offset: 3, blur: 16, spread: 2}],
+
+ [{offset: 6, blur: 6, spread: -3},
+ {offset: 10, blur: 14, spread: 1},
+ {offset: 4, blur: 18, spread: 3}],
+
+ [{offset: 6, blur: 7, spread: -4},
+ {offset: 11, blur: 15, spread: 1},
+ {offset: 4, blur: 20, spread: 3}],
+
+ [{offset: 7, blur: 8, spread: -4},
+ {offset: 12, blur: 17, spread: 2},
+ {offset: 5, blur: 22, spread: 4}],
+
+ [{offset: 7, blur: 8, spread: -4},
+ {offset: 13, blur: 19, spread: 2},
+ {offset: 5, blur: 24, spread: 4}],
+
+ [{offset: 7, blur: 9, spread: -4},
+ {offset: 14, blur: 21, spread: 2},
+ {offset: 5, blur: 26, spread: 4}],
+
+ [{offset: 8, blur: 9, spread: -5},
+ {offset: 15, blur: 22, spread: 2},
+ {offset: 6, blur: 28, spread: 5}],
+
+ [{offset: 8, blur: 10, spread: -5},
+ {offset: 16, blur: 24, spread: 2},
+ {offset: 6, blur: 30, spread: 5}],
+
+ [{offset: 8, blur: 11, spread: -5},
+ {offset: 17, blur: 26, spread: 2},
+ {offset: 6, blur: 32, spread: 5}],
+
+ [{offset: 9, blur: 11, spread: -5},
+ {offset: 18, blur: 28, spread: 2},
+ {offset: 7, blur: 34, spread: 6}],
+
+ [{offset: 9, blur: 12, spread: -6},
+ {offset: 19, blur: 29, spread: 2},
+ {offset: 7, blur: 36, spread: 6}],
+
+ [{offset: 10, blur: 13, spread: -6},
+ {offset: 20, blur: 31, spread: 3},
+ {offset: 8, blur: 38, spread: 7}],
+
+ [{offset: 10, blur: 13, spread: -6},
+ {offset: 21, blur: 33, spread: 3},
+ {offset: 8, blur: 40, spread: 7}],
+
+ [{offset: 10, blur: 14, spread: -6},
+ {offset: 22, blur: 35, spread: 3},
+ {offset: 8, blur: 42, spread: 7}],
+
+ [{offset: 11, blur: 14, spread: -7},
+ {offset: 23, blur: 36, spread: 3},
+ {offset: 9, blur: 44, spread: 8}],
+
+ [{offset: 11, blur: 15, spread: -7},
+ {offset: 24, blur: 38, spread: 3},
+ {offset: 9, blur: 46, spread: 8}]
+ ]
+
+ /*
+ \internal
+
+ The current shadow based on the elevation.
+ */
+ readonly property var _shadow: _shadows[Math.max(0, Math.min(elevation, _shadows.length - 1))]
+
+ // Nest the shadows and source view in two items rendered as a layer
+ // so the shadow is not clipped by the bounds of the source view
+ Item {
+ property int margin: -100
+
+ x: margin
+ y: margin
+ width: parent.width - 2 * margin
+ height: parent.height - 2 * margin
+
+ // By rendering as a layer, the shadow will never show through the source item,
+ // even when the source item's opacity is less than 1
+ layer.enabled: true
+
+ // The box shadows automatically pick up the size of the source Item and not
+ // the size of the parent, so we don't need to worry about the extra padding
+ // in the parent Item
+ BoxShadow {
+ offsetY: effect._shadow[0].offset
+ blurRadius: effect._shadow[0].blur
+ spreadRadius: effect._shadow[0].spread
+ color: Qt.rgba(0,0,0, 0.2)
+
+ fullWidth: effect.fullWidth
+ fullHeight: effect.fullHeight
+ source: effect.sourceItem
+ }
+
+ BoxShadow {
+ offsetY: effect._shadow[1].offset
+ blurRadius: effect._shadow[1].blur
+ spreadRadius: effect._shadow[1].spread
+ color: Qt.rgba(0,0,0, 0.14)
+
+ fullWidth: effect.fullWidth
+ fullHeight: effect.fullHeight
+ source: effect.sourceItem
+ }
+
+ BoxShadow {
+ offsetY: effect._shadow[2].offset
+ blurRadius: effect._shadow[2].blur
+ spreadRadius: effect._shadow[2].spread
+ color: Qt.rgba(0,0,0, 0.12)
+
+ fullWidth: effect.fullWidth
+ fullHeight: effect.fullHeight
+ source: effect.sourceItem
+ }
+
+ ShaderEffect {
+ property alias source: effect.source
+
+ x: (parent.width - width)/2
+ y: (parent.height - height)/2
+ width: effect.sourceItem.width
+ height: effect.sourceItem.height
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/impl/RadioIndicator.qml b/src/quickcontrols2/material/impl/RadioIndicator.qml
new file mode 100644
index 0000000000..ca14501c55
--- /dev/null
+++ b/src/quickcontrols2/material/impl/RadioIndicator.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+Rectangle {
+ id: indicator
+ implicitWidth: 20
+ implicitHeight: 20
+ radius: width / 2
+ border.width: 2
+ border.color: !control.enabled ? control.Material.hintTextColor
+ : control.checked || control.down ? control.Material.accentColor : control.Material.secondaryTextColor
+ color: "transparent"
+
+ property T.AbstractButton control
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 10
+ height: 10
+ radius: width / 2
+ color: parent.border.color
+ visible: indicator.control.checked || indicator.control.down
+ }
+}
diff --git a/src/quickcontrols2/material/impl/RectangularGlow.qml b/src/quickcontrols2/material/impl/RectangularGlow.qml
new file mode 100644
index 0000000000..b2337afc0b
--- /dev/null
+++ b/src/quickcontrols2/material/impl/RectangularGlow.qml
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+
+/*
+ A cross-graphics API implementation of QtGraphicalEffects' RectangularGlow.
+ */
+Item {
+ id: rootItem
+
+ /*
+ This property defines how many pixels outside the item area are reached
+ by the glow.
+
+ The value ranges from 0.0 (no glow) to inf (infinite glow). By default,
+ the property is set to \c 0.0.
+
+ \table
+ \header
+ \li Output examples with different glowRadius values
+ \li
+ \li
+ \row
+ \li \image RectangularGlow_glowRadius1.png
+ \li \image RectangularGlow_glowRadius2.png
+ \li \image RectangularGlow_glowRadius3.png
+ \row
+ \li \b { glowRadius: 10 }
+ \li \b { glowRadius: 20 }
+ \li \b { glowRadius: 40 }
+ \row
+ \li \l spread: 0
+ \li \l spread: 0
+ \li \l spread: 0
+ \row
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \row
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \endtable
+
+ */
+ property real glowRadius: 0.0
+
+ /*
+ This property defines how large part of the glow color is strenghtened
+ near the source edges.
+
+ The value ranges from 0.0 (no strenght increase) to 1.0 (maximum
+ strenght increase). By default, the property is set to \c 0.0.
+
+ \table
+ \header
+ \li Output examples with different spread values
+ \li
+ \li
+ \row
+ \li \image RectangularGlow_spread1.png
+ \li \image RectangularGlow_spread2.png
+ \li \image RectangularGlow_spread3.png
+ \row
+ \li \b { spread: 0.0 }
+ \li \b { spread: 0.5 }
+ \li \b { spread: 1.0 }
+ \row
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \row
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \row
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \endtable
+ */
+ property real spread: 0.0
+
+ /*
+ This property defines the RGBA color value which is used for the glow.
+
+ By default, the property is set to \c "white".
+
+ \table
+ \header
+ \li Output examples with different color values
+ \li
+ \li
+ \row
+ \li \image RectangularGlow_color1.png
+ \li \image RectangularGlow_color2.png
+ \li \image RectangularGlow_color3.png
+ \row
+ \li \b { color: #ffffff }
+ \li \b { color: #55ff55 }
+ \li \b { color: #5555ff }
+ \row
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \row
+ \li \l spread: 0
+ \li \l spread: 0
+ \li \l spread: 0
+ \row
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \li \l cornerRadius: 25
+ \endtable
+ */
+ property color color: "white"
+
+ /*
+ This property defines the corner radius that is used to draw a glow with
+ rounded corners.
+
+ The value ranges from 0.0 to half of the effective width or height of
+ the glow, whichever is smaller. This can be calculated with: \c{
+ min(width, height) / 2.0 + glowRadius}
+
+ By default, the property is bound to glowRadius property. The glow
+ behaves as if the rectangle was blurred when adjusting the glowRadius
+ property.
+
+ \table
+ \header
+ \li Output examples with different cornerRadius values
+ \li
+ \li
+ \row
+ \li \image RectangularGlow_cornerRadius1.png
+ \li \image RectangularGlow_cornerRadius2.png
+ \li \image RectangularGlow_cornerRadius3.png
+ \row
+ \li \b { cornerRadius: 0 }
+ \li \b { cornerRadius: 25 }
+ \li \b { cornerRadius: 50 }
+ \row
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \li \l glowRadius: 20
+ \row
+ \li \l spread: 0
+ \li \l spread: 0
+ \li \l spread: 0
+ \row
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \li \l color: #ffffff
+ \endtable
+ */
+ property real cornerRadius: glowRadius
+
+ /*
+ This property allows the effect output pixels to be cached in order to
+ improve the rendering performance.
+
+ Every time the source or effect properties are changed, the pixels in
+ the cache must be updated. Memory consumption is increased, because an
+ extra buffer of memory is required for storing the effect output.
+
+ It is recommended to disable the cache when the source or the effect
+ properties are animated.
+
+ By default, the property is set to \c false.
+ */
+ property bool cached: false
+
+ ShaderEffectSource {
+ id: cacheItem
+ anchors.fill: shaderItem
+ visible: rootItem.cached
+ smooth: true
+ sourceItem: shaderItem
+ live: true
+ hideSource: visible
+ }
+
+ ShaderEffect {
+ id: shaderItem
+
+ x: (parent.width - width) / 2.0
+ y: (parent.height - height) / 2.0
+ width: parent.width + rootItem.glowRadius * 2 + cornerRadius * 2
+ height: parent.height + rootItem.glowRadius * 2 + cornerRadius * 2
+
+ function clampedCornerRadius() {
+ var maxCornerRadius = Math.min(rootItem.width, rootItem.height) / 2 + rootItem.glowRadius;
+ return Math.max(0, Math.min(rootItem.cornerRadius, maxCornerRadius))
+ }
+
+ property color color: rootItem.color
+ property real inverseSpread: 1.0 - rootItem.spread
+ property real relativeSizeX: ((inverseSpread * inverseSpread) * rootItem.glowRadius + cornerRadius * 2.0) / width
+ property real relativeSizeY: relativeSizeX * (width / height)
+ property real spread: rootItem.spread / 2.0
+ property real cornerRadius: clampedCornerRadius()
+
+ fragmentShader: "qrc:/qt-project.org/imports/QtQuick/Controls/Material/shaders/RectangularGlow.frag"
+ }
+}
diff --git a/src/quickcontrols2/material/impl/SliderHandle.qml b/src/quickcontrols2/material/impl/SliderHandle.qml
new file mode 100644
index 0000000000..ad22c4d916
--- /dev/null
+++ b/src/quickcontrols2/material/impl/SliderHandle.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+Item {
+ id: root
+ implicitWidth: initialSize
+ implicitHeight: initialSize
+
+ property real value: 0
+ property bool handleHasFocus: false
+ property bool handlePressed: false
+ property bool handleHovered: false
+ readonly property int initialSize: 13
+ readonly property var control: parent
+
+ Rectangle {
+ id: handleRect
+ width: parent.width
+ height: parent.height
+ radius: width / 2
+ scale: root.handlePressed ? 1.5 : 1
+ color: root.control.enabled ? root.control.Material.accentColor : root.control.Material.sliderDisabledColor
+
+ Behavior on scale {
+ NumberAnimation {
+ duration: 250
+ }
+ }
+ }
+
+ Ripple {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: 22; height: 22
+ pressed: root.handlePressed
+ active: root.handlePressed || root.handleHasFocus || (enabled && root.handleHovered)
+ color: root.control.Material.highlightedRippleColor
+ }
+}
diff --git a/src/quickcontrols2/material/impl/SwitchIndicator.qml b/src/quickcontrols2/material/impl/SwitchIndicator.qml
new file mode 100644
index 0000000000..9d29d0658b
--- /dev/null
+++ b/src/quickcontrols2/material/impl/SwitchIndicator.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+
+Item {
+ id: indicator
+ implicitWidth: 38
+ implicitHeight: 32
+
+ property T.AbstractButton control
+ property alias handle: handle
+
+ Material.elevation: 1
+
+ Rectangle {
+ width: parent.width
+ height: 14
+ radius: height / 2
+ y: parent.height / 2 - height / 2
+ color: indicator.control.enabled ? (indicator.control.checked ? indicator.control.Material.switchCheckedTrackColor : indicator.control.Material.switchUncheckedTrackColor)
+ : indicator.control.Material.switchDisabledTrackColor
+ }
+
+ Rectangle {
+ id: handle
+ x: Math.max(0, Math.min(parent.width - width, indicator.control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+ width: 20
+ height: 20
+ radius: width / 2
+ color: indicator.control.enabled ? (indicator.control.checked ? indicator.control.Material.switchCheckedHandleColor : indicator.control.Material.switchUncheckedHandleColor)
+ : indicator.control.Material.switchDisabledHandleColor
+
+ Behavior on x {
+ enabled: !indicator.control.pressed
+ SmoothedAnimation {
+ duration: 300
+ }
+ }
+ layer.enabled: indicator.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: indicator.Material.elevation
+ }
+ }
+}
diff --git a/src/quickcontrols2/material/impl/qquickmaterialbusyindicator.cpp b/src/quickcontrols2/material/impl/qquickmaterialbusyindicator.cpp
new file mode 100644
index 0000000000..420927c690
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialbusyindicator.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialbusyindicator_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtGui/qpainter.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Relevant Android code:
+
+ - core/res/res/anim/progress_indeterminate_rotation_material.xml contains
+ the rotation animation data.
+ - core/res/res/anim/progress_indeterminate_material.xml contains the trim
+ animation data.
+ - core/res/res/interpolator/trim_start_interpolator.xml and
+ core/res/res/interpolator/trim_end_interpolator.xml contain the start
+ and end trim path interpolators.
+ - addCommand() in core/java/android/util/PathParser.java has a list of the
+ different path commands available.
+*/
+
+static const int SpanAnimationDuration = 700;
+static const int RotationAnimationDuration = SpanAnimationDuration * 6;
+static const int TargetRotation = 720;
+static const int OneDegree = 16;
+static const qreal MinSweepSpan = 10 * OneDegree;
+static const qreal MaxSweepSpan = 300 * OneDegree;
+
+class QQuickMaterialBusyIndicatorNode : public QQuickAnimatedNode
+{
+public:
+ QQuickMaterialBusyIndicatorNode(QQuickMaterialBusyIndicator *item);
+
+ void sync(QQuickItem *item) override;
+
+protected:
+ void updateCurrentTime(int time) override;
+
+private:
+ int m_lastStartAngle = 0;
+ int m_lastEndAngle = 0;
+ qreal m_width = 0;
+ qreal m_height = 0;
+ qreal m_devicePixelRatio = 1;
+ QColor m_color;
+};
+
+QQuickMaterialBusyIndicatorNode::QQuickMaterialBusyIndicatorNode(QQuickMaterialBusyIndicator *item)
+ : QQuickAnimatedNode(item)
+{
+ setLoopCount(Infinite);
+ setCurrentTime(item->elapsed());
+ setDuration(RotationAnimationDuration);
+
+ QSGImageNode *textureNode = item->window()->createImageNode();
+ textureNode->setOwnsTexture(true);
+ appendChildNode(textureNode);
+
+ // A texture seems to be required here, but we don't have one yet, as we haven't drawn anything,
+ // so just use a blank image.
+ QImage blankImage(item->width(), item->height(), QImage::Format_ARGB32_Premultiplied);
+ blankImage.fill(Qt::transparent);
+ textureNode->setTexture(item->window()->createTextureFromImage(blankImage));
+}
+
+void QQuickMaterialBusyIndicatorNode::updateCurrentTime(int time)
+{
+ const qreal w = m_width;
+ const qreal h = m_height;
+ const qreal size = qMin(w, h);
+ const qreal dx = (w - size) / 2;
+ const qreal dy = (h - size) / 2;
+
+ QImage image(size * m_devicePixelRatio, size * m_devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+
+ QPainter painter(&image);
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ QPen pen;
+ QSGImageNode *textureNode = static_cast<QSGImageNode *>(firstChild());
+ pen.setColor(m_color);
+ pen.setWidth(qCeil(size / 12) * m_devicePixelRatio);
+ painter.setPen(pen);
+
+ const qreal percentageComplete = time / qreal(RotationAnimationDuration);
+ const qreal spanPercentageComplete = (time % SpanAnimationDuration) / qreal(SpanAnimationDuration);
+ const int iteration = time / SpanAnimationDuration;
+ int startAngle = 0;
+ int endAngle = 0;
+
+ if (iteration % 2 == 0) {
+ if (m_lastStartAngle > 360 * OneDegree)
+ m_lastStartAngle -= 360 * OneDegree;
+
+ // The start angle is only affected by the rotation animation for the "grow" phase.
+ startAngle = m_lastStartAngle;
+ QEasingCurve angleCurve(QEasingCurve::OutQuad);
+ const qreal percentage = angleCurve.valueForProgress(spanPercentageComplete);
+ endAngle = m_lastStartAngle + MinSweepSpan + percentage * (MaxSweepSpan - MinSweepSpan);
+ m_lastEndAngle = endAngle;
+ } else {
+ // Both the start angle *and* the span are affected by the "shrink" phase.
+ QEasingCurve angleCurve(QEasingCurve::InQuad);
+ const qreal percentage = angleCurve.valueForProgress(spanPercentageComplete);
+ startAngle = m_lastEndAngle - MaxSweepSpan + percentage * (MaxSweepSpan - MinSweepSpan);
+ endAngle = m_lastEndAngle;
+ m_lastStartAngle = startAngle;
+ }
+
+ const int halfPen = pen.width() / 2;
+ const QRectF arcBounds = QRectF(halfPen, halfPen,
+ m_devicePixelRatio * size - pen.width(),
+ m_devicePixelRatio * size - pen.width());
+ // The current angle of the rotation animation.
+ const qreal rotation = OneDegree * percentageComplete * -TargetRotation;
+ startAngle -= rotation;
+ endAngle -= rotation;
+ const int angleSpan = endAngle - startAngle;
+ painter.drawArc(arcBounds, -startAngle, -angleSpan);
+ painter.end();
+
+ textureNode->setRect(QRectF(dx, dy, size, size));
+ textureNode->setTexture(window()->createTextureFromImage(image));
+}
+
+void QQuickMaterialBusyIndicatorNode::sync(QQuickItem *item)
+{
+ QQuickMaterialBusyIndicator *indicator = static_cast<QQuickMaterialBusyIndicator *>(item);
+ m_color = indicator->color();
+ m_width = indicator->width();
+ m_height = indicator->height();
+ m_devicePixelRatio = indicator->window()->effectiveDevicePixelRatio();
+}
+
+QQuickMaterialBusyIndicator::QQuickMaterialBusyIndicator(QQuickItem *parent) :
+ QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QColor QQuickMaterialBusyIndicator::color() const
+{
+ return m_color;
+}
+
+void QQuickMaterialBusyIndicator::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+bool QQuickMaterialBusyIndicator::isRunning() const
+{
+ return isVisible();
+}
+
+void QQuickMaterialBusyIndicator::setRunning(bool running)
+{
+ if (running)
+ setVisible(true);
+}
+
+int QQuickMaterialBusyIndicator::elapsed() const
+{
+ return m_elapsed;
+}
+
+void QQuickMaterialBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ switch (change) {
+ case ItemOpacityHasChanged:
+ if (qFuzzyIsNull(data.realValue))
+ setVisible(false);
+ break;
+ case ItemVisibleHasChanged:
+ update();
+ break;
+ default:
+ break;
+ }
+}
+
+QSGNode *QQuickMaterialBusyIndicator::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QQuickMaterialBusyIndicatorNode *node = static_cast<QQuickMaterialBusyIndicatorNode *>(oldNode);
+ if (isRunning() && width() > 0 && height() > 0) {
+ if (!node) {
+ node = new QQuickMaterialBusyIndicatorNode(this);
+ node->start();
+ }
+ node->sync(this);
+ } else {
+ m_elapsed = node ? node->currentTime() : 0;
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmaterialbusyindicator_p.cpp"
diff --git a/src/quickcontrols2/material/impl/qquickmaterialbusyindicator_p.h b/src/quickcontrols2/material/impl/qquickmaterialbusyindicator_p.h
new file mode 100644
index 0000000000..72aeaf66f1
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialbusyindicator_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMATERIALBUSYINDICATOR_P_H
+#define QQUICKMATERIALBUSYINDICATOR_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/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMaterialBusyIndicator : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning FINAL)
+ QML_NAMED_ELEMENT(BusyIndicatorImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickMaterialBusyIndicator(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+ int elapsed() const;
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ int m_elapsed = 0;
+ QColor m_color = Qt::black;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMaterialBusyIndicator)
+
+#endif // QQUICKMATERIALBUSYINDICATOR_P_H
diff --git a/src/quickcontrols2/material/impl/qquickmaterialprogressbar.cpp b/src/quickcontrols2/material/impl/qquickmaterialprogressbar.cpp
new file mode 100644
index 0000000000..ae52036061
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialprogressbar.cpp
@@ -0,0 +1,247 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialprogressbar_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuick/qsgimagenode.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int PauseDuration = 520;
+static const int SlideDuration = 1240;
+static const int TotalDuration = SlideDuration + PauseDuration;
+
+class QQuickMaterialProgressBarNode : public QQuickAnimatedNode
+{
+public:
+ QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *item);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ void moveNode(QSGTransformNode *node, const QRectF &geometry, qreal progress);
+
+ bool m_indeterminate = false;
+ QEasingCurve m_easing = QEasingCurve::OutCubic;
+};
+
+QQuickMaterialProgressBarNode::QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *item)
+ : QQuickAnimatedNode(item)
+{
+ setLoopCount(Infinite);
+ setDuration(TotalDuration);
+}
+
+void QQuickMaterialProgressBarNode::updateCurrentTime(int time)
+{
+ QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
+ Q_ASSERT(geometryNode->type() == QSGNode::GeometryNodeType);
+ const QRectF geometry = geometryNode->rect();
+
+ QSGTransformNode *firstNode = static_cast<QSGTransformNode *>(geometryNode->firstChild());
+ if (firstNode) {
+ Q_ASSERT(firstNode->type() == QSGNode::TransformNodeType);
+
+ const qreal progress = qMin<qreal>(1.0, static_cast<qreal>(time) / SlideDuration);
+ moveNode(static_cast<QSGTransformNode *>(firstNode), geometry, progress);
+ }
+
+ QSGTransformNode *secondNode = static_cast<QSGTransformNode *>(geometryNode->lastChild());
+ if (secondNode) {
+ Q_ASSERT(secondNode->type() == QSGNode::TransformNodeType);
+
+ const qreal progress = qMax<qreal>(0.0, static_cast<qreal>(time - PauseDuration) / SlideDuration);
+ moveNode(static_cast<QSGTransformNode *>(secondNode), geometry, progress);
+ }
+}
+
+void QQuickMaterialProgressBarNode::sync(QQuickItem *item)
+{
+ QQuickMaterialProgressBar *bar = static_cast<QQuickMaterialProgressBar *>(item);
+ if (m_indeterminate != bar->isIndeterminate()) {
+ m_indeterminate = bar->isIndeterminate();
+ if (m_indeterminate)
+ start();
+ else
+ stop();
+ }
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+
+ QRectF bounds = item->boundingRect();
+ bounds.setHeight(item->implicitHeight());
+ bounds.moveTop((item->height() - bounds.height()) / 2.0);
+
+ QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
+ if (!geometryNode) {
+ geometryNode = item->window()->createRectangleNode();
+ geometryNode->setColor(Qt::transparent);
+ appendChildNode(geometryNode);
+ }
+ geometryNode->setRect(bounds);
+
+ const int count = m_indeterminate ? 2 : 1;
+ const qreal w = m_indeterminate ? 0 : bar->progress() * item->width();
+ const QRectF rect(0, bounds.y(), w, bounds.height());
+
+ QSGNode *transformNode = geometryNode->firstChild();
+ for (int i = 0; i < count; ++i) {
+ if (!transformNode) {
+ transformNode = new QSGTransformNode;
+ geometryNode->appendChildNode(transformNode);
+
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ transformNode->appendChildNode(rectNode);
+ }
+ Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
+ static_cast<QSGTransformNode *>(transformNode)->setMatrix(QMatrix4x4());
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ rectNode->setRect(rect);
+ rectNode->setColor(bar->color());
+ rectNode->update();
+
+ transformNode = transformNode->nextSibling();
+ }
+
+ while (transformNode) {
+ QSGNode *nextSibling = transformNode->nextSibling();
+ delete transformNode;
+ transformNode = nextSibling;
+ }
+}
+
+void QQuickMaterialProgressBarNode::moveNode(QSGTransformNode *transformNode, const QRectF &geometry, qreal progress)
+{
+ const qreal value = m_easing.valueForProgress(progress);
+ const qreal x = value * geometry.width();
+
+ QMatrix4x4 matrix;
+ matrix.translate(x, 0);
+ transformNode->setMatrix(matrix);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ QRectF r = geometry;
+ r.setWidth(value * (geometry.width() - x));
+ rectNode->setRect(r);
+ rectNode->update();
+}
+
+QQuickMaterialProgressBar::QQuickMaterialProgressBar(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QColor QQuickMaterialProgressBar::color() const
+{
+ return m_color;
+}
+
+void QQuickMaterialProgressBar::setColor(const QColor &color)
+{
+ if (color == m_color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+qreal QQuickMaterialProgressBar::progress() const
+{
+ return m_progress;
+}
+
+void QQuickMaterialProgressBar::setProgress(qreal progress)
+{
+ if (progress == m_progress)
+ return;
+
+ m_progress = progress;
+ update();
+}
+
+bool QQuickMaterialProgressBar::isIndeterminate() const
+{
+ return m_indeterminate;
+}
+
+void QQuickMaterialProgressBar::setIndeterminate(bool indeterminate)
+{
+ if (indeterminate == m_indeterminate)
+ return;
+
+ m_indeterminate = indeterminate;
+ update();
+}
+
+void QQuickMaterialProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ if (change == ItemVisibleHasChanged)
+ update();
+}
+
+QSGNode *QQuickMaterialProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QQuickMaterialProgressBarNode *node = static_cast<QQuickMaterialProgressBarNode *>(oldNode);
+ if (isVisible() && width() > 0 && height() > 0) {
+ if (!node)
+ node = new QQuickMaterialProgressBarNode(this);
+ node->sync(this);
+ } else {
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmaterialprogressbar_p.cpp"
diff --git a/src/quickcontrols2/material/impl/qquickmaterialprogressbar_p.h b/src/quickcontrols2/material/impl/qquickmaterialprogressbar_p.h
new file mode 100644
index 0000000000..bf93812d08
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialprogressbar_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMATERIALPROGRESSBAR_P_H
+#define QQUICKMATERIALPROGRESSBAR_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/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMaterialProgressBar : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress FINAL)
+ Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate FINAL)
+ QML_NAMED_ELEMENT(ProgressBarImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickMaterialProgressBar(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ bool isIndeterminate() const;
+ void setIndeterminate(bool indeterminate);
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ QColor m_color = Qt::black;
+ qreal m_progress = 0.0;
+ bool m_indeterminate = false;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMaterialProgressBar)
+
+#endif // QQUICKMATERIALPROGRESSBAR_P_H
diff --git a/src/quickcontrols2/material/impl/qquickmaterialripple.cpp b/src/quickcontrols2/material/impl/qquickmaterialripple.cpp
new file mode 100644
index 0000000000..48abd9db6f
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialripple.cpp
@@ -0,0 +1,444 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialripple_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+ enum WavePhase { WaveEnter, WaveExit };
+}
+
+static const int RIPPLE_ENTER_DELAY = 80;
+static const int OPACITY_ENTER_DURATION_FAST = 120;
+static const int WAVE_OPACITY_DECAY_DURATION = 333;
+static const qreal WAVE_TOUCH_DOWN_ACCELERATION = 1024.0;
+
+class QQuickMaterialRippleWaveNode : public QQuickAnimatedNode
+{
+public:
+ QQuickMaterialRippleWaveNode(QQuickMaterialRipple *ripple);
+
+ void exit();
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ qreal m_from = 0;
+ qreal m_to = 0;
+ qreal m_value = 0;
+ WavePhase m_phase = WaveEnter;
+ QPointF m_anchor;
+ QRectF m_bounds;
+};
+
+QQuickMaterialRippleWaveNode::QQuickMaterialRippleWaveNode(QQuickMaterialRipple *ripple)
+ : QQuickAnimatedNode(ripple)
+{
+ start(qRound(1000.0 * qSqrt(ripple->diameter() / 2.0 / WAVE_TOUCH_DOWN_ACCELERATION)));
+
+ QSGOpacityNode *opacityNode = new QSGOpacityNode;
+ appendChildNode(opacityNode);
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(ripple);
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ opacityNode->appendChildNode(rectNode);
+}
+
+void QQuickMaterialRippleWaveNode::exit()
+{
+ m_phase = WaveExit;
+ m_from = m_value;
+ setDuration(WAVE_OPACITY_DECAY_DURATION);
+ restart();
+ connect(this, &QQuickAnimatedNode::stopped, this, &QObject::deleteLater);
+}
+
+void QQuickMaterialRippleWaveNode::updateCurrentTime(int time)
+{
+ qreal p = 1.0;
+ if (duration() > 0)
+ p = time / static_cast<qreal>(duration());
+
+ m_value = m_from + (m_to - m_from) * p;
+ p = m_value / m_to;
+
+ const qreal dx = (1.0 - p) * (m_anchor.x() - m_bounds.width() / 2);
+ const qreal dy = (1.0 - p) * (m_anchor.y() - m_bounds.height() / 2);
+
+ QMatrix4x4 m;
+ m.translate(qRound((m_bounds.width() - m_value) / 2 + dx),
+ qRound((m_bounds.height() - m_value) / 2 + dy));
+ setMatrix(m);
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+ qreal opacity = 1.0;
+ if (m_phase == WaveExit)
+ opacity -= static_cast<qreal>(time) / WAVE_OPACITY_DECAY_DURATION;
+ opacityNode->setOpacity(opacity);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+ rectNode->setRect(QRectF(0, 0, m_value, m_value));
+ rectNode->setRadius(m_value / 2);
+ rectNode->update();
+}
+
+void QQuickMaterialRippleWaveNode::sync(QQuickItem *item)
+{
+ QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
+ m_to = ripple->diameter();
+ m_anchor = ripple->anchorPoint();
+ m_bounds = ripple->boundingRect();
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+ rectNode->setColor(ripple->color());
+}
+
+class QQuickMaterialRippleBackgroundNode : public QQuickAnimatedNode
+{
+ Q_OBJECT
+
+public:
+ QQuickMaterialRippleBackgroundNode(QQuickMaterialRipple *ripple);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ bool m_active = false;
+};
+
+QQuickMaterialRippleBackgroundNode::QQuickMaterialRippleBackgroundNode(QQuickMaterialRipple *ripple)
+ : QQuickAnimatedNode(ripple)
+{
+ setDuration(OPACITY_ENTER_DURATION_FAST);
+
+ QSGOpacityNode *opacityNode = new QSGOpacityNode;
+ opacityNode->setOpacity(0.0);
+ appendChildNode(opacityNode);
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(ripple);
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ opacityNode->appendChildNode(rectNode);
+}
+
+void QQuickMaterialRippleBackgroundNode::updateCurrentTime(int time)
+{
+ qreal opacity = time / static_cast<qreal>(duration());
+ if (!m_active)
+ opacity = 1.0 - opacity;
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+ opacityNode->setOpacity(opacity);
+}
+
+void QQuickMaterialRippleBackgroundNode::sync(QQuickItem *item)
+{
+ QQuickMaterialRipple *ripple = static_cast<QQuickMaterialRipple *>(item);
+ if (m_active != ripple->isActive()) {
+ m_active = ripple->isActive();
+ setDuration(m_active ? OPACITY_ENTER_DURATION_FAST : WAVE_OPACITY_DECAY_DURATION);
+ restart();
+ }
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ const qreal w = ripple->width();
+ const qreal h = ripple->height();
+ const qreal sz = qSqrt(w * w + h * h);
+
+ QMatrix4x4 matrix;
+ if (qFuzzyIsNull(ripple->clipRadius())) {
+ matrix.translate(qRound((w - sz) / 2), qRound((h - sz) / 2));
+ rectNode->setRect(QRectF(0, 0, sz, sz));
+ rectNode->setRadius(sz / 2);
+ } else {
+ rectNode->setRect(QRectF(0, 0, w, h));
+ rectNode->setRadius(ripple->clipRadius());
+ }
+
+ setMatrix(matrix);
+ rectNode->setColor(ripple->color());
+ rectNode->update();
+}
+
+QQuickMaterialRipple::QQuickMaterialRipple(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+bool QQuickMaterialRipple::isActive() const
+{
+ return m_active;
+}
+
+void QQuickMaterialRipple::setActive(bool active)
+{
+ if (active == m_active)
+ return;
+
+ m_active = active;
+ update();
+}
+
+QColor QQuickMaterialRipple::color() const
+{
+ return m_color;
+}
+
+void QQuickMaterialRipple::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+qreal QQuickMaterialRipple::clipRadius() const
+{
+ return m_clipRadius;
+}
+
+void QQuickMaterialRipple::setClipRadius(qreal radius)
+{
+ if (qFuzzyCompare(m_clipRadius, radius))
+ return;
+
+ m_clipRadius = radius;
+ setClip(!qFuzzyIsNull(radius));
+ update();
+}
+
+bool QQuickMaterialRipple::isPressed() const
+{
+ return m_pressed;
+}
+
+void QQuickMaterialRipple::setPressed(bool pressed)
+{
+ if (pressed == m_pressed)
+ return;
+
+ m_pressed = pressed;
+
+ if (!isEnabled()) {
+ exitWave();
+ return;
+ }
+
+ if (pressed) {
+ if (m_trigger == Press)
+ prepareWave();
+ else
+ exitWave();
+ } else {
+ if (m_trigger == Release)
+ enterWave();
+ else
+ exitWave();
+ }
+}
+
+QQuickMaterialRipple::Trigger QQuickMaterialRipple::trigger() const
+{
+ return m_trigger;
+}
+
+void QQuickMaterialRipple::setTrigger(Trigger trigger)
+{
+ m_trigger = trigger;
+}
+
+QPointF QQuickMaterialRipple::anchorPoint() const
+{
+ const QRectF bounds = boundingRect();
+ const QPointF center = bounds.center();
+ if (!m_anchor)
+ return center;
+
+ QPointF anchorPoint = bounds.center();
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(m_anchor))
+ anchorPoint = QQuickAbstractButtonPrivate::get(button)->pressPoint;
+ anchorPoint = mapFromItem(m_anchor, anchorPoint);
+
+ // calculate whether the anchor point is within the ripple circle bounds,
+ // that is, whether waves should start expanding from the anchor point
+ const qreal r = qSqrt(bounds.width() * bounds.width() + bounds.height() * bounds.height()) / 2;
+ if (QLineF(center, anchorPoint).length() < r)
+ return anchorPoint;
+
+ // if the anchor point is outside the ripple circle bounds, start expanding
+ // from the intersection point of the ripple circle and a line from its center
+ // to the the anchor point
+ const qreal p = qAtan2(anchorPoint.y() - center.y(), anchorPoint.x() - center.x());
+ return QPointF(center.x() + r * qCos(p), center.y() + r * qSin(p));
+}
+
+QQuickItem *QQuickMaterialRipple::anchor() const
+{
+ return m_anchor;
+}
+
+void QQuickMaterialRipple::setAnchor(QQuickItem *item)
+{
+ m_anchor = item;
+}
+
+qreal QQuickMaterialRipple::diameter() const
+{
+ const qreal w = width();
+ const qreal h = height();
+ return qSqrt(w * w + h * h);
+}
+
+void QQuickMaterialRipple::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+}
+
+QSGNode *QQuickMaterialRipple::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QQuickItemPrivate *d = QQuickItemPrivate::get(this);
+ QQuickDefaultClipNode *clipNode = d->clipNode();
+ if (clipNode) {
+ // TODO: QTBUG-51894
+ // clipNode->setRadius(m_clipRadius);
+ clipNode->setRect(boundingRect());
+ clipNode->update();
+ }
+
+ QSGNode *container = oldNode;
+ if (!container)
+ container = new QSGNode;
+
+ QQuickMaterialRippleBackgroundNode *backgroundNode = static_cast<QQuickMaterialRippleBackgroundNode *>(container->firstChild());
+ if (!backgroundNode) {
+ backgroundNode = new QQuickMaterialRippleBackgroundNode(this);
+ backgroundNode->setObjectName(objectName());
+ container->appendChildNode(backgroundNode);
+ }
+ backgroundNode->sync(this);
+
+ // enter new waves
+ int i = m_waves;
+ QQuickMaterialRippleWaveNode *enterNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
+ while (i-- > 0) {
+ if (!enterNode) {
+ enterNode = new QQuickMaterialRippleWaveNode(this);
+ container->appendChildNode(enterNode);
+ }
+ enterNode->sync(this);
+ enterNode = static_cast<QQuickMaterialRippleWaveNode *>(enterNode->nextSibling());
+ }
+
+ // exit old waves
+ int j = container->childCount() - 1 - m_waves;
+ while (j-- > 0) {
+ QQuickMaterialRippleWaveNode *exitNode = static_cast<QQuickMaterialRippleWaveNode *>(backgroundNode->nextSibling());
+ if (exitNode) {
+ exitNode->exit();
+ exitNode->sync(this);
+ }
+ }
+
+ return container;
+}
+
+void QQuickMaterialRipple::timerEvent(QTimerEvent *event)
+{
+ QQuickItem::timerEvent(event);
+
+ if (event->timerId() == m_enterDelay)
+ enterWave();
+}
+
+void QQuickMaterialRipple::prepareWave()
+{
+ if (m_enterDelay <= 0)
+ m_enterDelay = startTimer(RIPPLE_ENTER_DELAY);
+}
+
+void QQuickMaterialRipple::enterWave()
+{
+ if (m_enterDelay > 0) {
+ killTimer(m_enterDelay);
+ m_enterDelay = 0;
+ }
+
+ ++m_waves;
+ update();
+}
+
+void QQuickMaterialRipple::exitWave()
+{
+ if (m_enterDelay > 0) {
+ killTimer(m_enterDelay);
+ m_enterDelay = 0;
+ }
+
+ if (m_waves > 0) {
+ --m_waves;
+ update();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmaterialripple_p.cpp"
+
+#include "qquickmaterialripple.moc"
diff --git a/src/quickcontrols2/material/impl/qquickmaterialripple_p.h b/src/quickcontrols2/material/impl/qquickmaterialripple_p.h
new file mode 100644
index 0000000000..517283896a
--- /dev/null
+++ b/src/quickcontrols2/material/impl/qquickmaterialripple_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMATERIALRIPPLE_P_H
+#define QQUICKMATERIALRIPPLE_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/qquickitem.h>
+#include <QtGui/qcolor.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMaterialRipple : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(qreal clipRadius READ clipRadius WRITE setClipRadius FINAL)
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed FINAL)
+ Q_PROPERTY(bool active READ isActive WRITE setActive FINAL)
+ Q_PROPERTY(QQuickItem *anchor READ anchor WRITE setAnchor FINAL)
+ Q_PROPERTY(Trigger trigger READ trigger WRITE setTrigger FINAL)
+ QML_NAMED_ELEMENT(Ripple)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ QQuickMaterialRipple(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ qreal clipRadius() const;
+ void setClipRadius(qreal radius);
+
+ bool isActive() const;
+ void setActive(bool active);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ enum Trigger { Press, Release };
+ Q_ENUM (Trigger)
+
+ Trigger trigger() const;
+ void setTrigger(Trigger trigger);
+
+ QPointF anchorPoint() const;
+
+ QQuickItem *anchor() const;
+ void setAnchor(QQuickItem *anchor);
+
+ qreal diameter() const;
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+ void timerEvent(QTimerEvent *event) override;
+
+ void prepareWave();
+ void enterWave();
+ void exitWave();
+
+private:
+ bool m_active = false;
+ bool m_pressed = false;
+ int m_waves = 0;
+ int m_enterDelay = 0;
+ Trigger m_trigger = Press;
+ qreal m_clipRadius = 0.0;
+ QColor m_color;
+ QQuickItem *m_anchor = nullptr;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMaterialRipple)
+
+#endif // QQUICKMATERIALRIPPLE_P_H
diff --git a/src/quickcontrols2/material/material.pri b/src/quickcontrols2/material/material.pri
new file mode 100644
index 0000000000..2c17f71f65
--- /dev/null
+++ b/src/quickcontrols2/material/material.pri
@@ -0,0 +1,61 @@
+HEADERS += \
+ $$PWD/qquickmaterialstyle_p.h \
+ $$PWD/qquickmaterialtheme_p.h
+
+SOURCES += \
+ $$PWD/qquickmaterialstyle.cpp \
+ $$PWD/qquickmaterialtheme.cpp
+
+QML_FILES += \
+ $$PWD/ApplicationWindow.qml \
+ $$PWD/BusyIndicator.qml \
+ $$PWD/Button.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/CheckDelegate.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/DelayButton.qml \
+ $$PWD/Dial.qml \
+ $$PWD/Dialog.qml \
+ $$PWD/DialogButtonBox.qml \
+ $$PWD/Drawer.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/HorizontalHeaderView.qml \
+ $$PWD/ItemDelegate.qml \
+ $$PWD/Label.qml \
+ $$PWD/Menu.qml \
+ $$PWD/MenuBar.qml \
+ $$PWD/MenuBarItem.qml \
+ $$PWD/MenuItem.qml \
+ $$PWD/MenuSeparator.qml \
+ $$PWD/Page.qml \
+ $$PWD/PageIndicator.qml \
+ $$PWD/Pane.qml \
+ $$PWD/Popup.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/RadioDelegate.qml \
+ $$PWD/RangeSlider.qml \
+ $$PWD/RoundButton.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollIndicator.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/SplitView.qml \
+ $$PWD/StackView.qml \
+ $$PWD/SwipeDelegate.qml \
+ $$PWD/SwipeView.qml \
+ $$PWD/Switch.qml \
+ $$PWD/SwitchDelegate.qml \
+ $$PWD/TabBar.qml \
+ $$PWD/TabButton.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TextField.qml \
+ $$PWD/ToolBar.qml \
+ $$PWD/ToolButton.qml \
+ $$PWD/ToolSeparator.qml \
+ $$PWD/ToolTip.qml \
+ $$PWD/Tumbler.qml \
+ $$PWD/VerticalHeaderView.qml
diff --git a/src/quickcontrols2/material/qquickmaterialstyle.cpp b/src/quickcontrols2/material/qquickmaterialstyle.cpp
new file mode 100644
index 0000000000..59851141db
--- /dev/null
+++ b/src/quickcontrols2/material/qquickmaterialstyle.cpp
@@ -0,0 +1,1397 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialstyle_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const QRgb colors[][14] = {
+ // Red
+ {
+ 0xFFFFEBEE, // Shade50
+ 0xFFFFCDD2, // Shade100
+ 0xFFEF9A9A, // Shade200
+ 0xFFE57373, // Shade300
+ 0xFFEF5350, // Shade400
+ 0xFFF44336, // Shade500
+ 0xFFE53935, // Shade600
+ 0xFFD32F2F, // Shade700
+ 0xFFC62828, // Shade800
+ 0xFFB71C1C, // Shade900
+ 0xFFFF8A80, // ShadeA100
+ 0xFFFF5252, // ShadeA200
+ 0xFFFF1744, // ShadeA400
+ 0xFFD50000 // ShadeA700
+ },
+ // Pink
+ {
+ 0xFFFCE4EC, // Shade50
+ 0xFFF8BBD0, // Shade100
+ 0xFFF48FB1, // Shade200
+ 0xFFF06292, // Shade300
+ 0xFFEC407A, // Shade400
+ 0xFFE91E63, // Shade500
+ 0xFFD81B60, // Shade600
+ 0xFFC2185B, // Shade700
+ 0xFFAD1457, // Shade800
+ 0xFF880E4F, // Shade900
+ 0xFFFF80AB, // ShadeA100
+ 0xFFFF4081, // ShadeA200
+ 0xFFF50057, // ShadeA400
+ 0xFFC51162 // ShadeA700
+ },
+ // Purple
+ {
+ 0xFFF3E5F5, // Shade50
+ 0xFFE1BEE7, // Shade100
+ 0xFFCE93D8, // Shade200
+ 0xFFBA68C8, // Shade300
+ 0xFFAB47BC, // Shade400
+ 0xFF9C27B0, // Shade500
+ 0xFF8E24AA, // Shade600
+ 0xFF7B1FA2, // Shade700
+ 0xFF6A1B9A, // Shade800
+ 0xFF4A148C, // Shade900
+ 0xFFEA80FC, // ShadeA100
+ 0xFFE040FB, // ShadeA200
+ 0xFFD500F9, // ShadeA400
+ 0xFFAA00FF // ShadeA700
+ },
+ // DeepPurple
+ {
+ 0xFFEDE7F6, // Shade50
+ 0xFFD1C4E9, // Shade100
+ 0xFFB39DDB, // Shade200
+ 0xFF9575CD, // Shade300
+ 0xFF7E57C2, // Shade400
+ 0xFF673AB7, // Shade500
+ 0xFF5E35B1, // Shade600
+ 0xFF512DA8, // Shade700
+ 0xFF4527A0, // Shade800
+ 0xFF311B92, // Shade900
+ 0xFFB388FF, // ShadeA100
+ 0xFF7C4DFF, // ShadeA200
+ 0xFF651FFF, // ShadeA400
+ 0xFF6200EA // ShadeA700
+ },
+ // Indigo
+ {
+ 0xFFE8EAF6, // Shade50
+ 0xFFC5CAE9, // Shade100
+ 0xFF9FA8DA, // Shade200
+ 0xFF7986CB, // Shade300
+ 0xFF5C6BC0, // Shade400
+ 0xFF3F51B5, // Shade500
+ 0xFF3949AB, // Shade600
+ 0xFF303F9F, // Shade700
+ 0xFF283593, // Shade800
+ 0xFF1A237E, // Shade900
+ 0xFF8C9EFF, // ShadeA100
+ 0xFF536DFE, // ShadeA200
+ 0xFF3D5AFE, // ShadeA400
+ 0xFF304FFE // ShadeA700
+ },
+ // Blue
+ {
+ 0xFFE3F2FD, // Shade50
+ 0xFFBBDEFB, // Shade100
+ 0xFF90CAF9, // Shade200
+ 0xFF64B5F6, // Shade300
+ 0xFF42A5F5, // Shade400
+ 0xFF2196F3, // Shade500
+ 0xFF1E88E5, // Shade600
+ 0xFF1976D2, // Shade700
+ 0xFF1565C0, // Shade800
+ 0xFF0D47A1, // Shade900
+ 0xFF82B1FF, // ShadeA100
+ 0xFF448AFF, // ShadeA200
+ 0xFF2979FF, // ShadeA400
+ 0xFF2962FF // ShadeA700
+ },
+ // LightBlue
+ {
+ 0xFFE1F5FE, // Shade50
+ 0xFFB3E5FC, // Shade100
+ 0xFF81D4FA, // Shade200
+ 0xFF4FC3F7, // Shade300
+ 0xFF29B6F6, // Shade400
+ 0xFF03A9F4, // Shade500
+ 0xFF039BE5, // Shade600
+ 0xFF0288D1, // Shade700
+ 0xFF0277BD, // Shade800
+ 0xFF01579B, // Shade900
+ 0xFF80D8FF, // ShadeA100
+ 0xFF40C4FF, // ShadeA200
+ 0xFF00B0FF, // ShadeA400
+ 0xFF0091EA // ShadeA700
+ },
+ // Cyan
+ {
+ 0xFFE0F7FA, // Shade50
+ 0xFFB2EBF2, // Shade100
+ 0xFF80DEEA, // Shade200
+ 0xFF4DD0E1, // Shade300
+ 0xFF26C6DA, // Shade400
+ 0xFF00BCD4, // Shade500
+ 0xFF00ACC1, // Shade600
+ 0xFF0097A7, // Shade700
+ 0xFF00838F, // Shade800
+ 0xFF006064, // Shade900
+ 0xFF84FFFF, // ShadeA100
+ 0xFF18FFFF, // ShadeA200
+ 0xFF00E5FF, // ShadeA400
+ 0xFF00B8D4 // ShadeA700
+ },
+ // Teal
+ {
+ 0xFFE0F2F1, // Shade50
+ 0xFFB2DFDB, // Shade100
+ 0xFF80CBC4, // Shade200
+ 0xFF4DB6AC, // Shade300
+ 0xFF26A69A, // Shade400
+ 0xFF009688, // Shade500
+ 0xFF00897B, // Shade600
+ 0xFF00796B, // Shade700
+ 0xFF00695C, // Shade800
+ 0xFF004D40, // Shade900
+ 0xFFA7FFEB, // ShadeA100
+ 0xFF64FFDA, // ShadeA200
+ 0xFF1DE9B6, // ShadeA400
+ 0xFF00BFA5 // ShadeA700
+ },
+ // Green
+ {
+ 0xFFE8F5E9, // Shade50
+ 0xFFC8E6C9, // Shade100
+ 0xFFA5D6A7, // Shade200
+ 0xFF81C784, // Shade300
+ 0xFF66BB6A, // Shade400
+ 0xFF4CAF50, // Shade500
+ 0xFF43A047, // Shade600
+ 0xFF388E3C, // Shade700
+ 0xFF2E7D32, // Shade800
+ 0xFF1B5E20, // Shade900
+ 0xFFB9F6CA, // ShadeA100
+ 0xFF69F0AE, // ShadeA200
+ 0xFF00E676, // ShadeA400
+ 0xFF00C853 // ShadeA700
+ },
+ // LightGreen
+ {
+ 0xFFF1F8E9, // Shade50
+ 0xFFDCEDC8, // Shade100
+ 0xFFC5E1A5, // Shade200
+ 0xFFAED581, // Shade300
+ 0xFF9CCC65, // Shade400
+ 0xFF8BC34A, // Shade500
+ 0xFF7CB342, // Shade600
+ 0xFF689F38, // Shade700
+ 0xFF558B2F, // Shade800
+ 0xFF33691E, // Shade900
+ 0xFFCCFF90, // ShadeA100
+ 0xFFB2FF59, // ShadeA200
+ 0xFF76FF03, // ShadeA400
+ 0xFF64DD17 // ShadeA700
+ },
+ // Lime
+ {
+ 0xFFF9FBE7, // Shade50
+ 0xFFF0F4C3, // Shade100
+ 0xFFE6EE9C, // Shade200
+ 0xFFDCE775, // Shade300
+ 0xFFD4E157, // Shade400
+ 0xFFCDDC39, // Shade500
+ 0xFFC0CA33, // Shade600
+ 0xFFAFB42B, // Shade700
+ 0xFF9E9D24, // Shade800
+ 0xFF827717, // Shade900
+ 0xFFF4FF81, // ShadeA100
+ 0xFFEEFF41, // ShadeA200
+ 0xFFC6FF00, // ShadeA400
+ 0xFFAEEA00 // ShadeA700
+ },
+ // Yellow
+ {
+ 0xFFFFFDE7, // Shade50
+ 0xFFFFF9C4, // Shade100
+ 0xFFFFF59D, // Shade200
+ 0xFFFFF176, // Shade300
+ 0xFFFFEE58, // Shade400
+ 0xFFFFEB3B, // Shade500
+ 0xFFFDD835, // Shade600
+ 0xFFFBC02D, // Shade700
+ 0xFFF9A825, // Shade800
+ 0xFFF57F17, // Shade900
+ 0xFFFFFF8D, // ShadeA100
+ 0xFFFFFF00, // ShadeA200
+ 0xFFFFEA00, // ShadeA400
+ 0xFFFFD600 // ShadeA700
+ },
+ // Amber
+ {
+ 0xFFFFF8E1, // Shade50
+ 0xFFFFECB3, // Shade100
+ 0xFFFFE082, // Shade200
+ 0xFFFFD54F, // Shade300
+ 0xFFFFCA28, // Shade400
+ 0xFFFFC107, // Shade500
+ 0xFFFFB300, // Shade600
+ 0xFFFFA000, // Shade700
+ 0xFFFF8F00, // Shade800
+ 0xFFFF6F00, // Shade900
+ 0xFFFFE57F, // ShadeA100
+ 0xFFFFD740, // ShadeA200
+ 0xFFFFC400, // ShadeA400
+ 0xFFFFAB00 // ShadeA700
+ },
+ // Orange
+ {
+ 0xFFFFF3E0, // Shade50
+ 0xFFFFE0B2, // Shade100
+ 0xFFFFCC80, // Shade200
+ 0xFFFFB74D, // Shade300
+ 0xFFFFA726, // Shade400
+ 0xFFFF9800, // Shade500
+ 0xFFFB8C00, // Shade600
+ 0xFFF57C00, // Shade700
+ 0xFFEF6C00, // Shade800
+ 0xFFE65100, // Shade900
+ 0xFFFFD180, // ShadeA100
+ 0xFFFFAB40, // ShadeA200
+ 0xFFFF9100, // ShadeA400
+ 0xFFFF6D00 // ShadeA700
+ },
+ // DeepOrange
+ {
+ 0xFFFBE9E7, // Shade50
+ 0xFFFFCCBC, // Shade100
+ 0xFFFFAB91, // Shade200
+ 0xFFFF8A65, // Shade300
+ 0xFFFF7043, // Shade400
+ 0xFFFF5722, // Shade500
+ 0xFFF4511E, // Shade600
+ 0xFFE64A19, // Shade700
+ 0xFFD84315, // Shade800
+ 0xFFBF360C, // Shade900
+ 0xFFFF9E80, // ShadeA100
+ 0xFFFF6E40, // ShadeA200
+ 0xFFFF3D00, // ShadeA400
+ 0xFFDD2C00 // ShadeA700
+ },
+ // Brown
+ {
+ 0xFFEFEBE9, // Shade50
+ 0xFFD7CCC8, // Shade100
+ 0xFFBCAAA4, // Shade200
+ 0xFFA1887F, // Shade300
+ 0xFF8D6E63, // Shade400
+ 0xFF795548, // Shade500
+ 0xFF6D4C41, // Shade600
+ 0xFF5D4037, // Shade700
+ 0xFF4E342E, // Shade800
+ 0xFF3E2723, // Shade900
+ 0xFF000000, // ShadeA100
+ 0xFF000000, // ShadeA200
+ 0xFF000000, // ShadeA400
+ 0xFF000000 // ShadeA700
+ },
+ // Grey
+ {
+ 0xFFFAFAFA, // Shade50
+ 0xFFF5F5F5, // Shade100
+ 0xFFEEEEEE, // Shade200
+ 0xFFE0E0E0, // Shade300
+ 0xFFBDBDBD, // Shade400
+ 0xFF9E9E9E, // Shade500
+ 0xFF757575, // Shade600
+ 0xFF616161, // Shade700
+ 0xFF424242, // Shade800
+ 0xFF212121, // Shade900
+ 0xFF000000, // ShadeA100
+ 0xFF000000, // ShadeA200
+ 0xFF000000, // ShadeA400
+ 0xFF000000 // ShadeA700
+ },
+ // BlueGrey
+ {
+ 0xFFECEFF1, // Shade50
+ 0xFFCFD8DC, // Shade100
+ 0xFFB0BEC5, // Shade200
+ 0xFF90A4AE, // Shade300
+ 0xFF78909C, // Shade400
+ 0xFF607D8B, // Shade500
+ 0xFF546E7A, // Shade600
+ 0xFF455A64, // Shade700
+ 0xFF37474F, // Shade800
+ 0xFF263238, // Shade900
+ 0xFF000000, // ShadeA100
+ 0xFF000000, // ShadeA200
+ 0xFF000000, // ShadeA400
+ 0xFF000000 // ShadeA700
+ }
+};
+
+// If no value was inherited from a parent or explicitly set, the "global" values are used.
+// The initial, default values of the globals are hard-coded here, but the environment
+// variables and .conf file override them if specified.
+static QQuickMaterialStyle::Theme globalTheme = QQuickMaterialStyle::Light;
+static uint globalPrimary = QQuickMaterialStyle::Indigo;
+static uint globalAccent = QQuickMaterialStyle::Pink;
+static uint globalForeground = 0xDD000000; // primaryTextColorLight
+static uint globalBackground = 0xFFFAFAFA; // backgroundColorLight
+// These represent whether a global foreground/background was set.
+// Each style's m_hasForeground/m_hasBackground are initialized to these values.
+static bool hasGlobalForeground = false;
+static bool hasGlobalBackground = false;
+// These represent whether or not the global color value was specified as one of the
+// values that QColor accepts, as opposed to one of the pre-defined colors like Red.
+static bool globalPrimaryCustom = false;
+static bool globalAccentCustom = false;
+static bool globalForegroundCustom = true;
+static bool globalBackgroundCustom = true;
+// This is global because:
+// 1) The theme needs access to it to determine font sizes.
+// 2) There can only be one variant used for the whole application.
+static QQuickMaterialStyle::Variant globalVariant = QQuickMaterialStyle::Normal;
+
+static const QRgb backgroundColorLight = 0xFFFAFAFA;
+static const QRgb backgroundColorDark = 0xFF303030;
+static const QRgb dialogColorLight = 0xFFFFFFFF;
+static const QRgb dialogColorDark = 0xFF424242;
+static const QRgb primaryTextColorLight = 0xDD000000;
+static const QRgb primaryTextColorDark = 0xFFFFFFFF;
+static const QRgb secondaryTextColorLight = 0x89000000;
+static const QRgb secondaryTextColorDark = 0xB2FFFFFF;
+static const QRgb hintTextColorLight = 0x60000000;
+static const QRgb hintTextColorDark = 0x4CFFFFFF;
+static const QRgb dividerColorLight = 0x1E000000;
+static const QRgb dividerColorDark = 0x1EFFFFFF;
+static const QRgb iconColorLight = 0x89000000;
+static const QRgb iconColorDark = 0xFFFFFFFF;
+static const QRgb iconDisabledColorLight = 0x42000000;
+static const QRgb iconDisabledColorDark = 0x4CFFFFFF;
+static const QRgb raisedButtonColorLight = 0xFFD6D7D7;
+static const QRgb raisedButtonColorDark = 0x3FCCCCCC;
+static const QRgb raisedButtonDisabledColorLight = dividerColorLight;
+static const QRgb raisedButtonDisabledColorDark = dividerColorDark;
+static const QRgb frameColorLight = hintTextColorLight;
+static const QRgb frameColorDark = hintTextColorDark;
+static const QRgb switchUncheckedTrackColorLight = 0x42000000;
+static const QRgb switchUncheckedTrackColorDark = 0x4CFFFFFF;
+static const QRgb switchDisabledTrackColorLight = 0x1E000000;
+static const QRgb switchDisabledTrackColorDark = 0x19FFFFFF;
+static const QRgb rippleColorLight = 0x10000000;
+static const QRgb rippleColorDark = 0x20FFFFFF;
+static const QRgb spinBoxDisabledIconColorLight = 0xFFCCCCCC;
+static const QRgb spinBoxDisabledIconColorDark = 0xFF666666;
+static const QRgb sliderDisabledColorLight = 0xFF9E9E9E;
+static const QRgb sliderDisabledColorDark = 0xFF616161;
+
+static QQuickMaterialStyle::Theme effectiveTheme(QQuickMaterialStyle::Theme theme)
+{
+ if (theme == QQuickMaterialStyle::System)
+ theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickMaterialStyle::Dark : QQuickMaterialStyle::Light;
+ return theme;
+}
+
+QQuickMaterialStyle::QQuickMaterialStyle(QObject *parent) : QQuickAttachedObject(parent),
+ m_customPrimary(globalPrimaryCustom),
+ m_customAccent(globalAccentCustom),
+ m_customForeground(globalForegroundCustom),
+ m_customBackground(globalBackgroundCustom),
+ m_hasForeground(hasGlobalForeground),
+ m_hasBackground(hasGlobalBackground),
+ m_theme(globalTheme),
+ m_primary(globalPrimary),
+ m_accent(globalAccent),
+ m_foreground(globalForeground),
+ m_background(globalBackground)
+{
+ QQuickAttachedObject::init();
+}
+
+QQuickMaterialStyle *QQuickMaterialStyle::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickMaterialStyle(object);
+}
+
+QQuickMaterialStyle::Theme QQuickMaterialStyle::theme() const
+{
+ return m_theme;
+}
+
+void QQuickMaterialStyle::setTheme(Theme theme)
+{
+ if (theme == System)
+ theme = QQuickStylePrivate::isDarkSystemTheme() ? Dark : Light;
+
+ m_explicitTheme = true;
+ if (m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ themeChange();
+ if (!m_customAccent)
+ accentChange();
+ if (!m_hasBackground)
+ backgroundChange();
+ if (!m_hasForeground)
+ foregroundChange();
+}
+
+void QQuickMaterialStyle::inheritTheme(Theme theme)
+{
+ if (m_explicitTheme || m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ themeChange();
+ if (!m_customAccent)
+ accentChange();
+ if (!m_hasBackground)
+ backgroundChange();
+ if (!m_hasForeground)
+ foregroundChange();
+}
+
+void QQuickMaterialStyle::propagateTheme()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
+ if (material)
+ material->inheritTheme(m_theme);
+ }
+}
+
+void QQuickMaterialStyle::resetTheme()
+{
+ if (!m_explicitTheme)
+ return;
+
+ m_explicitTheme = false;
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
+ inheritTheme(material ? material->theme() : globalTheme);
+}
+
+void QQuickMaterialStyle::themeChange()
+{
+ emit themeChanged();
+ emit themeOrAccentChanged();
+ emit primaryHighlightedTextColor();
+ emit buttonColorChanged();
+ emit buttonDisabledColorChanged();
+ emit dialogColorChanged();
+ emit tooltipColorChanged();
+ emit toolBarColorChanged();
+ emit toolTextColorChanged();
+}
+
+QVariant QQuickMaterialStyle::primary() const
+{
+ return primaryColor();
+}
+
+void QQuickMaterialStyle::setPrimary(const QVariant &var)
+{
+ QRgb primary = 0;
+ bool custom = false;
+ if (!variantToRgba(var, "primary", &primary, &custom))
+ return;
+
+ m_explicitPrimary = true;
+ if (m_primary == primary)
+ return;
+
+ m_customPrimary = custom;
+ m_primary = primary;
+ propagatePrimary();
+ primaryChange();
+}
+
+void QQuickMaterialStyle::inheritPrimary(uint primary, bool custom)
+{
+ if (m_explicitPrimary || m_primary == primary)
+ return;
+
+ m_customPrimary = custom;
+ m_primary = primary;
+ propagatePrimary();
+ primaryChange();
+}
+
+void QQuickMaterialStyle::propagatePrimary()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
+ if (material)
+ material->inheritPrimary(m_primary, m_customPrimary);
+ }
+}
+
+void QQuickMaterialStyle::resetPrimary()
+{
+ if (!m_explicitPrimary)
+ return;
+
+ m_customPrimary = false;
+ m_explicitPrimary = false;
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
+ if (material)
+ inheritPrimary(material->m_primary, material->m_customPrimary);
+ else
+ inheritPrimary(globalPrimary, false);
+}
+
+void QQuickMaterialStyle::primaryChange()
+{
+ emit primaryChanged();
+ emit toolBarColorChanged();
+ emit toolTextColorChanged();
+}
+
+QVariant QQuickMaterialStyle::accent() const
+{
+ return accentColor();
+}
+
+void QQuickMaterialStyle::setAccent(const QVariant &var)
+{
+ QRgb accent = 0;
+ bool custom = false;
+ if (!variantToRgba(var, "accent", &accent, &custom))
+ return;
+
+ m_explicitAccent = true;
+ if (m_accent == accent)
+ return;
+
+ m_customAccent = custom;
+ m_accent = accent;
+ propagateAccent();
+ accentChange();
+}
+
+void QQuickMaterialStyle::inheritAccent(uint accent, bool custom)
+{
+ if (m_explicitAccent || m_accent == accent)
+ return;
+
+ m_customAccent = custom;
+ m_accent = accent;
+ propagateAccent();
+ accentChange();
+}
+
+void QQuickMaterialStyle::propagateAccent()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
+ if (material)
+ material->inheritAccent(m_accent, m_customAccent);
+ }
+}
+
+void QQuickMaterialStyle::resetAccent()
+{
+ if (!m_explicitAccent)
+ return;
+
+ m_customAccent = false;
+ m_explicitAccent = false;
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
+ if (material)
+ inheritAccent(material->m_accent, material->m_customAccent);
+ else
+ inheritAccent(globalAccent, false);
+}
+
+void QQuickMaterialStyle::accentChange()
+{
+ emit accentChanged();
+ emit themeOrAccentChanged();
+ emit buttonColorChanged();
+}
+
+QVariant QQuickMaterialStyle::foreground() const
+{
+ if (!m_hasForeground)
+ return QColor::fromRgba(m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
+ if (m_customForeground)
+ return QColor::fromRgba(m_foreground);
+ if (m_foreground > BlueGrey)
+ return QColor();
+ return QColor::fromRgba(colors[m_foreground][Shade500]);
+}
+
+void QQuickMaterialStyle::setForeground(const QVariant &var)
+{
+ QRgb foreground = 0;
+ bool custom = false;
+ if (!variantToRgba(var, "foreground", &foreground, &custom))
+ return;
+
+ m_hasForeground = true;
+ m_explicitForeground = true;
+ if (m_foreground == foreground)
+ return;
+
+ m_customForeground = custom;
+ m_foreground = foreground;
+ propagateForeground();
+ foregroundChange();
+}
+
+void QQuickMaterialStyle::inheritForeground(uint foreground, bool custom, bool has)
+{
+ if (m_explicitForeground || m_foreground == foreground)
+ return;
+
+ m_hasForeground = has;
+ m_customForeground = custom;
+ m_foreground = foreground;
+ propagateForeground();
+ foregroundChange();
+}
+
+void QQuickMaterialStyle::propagateForeground()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
+ if (material)
+ material->inheritForeground(m_foreground, m_customForeground, m_hasForeground);
+ }
+}
+
+void QQuickMaterialStyle::resetForeground()
+{
+ if (!m_explicitForeground)
+ return;
+
+ m_hasForeground = false;
+ m_customForeground = false;
+ m_explicitForeground = false;
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
+ inheritForeground(material ? material->m_foreground : globalForeground, true, material ? material->m_hasForeground : false);
+}
+
+void QQuickMaterialStyle::foregroundChange()
+{
+ emit foregroundChanged();
+ emit primaryHighlightedTextColorChanged();
+ // TODO: This causes a binding loop: see QTBUG-85699 and the comments on its fix
+// emit toolTextColorChanged();
+}
+
+QVariant QQuickMaterialStyle::background() const
+{
+ return backgroundColor();
+}
+
+void QQuickMaterialStyle::setBackground(const QVariant &var)
+{
+ QRgb background = 0;
+ bool custom = false;
+ if (!variantToRgba(var, "background", &background, &custom))
+ return;
+
+ m_hasBackground = true;
+ m_explicitBackground = true;
+ if (m_background == background)
+ return;
+
+ m_customBackground = custom;
+ m_background = background;
+ propagateBackground();
+ backgroundChange();
+}
+
+void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has)
+{
+ if (m_explicitBackground || m_background == background)
+ return;
+
+ m_hasBackground = has;
+ m_customBackground = custom;
+ m_background = background;
+ propagateBackground();
+ backgroundChange();
+}
+
+void QQuickMaterialStyle::propagateBackground()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(child);
+ if (material)
+ material->inheritBackground(m_background, m_customBackground, m_hasBackground);
+ }
+}
+
+void QQuickMaterialStyle::resetBackground()
+{
+ if (!m_explicitBackground)
+ return;
+
+ m_hasBackground = false;
+ m_customBackground = false;
+ m_explicitBackground = false;
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(attachedParent());
+ inheritBackground(material ? material->m_background : globalBackground, true, material ? material->m_hasBackground : false);
+}
+
+void QQuickMaterialStyle::backgroundChange()
+{
+ emit backgroundChanged();
+ emit buttonColorChanged();
+ emit dialogColorChanged();
+ emit tooltipColorChanged();
+ emit toolBarColorChanged();
+}
+
+int QQuickMaterialStyle::elevation() const
+{
+ return m_elevation;
+}
+
+void QQuickMaterialStyle::setElevation(int elevation)
+{
+ if (m_elevation == elevation)
+ return;
+
+ m_elevation = elevation;
+ elevationChange();
+}
+
+void QQuickMaterialStyle::resetElevation()
+{
+ setElevation(0);
+}
+
+void QQuickMaterialStyle::elevationChange()
+{
+ emit elevationChanged();
+ emit buttonDisabledColorChanged();
+}
+
+QColor QQuickMaterialStyle::primaryColor() const
+{
+ if (m_customPrimary)
+ return QColor::fromRgba(m_primary);
+ if (m_primary > BlueGrey)
+ return QColor();
+ return colors[m_primary][Shade500];
+}
+
+QColor QQuickMaterialStyle::accentColor(Shade shade) const
+{
+ if (m_customAccent)
+ return shade == themeShade() ? QColor::fromRgba(m_accent)
+ : this->shade(QColor::fromRgba(m_accent), shade);
+ if (m_accent > BlueGrey)
+ return QColor();
+ return colors[m_accent][shade];
+}
+
+QColor QQuickMaterialStyle::accentColor() const
+{
+ return accentColor(themeShade());
+}
+
+QColor QQuickMaterialStyle::backgroundColor(Shade shade) const
+{
+ if (!m_hasBackground)
+ return QColor::fromRgba(m_theme == Light ? backgroundColorLight : backgroundColorDark);
+ if (m_customBackground)
+ return shade == themeShade() ? QColor::fromRgba(m_background)
+ : this->shade(QColor::fromRgba(m_background), shade);
+ if (m_background > BlueGrey)
+ return QColor();
+ return colors[m_background][shade];
+}
+
+QColor QQuickMaterialStyle::backgroundColor() const
+{
+ return backgroundColor(themeShade());
+}
+
+QColor QQuickMaterialStyle::primaryTextColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? primaryTextColorLight : primaryTextColorDark);
+}
+
+QColor QQuickMaterialStyle::primaryHighlightedTextColor() const
+{
+ if (m_explicitForeground)
+ return primaryTextColor();
+ return QColor::fromRgba(primaryTextColorDark);
+}
+
+QColor QQuickMaterialStyle::secondaryTextColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? secondaryTextColorLight : secondaryTextColorDark);
+}
+
+QColor QQuickMaterialStyle::hintTextColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? hintTextColorLight : hintTextColorDark);
+}
+
+QColor QQuickMaterialStyle::textSelectionColor() const
+{
+ QColor color = accentColor();
+ color.setAlphaF(0.4f);
+ return color;
+}
+
+QColor QQuickMaterialStyle::dropShadowColor() const
+{
+ return QColor::fromRgba(0x40000000);
+}
+
+QColor QQuickMaterialStyle::dividerColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? dividerColorLight : dividerColorDark);
+}
+
+QColor QQuickMaterialStyle::iconColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? iconColorLight : iconColorDark);
+}
+
+QColor QQuickMaterialStyle::iconDisabledColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? iconDisabledColorLight : iconDisabledColorDark);
+}
+
+QColor QQuickMaterialStyle::buttonColor(bool highlighted, bool checked) const
+{
+ Shade shade = themeShade();
+
+ QColor color = Qt::transparent;
+
+ if (m_explicitBackground) {
+ color = backgroundColor(shade);
+ } else if (highlighted) {
+ if (m_theme == Light) {
+ color = accentColor(shade);
+ if (checked)
+ color = color.lighter();
+ } else {
+ // A highlighted + checked button should become darker.
+ color = accentColor(checked ? Shade100 : shade);
+ }
+ } else if (elevation() > 0) {
+ color = QColor::fromRgba(m_theme == Light ? raisedButtonColorLight
+ : raisedButtonColorDark);
+ }
+
+ return color;
+}
+
+QColor QQuickMaterialStyle::buttonColor() const
+{
+ return buttonColor(false);
+}
+
+QColor QQuickMaterialStyle::buttonDisabledColor() const
+{
+ if (elevation() > 0) {
+ return QColor::fromRgba(m_theme == Light ? raisedButtonDisabledColorLight
+ : raisedButtonDisabledColorDark);
+ } else {
+ return Qt::transparent;
+ }
+}
+
+QColor QQuickMaterialStyle::highlightedButtonColor() const
+{
+ return buttonColor(true);
+}
+
+QColor QQuickMaterialStyle::highlightedCheckedButtonColor() const
+{
+ return buttonColor(true, true);
+}
+
+QColor QQuickMaterialStyle::frameColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? frameColorLight : frameColorDark);
+}
+
+QColor QQuickMaterialStyle::rippleColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? rippleColorLight : rippleColorDark);
+}
+
+QColor QQuickMaterialStyle::highlightedRippleColor() const
+{
+ QColor pressColor = accentColor();
+ pressColor.setAlpha(m_theme == Light ? 30 : 50);
+ return pressColor;
+}
+
+QColor QQuickMaterialStyle::switchUncheckedTrackColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? switchUncheckedTrackColorLight : switchUncheckedTrackColorDark);
+}
+
+QColor QQuickMaterialStyle::switchCheckedTrackColor() const
+{
+ QColor trackColor(accentColor());
+ trackColor.setAlphaF(0.5);
+ return trackColor;
+}
+
+QColor QQuickMaterialStyle::switchUncheckedHandleColor() const
+{
+ return m_theme == Light ? color(Grey, Shade50) : color(Grey, Shade400);
+}
+
+QColor QQuickMaterialStyle::switchCheckedHandleColor() const
+{
+ return m_theme == Light ? accentColor() : shade(accentColor(), Shade200);
+}
+
+QColor QQuickMaterialStyle::switchDisabledTrackColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? switchDisabledTrackColorLight : switchDisabledTrackColorDark);
+}
+
+QColor QQuickMaterialStyle::switchDisabledHandleColor() const
+{
+ return m_theme == Light ? color(Grey, Shade400) : color(Grey, Shade800);
+}
+
+QColor QQuickMaterialStyle::scrollBarColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? 0x40000000 : 0x40FFFFFF);
+}
+
+QColor QQuickMaterialStyle::scrollBarHoveredColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? 0x60000000 : 0x60FFFFFF);
+}
+
+QColor QQuickMaterialStyle::scrollBarPressedColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? 0x80000000 : 0x80FFFFFF);
+}
+
+QColor QQuickMaterialStyle::dialogColor() const
+{
+ if (m_hasBackground)
+ return backgroundColor();
+ return QColor::fromRgba(m_theme == Light ? dialogColorLight : dialogColorDark);
+}
+
+QColor QQuickMaterialStyle::backgroundDimColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? 0x99303030 : 0x99fafafa);
+}
+
+QColor QQuickMaterialStyle::listHighlightColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? 0x1e000000 : 0x1effffff);
+}
+
+QColor QQuickMaterialStyle::tooltipColor() const
+{
+ if (m_explicitBackground)
+ return backgroundColor();
+ return color(Grey, Shade700);
+}
+
+QColor QQuickMaterialStyle::toolBarColor() const
+{
+ if (m_explicitBackground)
+ return backgroundColor();
+ return primaryColor();
+}
+
+QColor QQuickMaterialStyle::toolTextColor() const
+{
+ if (m_hasForeground || m_customPrimary)
+ return primaryTextColor();
+
+ switch (m_primary) {
+ case Red:
+ case Pink:
+ case Purple:
+ case DeepPurple:
+ case Indigo:
+ case Blue:
+ case Teal:
+ case DeepOrange:
+ case Brown:
+ case BlueGrey:
+ return QColor::fromRgba(primaryTextColorDark);
+
+ case LightBlue:
+ case Cyan:
+ case Green:
+ case LightGreen:
+ case Lime:
+ case Yellow:
+ case Amber:
+ case Orange:
+ case Grey:
+ return QColor::fromRgba(primaryTextColorLight);
+
+ default:
+ break;
+ }
+
+ return primaryTextColor();
+}
+
+QColor QQuickMaterialStyle::spinBoxDisabledIconColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? spinBoxDisabledIconColorLight : spinBoxDisabledIconColorDark);
+}
+
+QColor QQuickMaterialStyle::sliderDisabledColor() const
+{
+ return QColor::fromRgba(m_theme == Light ? sliderDisabledColorLight : sliderDisabledColorDark);
+}
+
+QColor QQuickMaterialStyle::color(QQuickMaterialStyle::Color color, QQuickMaterialStyle::Shade shade) const
+{
+ int count = sizeof(colors) / sizeof(colors[0]);
+ if (color < 0 || color >= count)
+ return QColor();
+
+ count = sizeof(colors[0]) / sizeof(colors[0][0]);
+ if (shade < 0 || shade >= count)
+ return QColor();
+
+ return colors[color][shade];
+}
+
+static QColor lighterShade(const QColor &color, qreal amount)
+{
+ QColor hsl = color.toHsl();
+ hsl.setHslF(hsl.hueF(), hsl.saturationF(), qBound<qreal>(0.0, hsl.lightnessF() + amount, 1.0), color.alphaF());
+ return hsl.convertTo(color.spec());
+}
+
+static QColor darkerShade(const QColor &color, qreal amount)
+{
+ QColor hsl = color.toHsl();
+ hsl.setHslF(hsl.hueF(), hsl.saturationF(), qBound<qreal>(0.0, hsl.lightnessF() - amount, 1.0), color.alphaF());
+ return hsl.convertTo(color.spec());
+}
+
+QQuickMaterialStyle::Shade QQuickMaterialStyle::themeShade() const
+{
+ return m_theme == Light ? Shade500 : Shade200;
+}
+
+/*
+ * The following lightness values originate from the Material Design Color Generator project.
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015 mbitson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+// Returns the same color, if shade == themeShade()
+QColor QQuickMaterialStyle::shade(const QColor &color, Shade shade) const
+{
+ switch (shade) {
+ case Shade50:
+ return lighterShade(color, m_theme == Light ? 0.52 : 0.26);
+ case Shade100:
+ return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
+ case Shade200:
+ return m_theme == Light ? lighterShade(color, 0.26) : color;
+ case Shade300:
+ return m_theme == Light ? lighterShade(color, 0.12) : darkerShade(color, 0.14);
+ case Shade400:
+ return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
+ case Shade500:
+ return m_theme == Light ? color : darkerShade(color, 0.26);
+ case Shade600:
+ return darkerShade(color, m_theme == Light ? 0.06 : 0.32);
+ case Shade700:
+ return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
+ case Shade800:
+ return darkerShade(color, m_theme == Light ? 0.18 : 0.44);
+ case Shade900:
+ return darkerShade(color, m_theme == Light ? 0.24 : 0.50);
+ case ShadeA100:
+ return lighterShade(color, m_theme == Light ? 0.54 : 0.28);
+ case ShadeA200:
+ return lighterShade(color, m_theme == Light ? 0.37 : 0.11);
+ case ShadeA400:
+ return m_theme == Light ? lighterShade(color, 0.06) : darkerShade(color, 0.20);
+ case ShadeA700:
+ return darkerShade(color, m_theme == Light ? 0.12 : 0.38);
+ default:
+ Q_UNREACHABLE();
+ return QColor();
+ }
+}
+
+int QQuickMaterialStyle::touchTarget() const
+{
+ // https://material.io/guidelines/components/buttons.html#buttons-style
+ return globalVariant == Dense ? 44 : 48;
+}
+
+int QQuickMaterialStyle::buttonHeight() const
+{
+ // https://material.io/guidelines/components/buttons.html#buttons-style
+ return globalVariant == Dense ? 32 : 36;
+}
+
+int QQuickMaterialStyle::delegateHeight() const
+{
+ // https://material.io/guidelines/components/lists.html#lists-specs
+ return globalVariant == Dense ? 40 : 48;
+}
+
+int QQuickMaterialStyle::dialogButtonBoxHeight() const
+{
+ return globalVariant == Dense ? 48 : 52;
+}
+
+int QQuickMaterialStyle::frameVerticalPadding() const
+{
+ return globalVariant == Dense ? 8 : 12;
+}
+
+int QQuickMaterialStyle::menuItemHeight() const
+{
+ // https://material.io/guidelines/components/menus.html#menus-simple-menus
+ return globalVariant == Dense ? 32 : 48;
+}
+
+int QQuickMaterialStyle::menuItemVerticalPadding() const
+{
+ return globalVariant == Dense ? 8 : 12;
+}
+
+int QQuickMaterialStyle::switchDelegateVerticalPadding() const
+{
+ // SwitchDelegate's indicator is much larger than the others due to the shadow,
+ // so we must reduce its padding to ensure its implicitHeight is 40 when dense.
+ return globalVariant == Dense ? 4 : 8;
+}
+
+int QQuickMaterialStyle::tooltipHeight() const
+{
+ // https://material.io/guidelines/components/tooltips.html
+ return globalVariant == Dense ? 22 : 32;
+}
+
+QQuickMaterialStyle::Variant QQuickMaterialStyle::variant()
+{
+ return globalVariant;
+}
+
+template <typename Enum>
+static Enum toEnumValue(const QByteArray &value, bool *ok)
+{
+ QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
+ return static_cast<Enum>(enumeration.keyToValue(value, ok));
+}
+
+static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
+{
+ QByteArray value = qgetenv(env);
+#if QT_CONFIG(settings)
+ if (value.isNull() && !settings.isNull())
+ value = settings->value(name).toByteArray();
+#endif
+ return value;
+}
+
+void QQuickMaterialStyle::initGlobals()
+{
+ QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Material"));
+
+ bool ok = false;
+ QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_THEME", settings, QStringLiteral("Theme"));
+ Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
+ if (ok)
+ globalTheme = effectiveTheme(themeEnum);
+ else if (!themeValue.isEmpty())
+ qWarning().nospace().noquote() << "Material: unknown theme value: " << themeValue;
+
+ QByteArray variantValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_VARIANT", settings, QStringLiteral("Variant"));
+ Variant variantEnum = toEnumValue<Variant>(variantValue, &ok);
+ if (ok)
+ globalVariant = variantEnum;
+ else if (!variantValue.isEmpty())
+ qWarning().nospace().noquote() << "Material: unknown variant value: " << variantValue;
+
+ QByteArray primaryValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_PRIMARY", settings, QStringLiteral("Primary"));
+ Color primaryEnum = toEnumValue<Color>(primaryValue, &ok);
+ if (ok) {
+ globalPrimaryCustom = false;
+ globalPrimary = primaryEnum;
+ } else {
+ QColor color(primaryValue.constData());
+ if (color.isValid()) {
+ globalPrimaryCustom = true;
+ globalPrimary = color.rgba();
+ } else if (!primaryValue.isEmpty()) {
+ qWarning().nospace().noquote() << "Material: unknown primary value: " << primaryValue;
+ }
+ }
+
+ QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_ACCENT", settings, QStringLiteral("Accent"));
+ Color accentEnum = toEnumValue<Color>(accentValue, &ok);
+ if (ok) {
+ globalAccentCustom = false;
+ globalAccent = accentEnum;
+ } else if (!accentValue.isEmpty()) {
+ QColor color(accentValue.constData());
+ if (color.isValid()) {
+ globalAccentCustom = true;
+ globalAccent = color.rgba();
+ } else {
+ qWarning().nospace().noquote() << "Material: unknown accent value: " << accentValue;
+ }
+ }
+
+ QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_FOREGROUND", settings, QStringLiteral("Foreground"));
+ Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok);
+ if (ok) {
+ globalForegroundCustom = false;
+ globalForeground = foregroundEnum;
+ hasGlobalForeground = true;
+ } else if (!foregroundValue.isEmpty()) {
+ QColor color(foregroundValue.constData());
+ if (color.isValid()) {
+ globalForegroundCustom = true;
+ globalForeground = color.rgba();
+ hasGlobalForeground = true;
+ } else {
+ qWarning().nospace().noquote() << "Material: unknown foreground value: " << foregroundValue;
+ }
+ }
+
+ QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_MATERIAL_BACKGROUND", settings, QStringLiteral("Background"));
+ Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok);
+ if (ok) {
+ globalBackgroundCustom = false;
+ globalBackground = backgroundEnum;
+ hasGlobalBackground = true;
+ } else if (!backgroundValue.isEmpty()) {
+ QColor color(backgroundValue.constData());
+ if (color.isValid()) {
+ globalBackgroundCustom = true;
+ globalBackground = color.rgba();
+ hasGlobalBackground = true;
+ } else {
+ qWarning().nospace().noquote() << "Material: unknown background value: " << backgroundValue;
+ }
+ }
+}
+
+void QQuickMaterialStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+{
+ Q_UNUSED(oldParent);
+ QQuickMaterialStyle *material = qobject_cast<QQuickMaterialStyle *>(newParent);
+ if (material) {
+ inheritPrimary(material->m_primary, material->m_customPrimary);
+ inheritAccent(material->m_accent, material->m_customAccent);
+ inheritForeground(material->m_foreground, material->m_customForeground, material->m_hasForeground);
+ inheritBackground(material->m_background, material->m_customBackground, material->m_hasBackground);
+ inheritTheme(material->theme());
+ }
+}
+
+bool QQuickMaterialStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba, bool *custom) const
+{
+ *custom = false;
+ if (var.metaType().id() == QMetaType::Int) {
+ int val = var.toInt();
+ if (val > BlueGrey) {
+ qmlWarning(parent()) << "unknown Material." << name << " value: " << val;
+ return false;
+ }
+ *rgba = val;
+ } else {
+ int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
+ if (val != -1) {
+ *rgba = val;
+ } else {
+ QColor color(var.toString());
+ if (!color.isValid()) {
+ qmlWarning(parent()) << "unknown Material." << name << " value: " << var.toString();
+ return false;
+ }
+ *custom = true;
+ *rgba = color.rgba();
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmaterialstyle_p.cpp"
diff --git a/src/quickcontrols2/material/qquickmaterialstyle_p.h b/src/quickcontrols2/material/qquickmaterialstyle_p.h
new file mode 100644
index 0000000000..dea1805a56
--- /dev/null
+++ b/src/quickcontrols2/material/qquickmaterialstyle_p.h
@@ -0,0 +1,336 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMATERIALSTYLE_P_H
+#define QQUICKMATERIALSTYLE_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 <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMaterialStyle : public QQuickAttachedObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Theme theme READ theme WRITE setTheme RESET resetTheme NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QVariant primary READ primary WRITE setPrimary RESET resetPrimary NOTIFY primaryChanged FINAL)
+ Q_PROPERTY(QVariant accent READ accent WRITE setAccent RESET resetAccent NOTIFY accentChanged FINAL)
+ Q_PROPERTY(QVariant foreground READ foreground WRITE setForeground RESET resetForeground NOTIFY foregroundChanged FINAL)
+ Q_PROPERTY(QVariant background READ background WRITE setBackground RESET resetBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(int elevation READ elevation WRITE setElevation RESET resetElevation NOTIFY elevationChanged FINAL)
+
+ Q_PROPERTY(QColor primaryColor READ primaryColor NOTIFY primaryChanged FINAL) // TODO: remove?
+ Q_PROPERTY(QColor accentColor READ accentColor NOTIFY accentChanged FINAL) // TODO: remove?
+ Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QColor primaryTextColor READ primaryTextColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor primaryHighlightedTextColor READ primaryHighlightedTextColor NOTIFY primaryHighlightedTextColorChanged FINAL)
+ Q_PROPERTY(QColor secondaryTextColor READ secondaryTextColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor hintTextColor READ hintTextColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor textSelectionColor READ textSelectionColor NOTIFY themeOrAccentChanged FINAL)
+ Q_PROPERTY(QColor dropShadowColor READ dropShadowColor CONSTANT FINAL)
+ Q_PROPERTY(QColor dividerColor READ dividerColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor iconColor READ iconColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor iconDisabledColor READ iconDisabledColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor buttonColor READ buttonColor NOTIFY buttonColorChanged FINAL)
+ Q_PROPERTY(QColor buttonDisabledColor READ buttonDisabledColor NOTIFY buttonDisabledColorChanged FINAL)
+ Q_PROPERTY(QColor highlightedButtonColor READ highlightedButtonColor NOTIFY buttonColorChanged FINAL)
+ Q_PROPERTY(QColor highlightedCheckedButtonColor READ highlightedCheckedButtonColor NOTIFY buttonColorChanged FINAL REVISION(6, 2))
+ Q_PROPERTY(QColor frameColor READ frameColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor rippleColor READ rippleColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor highlightedRippleColor READ highlightedRippleColor NOTIFY themeOrAccentChanged FINAL)
+ Q_PROPERTY(QColor switchUncheckedTrackColor READ switchUncheckedTrackColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor switchCheckedTrackColor READ switchCheckedTrackColor NOTIFY themeOrAccentChanged FINAL)
+ Q_PROPERTY(QColor switchUncheckedHandleColor READ switchUncheckedHandleColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor switchCheckedHandleColor READ switchCheckedHandleColor NOTIFY themeOrAccentChanged FINAL)
+ Q_PROPERTY(QColor switchDisabledTrackColor READ switchDisabledTrackColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor switchDisabledHandleColor READ switchDisabledHandleColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor scrollBarColor READ scrollBarColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor scrollBarHoveredColor READ scrollBarHoveredColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor dialogColor READ dialogColor NOTIFY dialogColorChanged FINAL)
+ Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor tooltipColor READ tooltipColor NOTIFY tooltipColorChanged FINAL)
+ Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY toolBarColorChanged FINAL)
+ Q_PROPERTY(QColor toolTextColor READ toolTextColor NOTIFY toolTextColorChanged FINAL)
+ Q_PROPERTY(QColor spinBoxDisabledIconColor READ spinBoxDisabledIconColor NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QColor sliderDisabledColor READ sliderDisabledColor NOTIFY themeChanged FINAL REVISION(2, 15))
+
+ Q_PROPERTY(int touchTarget READ touchTarget CONSTANT FINAL)
+ Q_PROPERTY(int buttonHeight READ buttonHeight CONSTANT FINAL)
+ Q_PROPERTY(int delegateHeight READ delegateHeight CONSTANT FINAL)
+ Q_PROPERTY(int dialogButtonBoxHeight READ dialogButtonBoxHeight CONSTANT FINAL)
+ Q_PROPERTY(int frameVerticalPadding READ frameVerticalPadding CONSTANT FINAL)
+ Q_PROPERTY(int menuItemHeight READ menuItemHeight CONSTANT FINAL)
+ Q_PROPERTY(int menuItemVerticalPadding READ menuItemVerticalPadding CONSTANT FINAL)
+ Q_PROPERTY(int switchDelegateVerticalPadding READ switchDelegateVerticalPadding CONSTANT FINAL)
+ Q_PROPERTY(int tooltipHeight READ tooltipHeight CONSTANT FINAL)
+
+ QML_NAMED_ELEMENT(Material)
+ QML_ATTACHED(QQuickMaterialStyle)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ enum Theme {
+ Light,
+ Dark,
+ System
+ };
+
+ enum Variant {
+ Normal,
+ Dense
+ };
+
+ enum Color {
+ Red,
+ Pink,
+ Purple,
+ DeepPurple,
+ Indigo,
+ Blue,
+ LightBlue,
+ Cyan,
+ Teal,
+ Green,
+ LightGreen,
+ Lime,
+ Yellow,
+ Amber,
+ Orange,
+ DeepOrange,
+ Brown,
+ Grey,
+ BlueGrey
+ };
+
+ enum Shade {
+ Shade50,
+ Shade100,
+ Shade200,
+ Shade300,
+ Shade400,
+ Shade500,
+ Shade600,
+ Shade700,
+ Shade800,
+ Shade900,
+ ShadeA100,
+ ShadeA200,
+ ShadeA400,
+ ShadeA700,
+ };
+
+ Q_ENUM(Theme)
+ Q_ENUM(Variant)
+ Q_ENUM(Color)
+ Q_ENUM(Shade)
+
+ explicit QQuickMaterialStyle(QObject *parent = nullptr);
+
+ static QQuickMaterialStyle *qmlAttachedProperties(QObject *object);
+
+ Theme theme() const;
+ void setTheme(Theme theme);
+ void inheritTheme(Theme theme);
+ void propagateTheme();
+ void resetTheme();
+ void themeChange();
+
+ QVariant primary() const;
+ void setPrimary(const QVariant &accent);
+ void inheritPrimary(uint primary, bool custom);
+ void propagatePrimary();
+ void resetPrimary();
+ void primaryChange();
+
+ QVariant accent() const;
+ void setAccent(const QVariant &accent);
+ void inheritAccent(uint accent, bool custom);
+ void propagateAccent();
+ void resetAccent();
+ void accentChange();
+
+ QVariant foreground() const;
+ void setForeground(const QVariant &foreground);
+ void inheritForeground(uint foreground, bool custom, bool has);
+ void propagateForeground();
+ void resetForeground();
+ void foregroundChange();
+
+ QVariant background() const;
+ void setBackground(const QVariant &background);
+ void inheritBackground(uint background, bool custom, bool has);
+ void propagateBackground();
+ void resetBackground();
+ void backgroundChange();
+
+ int elevation() const;
+ void setElevation(int elevation);
+ void resetElevation();
+ void elevationChange();
+
+ QColor primaryColor() const;
+ QColor accentColor() const;
+ QColor backgroundColor() const;
+ QColor primaryTextColor() const;
+ QColor primaryHighlightedTextColor() const;
+ QColor secondaryTextColor() const;
+ QColor hintTextColor() const;
+ QColor textSelectionColor() const;
+ QColor dropShadowColor() const;
+ QColor dividerColor() const;
+ QColor iconColor() const;
+ QColor iconDisabledColor() const;
+ QColor buttonColor() const;
+ QColor buttonDisabledColor() const;
+ QColor highlightedButtonColor() const;
+ QColor highlightedCheckedButtonColor() const;
+ QColor highlightedButtonDisabledColor() const;
+ QColor frameColor() const;
+ QColor rippleColor() const;
+ QColor highlightedRippleColor() const;
+ QColor switchUncheckedTrackColor() const;
+ QColor switchCheckedTrackColor() const;
+ QColor switchUncheckedHandleColor() const;
+ QColor switchCheckedHandleColor() const;
+ QColor switchDisabledTrackColor() const;
+ QColor switchDisabledHandleColor() const;
+ QColor scrollBarColor() const;
+ QColor scrollBarHoveredColor() const;
+ QColor scrollBarPressedColor() const;
+ QColor dialogColor() const;
+ QColor backgroundDimColor() const;
+ QColor listHighlightColor() const;
+ QColor tooltipColor() const;
+ QColor toolBarColor() const;
+ QColor toolTextColor() const;
+ QColor spinBoxDisabledIconColor() const;
+ QColor sliderDisabledColor() const;
+
+ Q_INVOKABLE QColor color(Color color, Shade shade = Shade500) const;
+ Q_INVOKABLE QColor shade(const QColor &color, Shade shade) const;
+
+ int touchTarget() const;
+ int buttonHeight() const;
+ int delegateHeight() const;
+ int dialogButtonBoxHeight() const;
+ int frameVerticalPadding() const;
+ int menuItemHeight() const;
+ int menuItemVerticalPadding() const;
+ int switchDelegateVerticalPadding() const;
+ int tooltipHeight() const;
+
+ static void initGlobals();
+
+ static Variant variant();
+
+Q_SIGNALS:
+ void themeChanged();
+ void primaryChanged();
+ void accentChanged();
+ void foregroundChanged();
+ void backgroundChanged();
+ void elevationChanged();
+
+ void themeOrAccentChanged();
+
+ void primaryHighlightedTextColorChanged();
+ void buttonColorChanged();
+ void buttonDisabledColorChanged();
+ void dialogColorChanged();
+ void tooltipColorChanged();
+ void toolBarColorChanged();
+ void toolTextColorChanged();
+
+protected:
+ void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+
+private:
+ void init();
+ bool variantToRgba(const QVariant &var, const char *name, QRgb *rgba, bool *custom) const;
+
+ QColor backgroundColor(Shade shade) const;
+ QColor accentColor(Shade shade) const;
+ QColor buttonColor(bool highlighted, bool checked = false) const;
+ Shade themeShade() const;
+
+ // These reflect whether a color value was explicitly set on the specific
+ // item that this attached style object represents.
+ bool m_explicitTheme = false;
+ bool m_explicitPrimary = false;
+ bool m_explicitAccent = false;
+ bool m_explicitForeground = false;
+ bool m_explicitBackground = false;
+ // These reflect whether the color value that was either inherited or
+ // explicitly set is in the form that QColor expects, rather than one of
+ // our pre-defined color enum values.
+ bool m_customPrimary = false;
+ bool m_customAccent = false;
+ bool m_customForeground = false;
+ bool m_customBackground = false;
+ // These will be true when this item has an explicit or inherited foreground/background
+ // color, or these colors were declared globally via settings (e.g. conf or env vars).
+ // Some color properties of the style will return different values depending on whether
+ // or not these are set.
+ bool m_hasForeground = false;
+ bool m_hasBackground = false;
+ // The actual values for this item, whether explicit, inherited or globally set.
+ Theme m_theme = Light;
+ uint m_primary = 0;
+ uint m_accent = 0;
+ uint m_foreground = 0;
+ uint m_background = 0;
+ int m_elevation = 0;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QQuickMaterialStyle, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKMATERIALSTYLE_P_H
diff --git a/src/quickcontrols2/material/qquickmaterialtheme.cpp b/src/quickcontrols2/material/qquickmaterialtheme.cpp
new file mode 100644
index 0000000000..aec9e23233
--- /dev/null
+++ b/src/quickcontrols2/material/qquickmaterialtheme.cpp
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialtheme_p.h"
+#include "qquickmaterialstyle_p.h"
+
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qfontinfo.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickMaterialTheme::initialize(QQuickTheme *theme)
+{
+ QFont systemFont;
+ QFont buttonFont;
+ QFont toolTipFont;
+ QFont itemViewFont;
+ QFont listViewFont;
+ QFont menuItemFont;
+ QFont editorFont;
+
+ QFont font;
+ font.setFamilies(QStringList{QLatin1String("Roboto")});
+ QString family = QFontInfo(font).family();
+
+ if (family != QLatin1String("Roboto")) {
+ font.setFamilies(QStringList{QLatin1String("Noto")});
+ family = QFontInfo(font).family();
+ }
+
+ if (family == QLatin1String("Roboto") || family == QLatin1String("Noto")) {
+ const QStringList families{family};
+ systemFont.setFamilies(families);
+ buttonFont.setFamilies(families);
+ toolTipFont.setFamilies(families);
+ itemViewFont.setFamilies(families);
+ listViewFont.setFamilies(families);
+ menuItemFont.setFamilies(families);
+ editorFont.setFamilies(families);
+ }
+
+ const bool dense = QQuickMaterialStyle::variant() == QQuickMaterialStyle::Dense;
+ systemFont.setPixelSize(dense ? 13 : 14);
+ theme->setFont(QQuickTheme::System, systemFont);
+
+ // https://material.io/guidelines/components/buttons.html#buttons-style
+ buttonFont.setPixelSize(dense ? 13 : 14);
+ buttonFont.setCapitalization(QFont::AllUppercase);
+ buttonFont.setWeight(QFont::Medium);
+ theme->setFont(QQuickTheme::Button, buttonFont);
+ theme->setFont(QQuickTheme::TabBar, buttonFont);
+ theme->setFont(QQuickTheme::ToolBar, buttonFont);
+
+ // https://material.io/guidelines/components/tooltips.html
+ toolTipFont.setPixelSize(dense ? 10 : 14);
+ toolTipFont.setWeight(QFont::Medium);
+ theme->setFont(QQuickTheme::ToolTip, toolTipFont);
+
+ itemViewFont.setPixelSize(dense ? 13 : 14);
+ itemViewFont.setWeight(QFont::Medium);
+ theme->setFont(QQuickTheme::ItemView, itemViewFont);
+
+ // https://material.io/guidelines/components/lists.html#lists-specs
+ listViewFont.setPixelSize(dense ? 13 : 16);
+ theme->setFont(QQuickTheme::ListView, listViewFont);
+
+ menuItemFont.setPixelSize(dense ? 13 : 16);
+ theme->setFont(QQuickTheme::Menu, menuItemFont);
+ theme->setFont(QQuickTheme::MenuBar, menuItemFont);
+ theme->setFont(QQuickTheme::ComboBox, menuItemFont);
+
+ editorFont.setPixelSize(dense ? 13 : 16);
+ theme->setFont(QQuickTheme::TextArea, editorFont);
+ theme->setFont(QQuickTheme::TextField, editorFont);
+ theme->setFont(QQuickTheme::SpinBox, editorFont);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/material/qquickmaterialtheme_p.h b/src/quickcontrols2/material/qquickmaterialtheme_p.h
new file mode 100644
index 0000000000..9a1362b81c
--- /dev/null
+++ b/src/quickcontrols2/material/qquickmaterialtheme_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMATERIALTHEME_P_H
+#define QQUICKMATERIALTHEME_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 QQuickMaterialTheme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMATERIALTHEME_P_H
diff --git a/src/quickcontrols2/material/qt_attribution.json b/src/quickcontrols2/material/qt_attribution.json
new file mode 100644
index 0000000000..85fdadf9e0
--- /dev/null
+++ b/src/quickcontrols2/material/qt_attribution.json
@@ -0,0 +1,13 @@
+{
+ "Id": "shadow_angular_material",
+ "Name": "Shadow values from Angular Material",
+ "QDocModule": "qtquickcontrols",
+ "QtUsage": "Used in the Material Style of Qt Quick Controls 2.",
+ "Files": "ElevationEffect.qml",
+ "Description": "Shadow values for the elevation effect.",
+ "Homepage": "https://angularjs.org/",
+ "License": "MIT License",
+ "LicenseId": "MIT",
+ "LicenseFile": "LICENSE_ANGULARJS.txt",
+ "Copyright": "Copyright (c) 2014-2016 Google, Inc"
+}
diff --git a/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.cpp b/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.cpp
new file mode 100644
index 0000000000..25807eecf7
--- /dev/null
+++ b/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmaterialstyle_p.h"
+#include "qquickmaterialtheme_p.h"
+
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2Impl/private/qquickpaddedrectangle_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+extern void qml_register_types_QtQuick_Controls_Material();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Material);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2MaterialStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2MaterialStylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+
+ QQuickMaterialTheme theme;
+};
+
+QtQuickControls2MaterialStylePlugin::QtQuickControls2MaterialStylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Material;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2MaterialStylePlugin::name() const
+{
+ return QStringLiteral("Material");
+}
+
+void QtQuickControls2MaterialStylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ QQuickMaterialStyle::initGlobals();
+ this->theme.initialize(theme);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2materialstyleplugin.moc"
diff --git a/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.qrc b/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.qrc
new file mode 100644
index 0000000000..981960c440
--- /dev/null
+++ b/src/quickcontrols2/material/qtquickcontrols2materialstyleplugin.qrc
@@ -0,0 +1,20 @@
+<RCC>
+ <qresource prefix="/qt-project.org/imports/QtQuick/Controls/Material">
+ <file>images/arrow-indicator.png</file>
+ <file>images/arrow-indicator@2x.png</file>
+ <file>images/arrow-indicator@3x.png</file>
+ <file>images/arrow-indicator@4x.png</file>
+ <file>images/check.png</file>
+ <file>images/check@2x.png</file>
+ <file>images/check@3x.png</file>
+ <file>images/check@4x.png</file>
+ <file>images/drop-indicator.png</file>
+ <file>images/drop-indicator@2x.png</file>
+ <file>images/drop-indicator@3x.png</file>
+ <file>images/drop-indicator@4x.png</file>
+ <file>shaders/RectangularGlow.frag</file>
+ <file>shaders/+glslcore/RectangularGlow.frag</file>
+ <file>shaders/+hlsl/RectangularGlow.frag</file>
+ <file>shaders/+qsb/RectangularGlow.frag</file>
+ </qresource>
+</RCC>
diff --git a/src/quickcontrols2/material/shaders/+glslcore/RectangularGlow.frag b/src/quickcontrols2/material/shaders/+glslcore/RectangularGlow.frag
new file mode 100644
index 0000000000..432d86b5d5
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/+glslcore/RectangularGlow.frag
@@ -0,0 +1,25 @@
+#version 150
+
+uniform float qt_Opacity;
+uniform float relativeSizeX;
+uniform float relativeSizeY;
+uniform float spread;
+uniform vec4 color;
+
+in vec2 qt_TexCoord0;
+out vec4 fragColor;
+
+float linearstep(float e0, float e1, float x)
+{
+ return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
+}
+
+void main()
+{
+ float alpha =
+ smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *
+ smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));
+
+ float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);
+ fragColor = color * qt_Opacity * spreadMultiplier * spreadMultiplier;
+}
diff --git a/src/quickcontrols2/material/shaders/+hlsl/RectangularGlow.frag b/src/quickcontrols2/material/shaders/+hlsl/RectangularGlow.frag
new file mode 100644
index 0000000000..69d9f852fb
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/+hlsl/RectangularGlow.frag
@@ -0,0 +1,21 @@
+cbuffer ConstantBuffer : register(b0)
+{
+ float4x4 qt_Matrix;
+ float qt_Opacity;
+ float relativeSizeX;
+ float relativeSizeY;
+ float spread;
+ float4 color;
+}
+
+float linearstep(float e0, float e1, float x) { return clamp((x - e0) / (e1 - e0), 0.0, 1.0); }
+
+float4 main(float4 position : SV_POSITION, float2 coord : TEXCOORD0) : SV_TARGET
+{
+ float alpha =
+ smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - coord.x)) *
+ smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - coord.y));
+
+ float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);
+ return color * qt_Opacity * spreadMultiplier * spreadMultiplier;
+}
diff --git a/src/quickcontrols2/material/shaders/+qsb/RectangularGlow.frag b/src/quickcontrols2/material/shaders/+qsb/RectangularGlow.frag
new file mode 100644
index 0000000000..5cfa2db6ed
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/+qsb/RectangularGlow.frag
Binary files differ
diff --git a/src/quickcontrols2/material/shaders/RectangularGlow.frag b/src/quickcontrols2/material/shaders/RectangularGlow.frag
new file mode 100644
index 0000000000..40bab5806c
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/RectangularGlow.frag
@@ -0,0 +1,19 @@
+uniform highp float qt_Opacity;
+uniform mediump float relativeSizeX;
+uniform mediump float relativeSizeY;
+uniform mediump float spread;
+uniform lowp vec4 color;
+varying highp vec2 qt_TexCoord0;
+
+highp float linearstep(highp float e0, highp float e1, highp float x) {
+ return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
+}
+
+void main() {
+ lowp float alpha =
+ smoothstep(0.0, relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *
+ smoothstep(0.0, relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));
+
+ highp float spreadMultiplier = linearstep(spread, 1.0 - spread, alpha);
+ gl_FragColor = color * qt_Opacity * spreadMultiplier * spreadMultiplier;
+}
diff --git a/src/quickcontrols2/material/shaders/RectangularGlow_rhi.frag b/src/quickcontrols2/material/shaders/RectangularGlow_rhi.frag
new file mode 100644
index 0000000000..3e7d2dfe6f
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/RectangularGlow_rhi.frag
@@ -0,0 +1,28 @@
+#version 440
+
+layout(location = 0) in vec2 qt_TexCoord0;
+layout(location = 0) out vec4 fragColor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ float qt_Opacity;
+ float relativeSizeX;
+ float relativeSizeY;
+ float spread;
+ vec4 color;
+} ubuf;
+
+float linearstep(float e0, float e1, float x)
+{
+ return clamp((x - e0) / (e1 - e0), 0.0, 1.0);
+}
+
+void main()
+{
+ float alpha =
+ smoothstep(0.0, ubuf.relativeSizeX, 0.5 - abs(0.5 - qt_TexCoord0.x)) *
+ smoothstep(0.0, ubuf.relativeSizeY, 0.5 - abs(0.5 - qt_TexCoord0.y));
+
+ float spreadMultiplier = linearstep(ubuf.spread, 1.0 - ubuf.spread, alpha);
+ fragColor = ubuf.color * ubuf.qt_Opacity * spreadMultiplier * spreadMultiplier;
+}
diff --git a/src/quickcontrols2/material/shaders/compile.bat b/src/quickcontrols2/material/shaders/compile.bat
new file mode 100644
index 0000000000..e87efa7a6d
--- /dev/null
+++ b/src/quickcontrols2/material/shaders/compile.bat
@@ -0,0 +1,40 @@
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+::
+:: Copyright (C) 2019 The Qt Company Ltd.
+:: Contact: https://www.qt.io/licensing/
+::
+:: This file is part of the QtQuick module of the Qt Toolkit.
+::
+:: $QT_BEGIN_LICENSE:LGPL$
+:: Commercial License Usage
+:: Licensees holding valid commercial Qt licenses may use this file in
+:: accordance with the commercial license agreement provided with the
+:: Software or, alternatively, in accordance with the terms contained in
+:: a written agreement between you and The Qt Company. For licensing terms
+:: and conditions see https://www.qt.io/terms-conditions. For further
+:: information use the contact form at https://www.qt.io/contact-us.
+::
+:: GNU Lesser General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU Lesser
+:: General Public License version 3 as published by the Free Software
+:: Foundation and appearing in the file LICENSE.LGPL3 included in the
+:: packaging of this file. Please review the following information to
+:: ensure the GNU Lesser General Public License version 3 requirements
+:: will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+::
+:: GNU General Public License Usage
+:: Alternatively, this file may be used under the terms of the GNU
+:: General Public License version 2.0 or (at your option) the GNU General
+:: Public license version 3 or any later version approved by the KDE Free
+:: Qt Foundation. The licenses are as published by the Free Software
+:: Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+:: included in the packaging of this file. Please review the following
+:: information to ensure the GNU General Public License requirements will
+:: be met: https://www.gnu.org/licenses/gpl-2.0.html and
+:: https://www.gnu.org/licenses/gpl-3.0.html.
+::
+:: $QT_END_LICENSE$
+::
+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+
+qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o +qsb/RectangularGlow.frag RectangularGlow_rhi.frag
diff --git a/src/quickcontrols2/qquickstyle.cpp b/src/quickcontrols2/qquickstyle.cpp
new file mode 100644
index 0000000000..3ba0ad0610
--- /dev/null
+++ b/src/quickcontrols2/qquickstyle.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyle.h"
+#include "qquickstyle_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtCore/qfileselector.h>
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qmetaobject.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/private/qqmlmetatype_p.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
+
+#include <functional>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQtQuickControlsStyle, "qt.quick.controls.style")
+
+/*!
+ \class QQuickStyle
+ \brief The QQuickStyle class allows configuring the application style.
+ \inmodule QtQuickControls2
+ \since 5.7
+
+ QQuickStyle provides API for querying and configuring the application
+ \l {Styling Qt Quick Controls}{styles} of Qt Quick Controls.
+
+ \code
+ #include <QGuiApplication>
+ #include <QQmlApplicationEngine>
+ #include <QQuickStyle>
+
+ int main(int argc, char *argv[])
+ {
+ QGuiApplication app(argc, argv);
+
+ QQuickStyle::setStyle("Material");
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl("qrc:/main.qml"));
+
+ return app.exec();
+ }
+ \endcode
+
+ \note The style must be configured \b before loading QML that imports
+ Qt Quick Controls. It is not possible to change the style after the QML
+ types have been registered.
+
+ \note QQuickStyle is not supported when using
+ \l {Compile-Time Style Selection}{compile-time style selection}.
+
+ To create your own custom style, see \l {Creating a Custom Style}. Custom
+ styles do not need to implement all controls. By default, the styling
+ system uses the \l {Basic style} as a fallback for controls that a custom
+ style does not provide. It is possible to specify a different fallback
+ style to customize or extend one of the built-in styles.
+
+ \code
+ QQuickStyle::setStyle("MyStyle");
+ QQuickStyle::setFallbackStyle("Material");
+ \endcode
+
+ \sa {Styling Qt Quick Controls}
+*/
+
+struct QQuickStyleSpec
+{
+ QQuickStyleSpec() { }
+
+ QString name()
+ {
+ if (!resolved)
+ resolve();
+ return style.mid(style.lastIndexOf(QLatin1Char('/')) + 1);
+ }
+
+ QString path()
+ {
+ if (!resolved)
+ resolve();
+ QString s = style;
+ if (QQmlFile::isLocalFile(s))
+ s = QQmlFile::urlToLocalFileOrQrc(s);
+ return s.left(s.lastIndexOf(QLatin1Char('/')) + 1);
+ }
+
+ void setStyle(const QString &s)
+ {
+ qCDebug(lcQtQuickControlsStyle) << "style" << s << "set on QQuickStyleSpec";
+ if (s.contains(QLatin1Char('/'))) {
+ qWarning() << "Style names must not contain paths; see the \"Definition of a Style\" documentation for more information";
+ return;
+ }
+
+ qCDebug(lcQtQuickControlsStyle) << "clearing resolved flag and resolving";
+ style = s;
+ resolved = false;
+ resolve();
+ }
+
+ void setFallbackStyle(const QString &fallback, const QByteArray &method)
+ {
+ if (!fallback.isEmpty())
+ qCDebug(lcQtQuickControlsStyle) << "fallback style" << fallback << "set on QQuickStyleSpec via" << method;
+
+ fallbackStyle = fallback;
+ fallbackMethod = method;
+ }
+
+ void resolve()
+ {
+ qCDebug(lcQtQuickControlsStyle) << "resolving style";
+
+ if (style.isEmpty())
+ style = QGuiApplicationPrivate::styleOverride;
+ if (style.isEmpty())
+ style = QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_STYLE"));
+ if (fallbackStyle.isEmpty())
+ setFallbackStyle(QString::fromLocal8Bit(qgetenv("QT_QUICK_CONTROLS_FALLBACK_STYLE")), "QT_QUICK_CONTROLS_FALLBACK_STYLE");
+#if QT_CONFIG(settings)
+ if (style.isEmpty() || fallbackStyle.isEmpty()) {
+ QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Controls"));
+ if (settings) {
+ if (style.isEmpty())
+ style = settings->value(QStringLiteral("Style")).toString();
+ if (fallbackStyle.isEmpty())
+ setFallbackStyle(settings->value(QStringLiteral("FallbackStyle")).toString(), ":/qtquickcontrols2.conf");
+ }
+ }
+#endif
+
+ auto builtInStyleList = QQuickStylePrivate::builtInStyles();
+ if (!fallbackStyle.isEmpty() && !builtInStyleList.contains(fallbackStyle)) {
+ qWarning().nospace().noquote() << fallbackMethod << ": the specified fallback style \"" <<
+ fallbackStyle << "\" is not one of the built-in Qt Quick Controls 2 styles";
+ fallbackStyle.clear();
+ }
+
+ // Find the config file.
+ resolveConfigFilePath();
+
+ usingDefaultStyle = false;
+
+ if (style.isEmpty() || style.toLower() == QStringLiteral("default")) {
+ usingDefaultStyle = true;
+ style.clear();
+
+ qCDebug(lcQtQuickControlsStyle) << "no style (or Default) was specified;"
+ << "checking if we have an appropriate style for this platform";
+
+ // If these defaults are changed, ensure that the "Using Styles in Qt Quick Controls"
+ // section of qtquickcontrols2-styles.qdoc is updated.
+#if defined(Q_OS_MACOS)
+ style = QLatin1String("macOS");
+#elif defined(Q_OS_WINDOWS)
+ style = QLatin1String("Windows");
+#elif defined(Q_OS_ANDROID)
+ style = QLatin1String("Material");
+#elif defined(Q_OS_LINUX)
+ style = QLatin1String("Fusion");
+#endif
+ if (!style.isEmpty())
+ qCDebug(lcQtQuickControlsStyle) << "using" << style << "as a default";
+ else
+ qCDebug(lcQtQuickControlsStyle) << "no appropriate style found; using Basic as a default";
+ }
+
+ // If it's still empty by this point, then it means we have no native style available for this platform,
+ // as is the case on e.g. embedded. In that case, we want to default to the Basic style,
+ // which is what effectiveStyleName() returns when "style" is empty.
+ custom = !builtInStyleList.contains(QQuickStylePrivate::effectiveStyleName(style));
+
+ resolved = true;
+
+ qCDebug(lcQtQuickControlsStyle).nospace() << "done resolving:"
+ << "\n style=" << style
+ << "\n custom=" << custom
+ << "\n resolved=" << resolved
+ << "\n fallbackStyle=" << fallbackStyle
+ << "\n fallbackMethod=" << fallbackMethod
+ << "\n configFilePath=" << configFilePath;
+ }
+
+ void reset()
+ {
+ qCDebug(lcQtQuickControlsStyle) << "resetting values to their defaults";
+
+ custom = false;
+ resolved = false;
+ usingDefaultStyle = false;
+ style.clear();
+ fallbackStyle.clear();
+ fallbackMethod.clear();
+ configFilePath.clear();
+ }
+
+ QString resolveConfigFilePath()
+ {
+ if (configFilePath.isEmpty()) {
+ configFilePath = QFile::decodeName(qgetenv("QT_QUICK_CONTROLS_CONF"));
+ if (configFilePath.isEmpty() || !QFile::exists(configFilePath)) {
+ if (!configFilePath.isEmpty())
+ qWarning("QT_QUICK_CONTROLS_CONF=%s: No such file", qPrintable(configFilePath));
+
+ configFilePath = QStringLiteral(":/qtquickcontrols2.conf");
+ }
+ }
+ return configFilePath;
+ }
+
+ // Is this a custom style defined by the user and not "built-in" style?
+ bool custom = false;
+ // Have we resolved the style yet?
+ bool resolved = false;
+ // Are we using the default style for this platform (because no style was specified)?
+ bool usingDefaultStyle = false;
+ // The name of the style.
+ QString style;
+ // The built-in style to use if the requested style cannot be found.
+ QString fallbackStyle;
+ // A description of the way in which fallbackStyle was set, used in e.g. warning messages shown to the user.
+ QByteArray fallbackMethod;
+ // The path to the qtquickcontrols2.conf file.
+ QString configFilePath;
+};
+
+Q_GLOBAL_STATIC(QQuickStyleSpec, styleSpec)
+
+/*
+ Note that most of these functions (with the exception of e.g. isResolved())
+ should not be called before the style has been resolved, as it's only after
+ that happens that they will have been set.
+*/
+QString QQuickStylePrivate::style()
+{
+ return styleSpec()->style;
+}
+
+QString QQuickStylePrivate::effectiveStyleName(const QString &styleName)
+{
+ return !styleName.isEmpty() ? styleName : QLatin1String("Basic");
+}
+
+QString QQuickStylePrivate::fallbackStyle()
+{
+ return styleSpec()->fallbackStyle;
+}
+
+bool QQuickStylePrivate::isCustomStyle()
+{
+ return styleSpec()->custom;
+}
+
+bool QQuickStylePrivate::isResolved()
+{
+ return styleSpec()->resolved;
+}
+
+bool QQuickStylePrivate::isUsingDefaultStyle()
+{
+ return styleSpec()->usingDefaultStyle;
+}
+
+void QQuickStylePrivate::init()
+{
+ QQuickStyleSpec *spec = styleSpec();
+ spec->resolve();
+}
+
+void QQuickStylePrivate::reset()
+{
+ if (styleSpec())
+ styleSpec()->reset();
+}
+
+QString QQuickStylePrivate::configFilePath()
+{
+ return styleSpec()->resolveConfigFilePath();
+}
+
+QSharedPointer<QSettings> QQuickStylePrivate::settings(const QString &group)
+{
+#ifndef QT_NO_SETTINGS
+ const QString filePath = QQuickStylePrivate::configFilePath();
+ if (QFile::exists(filePath)) {
+ QFileSelector selector;
+ QSettings *settings = new QSettings(selector.select(filePath), QSettings::IniFormat);
+ if (!group.isEmpty())
+ settings->beginGroup(group);
+ return QSharedPointer<QSettings>(settings);
+ }
+#endif // QT_NO_SETTINGS
+ return QSharedPointer<QSettings>();
+}
+
+#if QT_CONFIG(settings)
+static void readValue(const QSharedPointer<QSettings> &settings, const QString &name, std::function<void(const QVariant &)> setValue)
+{
+ const QVariant var = settings->value(name);
+ if (var.isValid())
+ setValue(var);
+}
+
+template <typename Enum>
+static Enum toEnumValue(const QVariant &var)
+{
+ // ### TODO: expose QFont enums to the meta object system using Q_ENUM
+ //QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
+ //bool ok = false;
+ //int value = enumeration.keyToValue(var.toByteArray(), &ok);
+ //if (!ok)
+ // value = var.toInt();
+ //return static_cast<Enum>(value);
+
+ return static_cast<Enum>(var.toInt());
+}
+
+const QFont *QQuickStylePrivate::readFont(const QSharedPointer<QSettings> &settings)
+{
+ const QVariant var = settings->value(QStringLiteral("Font"));
+ if (var.isValid())
+ return new QFont(var.value<QFont>());
+
+ QFont f;
+ settings->beginGroup(QStringLiteral("Font"));
+ readValue(settings, QStringLiteral("Family"), [&f](const QVariant &var) { f.setFamilies(QStringList{var.toString()}); });
+ readValue(settings, QStringLiteral("PointSize"), [&f](const QVariant &var) { f.setPointSizeF(var.toReal()); });
+ readValue(settings, QStringLiteral("PixelSize"), [&f](const QVariant &var) { f.setPixelSize(var.toInt()); });
+ readValue(settings, QStringLiteral("StyleHint"), [&f](const QVariant &var) { f.setStyleHint(toEnumValue<QFont::StyleHint>(var.toInt())); });
+ readValue(settings, QStringLiteral("Weight"), [&f](const QVariant &var) { f.setWeight(toEnumValue<QFont::Weight>(var)); });
+ readValue(settings, QStringLiteral("Style"), [&f](const QVariant &var) { f.setStyle(toEnumValue<QFont::Style>(var.toInt())); });
+ settings->endGroup();
+ return new QFont(f);
+}
+
+static void readColorGroup(const QSharedPointer<QSettings> &settings, QPalette::ColorGroup group, QPalette *palette)
+{
+ const QStringList keys = settings->childKeys();
+ if (keys.isEmpty())
+ return;
+
+ static const int index = QPalette::staticMetaObject.indexOfEnumerator("ColorRole");
+ Q_ASSERT(index != -1);
+ QMetaEnum metaEnum = QPalette::staticMetaObject.enumerator(index);
+
+ for (const QString &key : keys) {
+ bool ok = false;
+ int role = metaEnum.keyToValue(key.toUtf8(), &ok);
+ if (ok)
+ palette->setColor(group, static_cast<QPalette::ColorRole>(role), settings->value(key).value<QColor>());
+ }
+}
+
+const QPalette *QQuickStylePrivate::readPalette(const QSharedPointer<QSettings> &settings)
+{
+ QPalette p;
+ settings->beginGroup(QStringLiteral("Palette"));
+ readColorGroup(settings, QPalette::All, &p);
+
+ settings->beginGroup(QStringLiteral("Normal"));
+ readColorGroup(settings, QPalette::Normal, &p);
+ settings->endGroup();
+
+ settings->beginGroup(QStringLiteral("Disabled"));
+ readColorGroup(settings, QPalette::Disabled, &p);
+ settings->endGroup();
+ return new QPalette(p);
+}
+#endif // QT_CONFIG(settings)
+
+bool QQuickStylePrivate::isDarkSystemTheme()
+{
+ const static bool dark = [](){
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ return theme->appearance() == QPlatformTheme::Appearance::Dark;
+ return false;
+ }();
+ return dark;
+}
+
+QStringList QQuickStylePrivate::builtInStyles()
+{
+ return {
+ QLatin1String("Basic"),
+ QLatin1String("Fusion"),
+ QLatin1String("Imagine"),
+#ifdef Q_OS_MACOS
+ QLatin1String("macOS"),
+#endif
+ QLatin1String("Material"),
+ QLatin1String("Universal"),
+#ifdef Q_OS_WINDOWS
+ QLatin1String("Windows")
+#endif
+ };
+}
+
+/*!
+ Returns the name of the application style.
+
+ \note The application style can be specified by passing a \c -style command
+ line argument. Therefore \c name() may not return a fully resolved
+ value if called before constructing a QGuiApplication.
+*/
+QString QQuickStyle::name()
+{
+ return styleSpec()->name();
+}
+
+/*!
+ Sets the application style to \a style.
+
+ \note The style must be configured \b before loading QML that imports Qt Quick Controls.
+ It is not possible to change the style after the QML types have been registered.
+
+ \sa setFallbackStyle(), {Using Styles in Qt Quick Controls}
+*/
+void QQuickStyle::setStyle(const QString &style)
+{
+ qCDebug(lcQtQuickControlsStyle) << "setStyle called with" << style;
+
+ if (QQmlMetaType::matchingModuleVersion(
+ QStringLiteral("QtQuick.Controls"), QTypeRevision::fromVersion(2, 0)).isValid()) {
+ qWarning() << "ERROR: QQuickStyle::setStyle() must be called before loading QML that imports Qt Quick Controls 2.";
+ return;
+ }
+
+ styleSpec()->setStyle(style);
+}
+
+/*!
+ \since 5.8
+ Sets the application fallback style to \a style.
+
+ \note The fallback style must be the name of one of the built-in Qt Quick Controls styles, e.g. "Material".
+
+ \note The style must be configured \b before loading QML that imports Qt Quick Controls.
+ It is not possible to change the style after the QML types have been registered.
+
+ The fallback style can be also specified by setting the \c QT_QUICK_CONTROLS_FALLBACK_STYLE
+ \l {Supported Environment Variables in Qt Quick Controls}{environment variable}.
+
+ \sa setStyle(), {Using Styles in Qt Quick Controls}
+*/
+void QQuickStyle::setFallbackStyle(const QString &style)
+{
+ if (QQmlMetaType::matchingModuleVersion(
+ QStringLiteral("QtQuick.Controls"), QTypeRevision::fromVersion(2, 0)).isValid()) {
+ qWarning() << "ERROR: QQuickStyle::setFallbackStyle() must be called before loading QML that imports Qt Quick Controls 2.";
+ return;
+ }
+
+ styleSpec()->setFallbackStyle(style, "QQuickStyle::setFallbackStyle()");
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/qquickstyle.h b/src/quickcontrols2/qquickstyle.h
new file mode 100644
index 0000000000..e26ec90be3
--- /dev/null
+++ b/src/quickcontrols2/qquickstyle.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLE_H
+#define QQUICKSTYLE_H
+
+#include <QtCore/qurl.h>
+#include <QtCore/qstring.h>
+#include <QtQuickControls2/qtquickcontrols2global.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_EXPORT QQuickStyle
+{
+public:
+ static QString name();
+ static void setStyle(const QString &style);
+ static void setFallbackStyle(const QString &style);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLE_H
diff --git a/src/quickcontrols2/qquickstyle_p.h b/src/quickcontrols2/qquickstyle_p.h
new file mode 100644
index 0000000000..31c7089379
--- /dev/null
+++ b/src/quickcontrols2/qquickstyle_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLE_P_H
+#define QQUICKSTYLE_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/qsharedpointer.h>
+#include <QtQuickControls2/qtquickcontrols2global.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSettings;
+
+class Q_QUICKCONTROLS2_EXPORT QQuickStylePrivate
+{
+public:
+ static QString style();
+ static QString effectiveStyleName(const QString &styleName);
+ static QString fallbackStyle();
+ static bool isCustomStyle();
+ static bool isResolved();
+ static bool isUsingDefaultStyle();
+ static bool exists();
+ static void init();
+ static void reset();
+ static QString configFilePath();
+ static QSharedPointer<QSettings> settings(const QString &group = QString());
+ static const QFont *readFont(const QSharedPointer<QSettings> &settings);
+ static const QPalette *readPalette(const QSharedPointer<QSettings> &settings);
+ static bool isDarkSystemTheme();
+ static QStringList builtInStyles();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLE_P_H
diff --git a/src/quickcontrols2/qquickstyleplugin.cpp b/src/quickcontrols2/qquickstyleplugin.cpp
new file mode 100644
index 0000000000..b396508ebf
--- /dev/null
+++ b/src/quickcontrols2/qquickstyleplugin.cpp
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyle.h"
+#include "qquickstyle_p.h"
+#include "qquickstyleplugin_p.h"
+
+#include <QtCore/private/qfileselector_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQml/private/qqmlmetatype_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcStylePlugin, "qt.quick.controls.styleplugin")
+
+QQuickStylePlugin::QQuickStylePlugin(QObject *parent)
+ : QQmlExtensionPlugin(parent)
+{
+}
+
+QQuickStylePlugin::~QQuickStylePlugin()
+{
+}
+
+void QQuickStylePlugin::registerTypes(const char *uri)
+{
+ qCDebug(lcStylePlugin).nospace() << "registerTypes called with uri " << uri << "; plugin name is " << name();
+
+ const QTypeRevision latestControlsRevision = QQmlMetaType::latestModuleVersion(QLatin1String("QtQuick.Controls"));
+ // Use the private function because we don't want to cause resolve() to be called,
+ // as the logic that assigns a default style if one wasn't set would interfere with compile-time style selection.
+ QString styleName = QQuickStylePrivate::style();
+ if (!latestControlsRevision.isValid() && styleName.isEmpty()) {
+ // The user hasn't imported QtQuick.Controls, nor set a style via the runtime methods.
+ qCDebug(lcStylePlugin).nospace() << uri << " imported before QtQuick.Controls; using compile-time style selection";
+ QQuickStyle::setStyle(name());
+ styleName = name();
+ }
+
+ // Even if this style plugin isn't for the style set by the user,
+ // we still want to create the theme object, because that function
+ // is also responsible for reading values from qtquickcontrols2.conf.
+ // So, even if a style doesn't have a QQuickTheme, it can still have
+ // values set for (e.g. fonts and palettes) in qtquickcontrols2.conf.
+ const QString effectiveCurrentStyleName = QQuickStylePrivate::effectiveStyleName(styleName);
+ auto theme = QQuickTheme::instance();
+ if (!theme) {
+ qCDebug(lcStylePlugin) << "creating theme";
+ theme = createTheme(effectiveCurrentStyleName);
+ }
+
+ if (name() != effectiveCurrentStyleName) {
+ qCDebug(lcStylePlugin).nospace() << "theme does not belong to current style ("
+ << effectiveCurrentStyleName << "); not calling initializeTheme()";
+ return;
+ }
+
+ qCDebug(lcStylePlugin) << "theme has not yet been initialized; calling initializeTheme()";
+ initializeTheme(theme);
+
+ if (!styleName.isEmpty())
+ QFileSelectorPrivate::addStatics(QStringList() << styleName);
+}
+
+void QQuickStylePlugin::unregisterTypes()
+{
+ qCDebug(lcStylePlugin) << "unregisterTypes called; plugin name is" << name();
+ if (!QQuickThemePrivate::instance)
+ return;
+
+ // Not every style has a plugin - some styles are QML-only. So, we clean this
+ // stuff up when the first style plugin is unregistered rather than when the
+ // plugin for the current style is unregistered.
+ QQuickThemePrivate::instance.reset();
+ QQuickStylePrivate::reset();
+}
+
+/*!
+ \internal
+
+ Responsible for setting the font and palette settings that were specified in the
+ qtquickcontrols2.conf file.
+
+ Style-specific settings (e.g. Variant=Dense) are read in the constructor of the
+ appropriate style plugin (e.g. QtQuickControls2MaterialStylePlugin).
+
+ Implicit style-specific font and palette values are assigned in the relevant theme
+ (e.g. QQuickMaterialTheme).
+*/
+QQuickTheme *QQuickStylePlugin::createTheme(const QString &name)
+{
+ qCDebug(lcStylePlugin) << "creating QQuickTheme instance to be initialized by style-specific theme of" << name;
+
+ QQuickTheme *theme = new QQuickTheme;
+#if QT_CONFIG(settings)
+ QQuickThemePrivate *p = QQuickThemePrivate::get(theme);
+ QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(name);
+ if (settings) {
+ p->defaultFont.reset(QQuickStylePrivate::readFont(settings));
+ // Set the default font as the System scope, because that's what
+ // QQuickControlPrivate::parentFont() uses as its fallback if no
+ // parent item has a font explicitly set. QQuickControlPrivate::parentFont()
+ // is used as the starting point for font inheritance/resolution.
+ // The same goes for palettes below.
+ theme->setFont(QQuickTheme::System, *p->defaultFont);
+
+ p->defaultPalette.reset(QQuickStylePrivate::readPalette(settings));
+ theme->setPalette(QQuickTheme::System, *p->defaultPalette);
+ }
+#endif
+ QQuickThemePrivate::instance.reset(theme);
+ return theme;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleplugin_p.cpp"
diff --git a/src/quickcontrols2/qquickstyleplugin_p.h b/src/quickcontrols2/qquickstyleplugin_p.h
new file mode 100644
index 0000000000..0cc793a28d
--- /dev/null
+++ b/src/quickcontrols2/qquickstyleplugin_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEPLUGIN_P_H
+#define QQUICKSTYLEPLUGIN_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/qqmlextensionplugin.h>
+#include <QtQuickControls2/qtquickcontrols2global.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTheme;
+
+class Q_QUICKCONTROLS2_EXPORT QQuickStylePlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickStylePlugin(QObject *parent = nullptr);
+ ~QQuickStylePlugin();
+
+ virtual QString name() const = 0;
+ virtual void initializeTheme(QQuickTheme *theme) = 0;
+
+ void registerTypes(const char *uri) override;
+ void unregisterTypes() override;
+
+private:
+ QQuickTheme *createTheme(const QString &name);
+
+ Q_DISABLE_COPY(QQuickStylePlugin)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEPLUGIN_P_H
diff --git a/src/quickcontrols2/qt_cmdline.cmake b/src/quickcontrols2/qt_cmdline.cmake
new file mode 100644
index 0000000000..b1e98c9ac8
--- /dev/null
+++ b/src/quickcontrols2/qt_cmdline.cmake
@@ -0,0 +1,6 @@
+qt_commandline_option(style-fusion TYPE boolean NAME quickcontrols2-fusion)
+qt_commandline_option(style-imagine TYPE boolean NAME quickcontrols2-imagine)
+qt_commandline_option(style-material TYPE boolean NAME quickcontrols2-material)
+qt_commandline_option(style-universal TYPE boolean NAME quickcontrols2-universal)
+qt_commandline_option(style-macos TYPE boolean NAME quickcontrols2-macos)
+qt_commandline_option(style-windows TYPE boolean NAME quickcontrols2-windows)
diff --git a/src/quickcontrols2/qtquickcontrols2global.h b/src/quickcontrols2/qtquickcontrols2global.h
new file mode 100644
index 0000000000..e5f050ce1e
--- /dev/null
+++ b/src/quickcontrols2/qtquickcontrols2global.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKCONTROLS2GLOBAL_H
+#define QTQUICKCONTROLS2GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKCONTROLS2_LIB)
+# define Q_QUICKCONTROLS2_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKCONTROLS2_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKCONTROLS2_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+Q_QUICKCONTROLS2_EXPORT void qml_register_types_QtQuick_Controls();
+
+#endif // QTQUICKCONTROLS2GLOBAL_H
diff --git a/src/quickcontrols2/qtquickcontrols2plugin.cpp b/src/quickcontrols2/qtquickcontrols2plugin.cpp
new file mode 100644
index 0000000000..7b0f43ca65
--- /dev/null
+++ b/src/quickcontrols2/qtquickcontrols2plugin.cpp
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/private/qfileselector_p.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQuickTemplates2/private/qquicktheme_p_p.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2/qquickstyle.h>
+#include <QtQuickControls2/qtquickcontrols2global.h>
+
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls);
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQtQuickControls2Plugin, "qt.quick.controls.qtquickcontrols2plugin")
+
+class QtQuickControls2Plugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2Plugin(QObject *parent = nullptr);
+ ~QtQuickControls2Plugin();
+
+ void registerTypes(const char *uri) override;
+ void unregisterTypes() override;
+
+private:
+ // We store these because the style plugins can be unregistered before
+ // QtQuickControls2Plugin, and since QQuickStylePlugin calls QQuickStylePrivate::reset(),
+ // the style information can be lost when it comes time to call qmlUnregisterModuleImport().
+ // It also avoids unnecessarily resolving the style after resetting it just to get the style
+ // name in unregisterTypes().
+ bool customStyle = false;
+ QString registeredStyleUri;
+ QString registeredFallbackStyleUri;
+};
+
+static const char *qtQuickControlsUri = "QtQuick.Controls";
+
+QString styleUri()
+{
+ const QString style = QQuickStyle::name();
+ if (!QQuickStylePrivate::isCustomStyle()) {
+ // The style set is a built-in style.
+ const QString styleName = QQuickStylePrivate::effectiveStyleName(style);
+ return QString::fromLatin1("QtQuick.Controls.%1").arg(styleName);
+ }
+
+ // This is a custom style, so just use the name as the import uri.
+ QString styleName = style;
+ if (styleName.startsWith(QLatin1String(":/")))
+ styleName.remove(0, 2);
+ return styleName;
+}
+
+QString fallbackStyleUri()
+{
+ // The fallback style must be a built-in style, so we don't need to check for custom styles here.
+ const QString fallbackStyle = QQuickStylePrivate::fallbackStyle();
+ const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(fallbackStyle);
+ return QString::fromLatin1("QtQuick.Controls.%1").arg(fallbackStyleName);
+}
+
+QtQuickControls2Plugin::QtQuickControls2Plugin(QObject *parent) : QQmlExtensionPlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls;
+ Q_UNUSED(registration);
+}
+
+QtQuickControls2Plugin::~QtQuickControls2Plugin()
+{
+ // Intentionally empty: we use register/unregisterTypes() to do
+ // initialization and cleanup, as plugins are not unloaded on macOS.
+}
+
+void QtQuickControls2Plugin::registerTypes(const char *uri)
+{
+ qCDebug(lcQtQuickControls2Plugin) << "registerTypes() called with uri" << uri;
+
+ // It's OK that the style is resolved more than once; some accessors like name() cause it to be called, for example.
+ QQuickStylePrivate::init();
+
+ const QString styleName = QQuickStylePrivate::effectiveStyleName(QQuickStyle::name());
+ const QString fallbackStyleName = QQuickStylePrivate::effectiveStyleName(QQuickStylePrivate::fallbackStyle());
+ qCDebug(lcQtQuickControls2Plugin) << "style:" << QQuickStyle::name() << "effective style:" << styleName
+ << "fallback style:" << QQuickStylePrivate::fallbackStyle() << "effective fallback style:" << fallbackStyleName;
+
+ // If the style is Basic, we don't need to register the fallback because the Basic style
+ // provides all controls. Also, if we didn't return early here, we can get an infinite import loop
+ // when the style is set to Basic.
+ if (styleName != fallbackStyleName && styleName != QLatin1String("Basic")) {
+ registeredFallbackStyleUri = ::fallbackStyleUri();
+ qCDebug(lcQtQuickControls2Plugin) << "calling qmlRegisterModuleImport() to register fallback style with"
+ << " uri \"" << qtQuickControlsUri << "\" moduleMajor" << QQmlModuleImportModuleAny
+ << "import" << registeredFallbackStyleUri << "importMajor" << QQmlModuleImportAuto;
+ // The fallback style must be a built-in style, so we match the version number.
+ qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredFallbackStyleUri.toUtf8().constData(),
+ QQmlModuleImportAuto, QQmlModuleImportAuto);
+ }
+
+ // If the user imports QtQuick.Controls 2.15, and they're using the Material style, we should import version 2.15.
+ // However, if they import QtQuick.Controls 2.15, but are using a custom style, we want to use the latest version
+ // number of their style.
+ customStyle = QQuickStylePrivate::isCustomStyle();
+ registeredStyleUri = ::styleUri();
+ const int importMajor = !customStyle ? QQmlModuleImportAuto : QQmlModuleImportLatest;
+ qCDebug(lcQtQuickControls2Plugin).nospace() << "calling qmlRegisterModuleImport() to register primary style with"
+ << " uri \"" << qtQuickControlsUri << "\" moduleMajor " << importMajor
+ << " import " << registeredStyleUri << " importMajor " << importMajor;
+ qmlRegisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredStyleUri.toUtf8().constData(), importMajor);
+
+ if (customStyle)
+ QFileSelectorPrivate::addStatics(QStringList() << styleName);
+}
+
+void QtQuickControls2Plugin::unregisterTypes()
+{
+ qCDebug(lcQtQuickControls2Plugin) << "unregisterTypes() called";
+
+ if (!registeredFallbackStyleUri.isEmpty()) {
+ // We registered a fallback style, so now we need to unregister it.
+ qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredFallbackStyleUri.toUtf8().constData(),
+ QQmlModuleImportAuto, QQmlModuleImportAuto);
+ registeredFallbackStyleUri.clear();
+ }
+
+ const int importMajor = !customStyle ? QQmlModuleImportAuto : QQmlModuleImportLatest;
+ qmlUnregisterModuleImport(qtQuickControlsUri, QQmlModuleImportModuleAny, registeredStyleUri.toUtf8().constData(), importMajor);
+ customStyle = false;
+ registeredStyleUri.clear();
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2plugin.moc"
diff --git a/src/quickcontrols2/universal/ApplicationWindow.qml b/src/quickcontrols2/universal/ApplicationWindow.qml
new file mode 100644
index 0000000000..2ec9c56566
--- /dev/null
+++ b/src/quickcontrols2/universal/ApplicationWindow.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.ApplicationWindow {
+ id: window
+
+ color: Universal.background
+
+ FocusRectangle {
+ parent: window.activeFocusControl
+ width: parent ? parent.width : 0
+ height: parent ? parent.height : 0
+ visible: parent && !!parent.useSystemFocusVisuals && !!parent.visualFocus
+ }
+}
diff --git a/src/quickcontrols2/universal/BusyIndicator.qml b/src/quickcontrols2/universal/BusyIndicator.qml
new file mode 100644
index 0000000000..0bd3ca038a
--- /dev/null
+++ b/src/quickcontrols2/universal/BusyIndicator.qml
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.BusyIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: BusyIndicatorImpl {
+ implicitWidth: 20
+ implicitHeight: 20
+
+ readonly property real size: Math.min(control.availableWidth, control.availableHeight)
+
+ count: size < 60 ? 5 : 6 // "Small" vs. "Large"
+ color: control.Universal.accent
+ visible: control.running
+ }
+}
diff --git a/src/quickcontrols2/universal/Button.qml b/src/quickcontrols2/universal/Button.qml
new file mode 100644
index 0000000000..7dd2ff3464
--- /dev/null
+++ b/src/quickcontrols2/universal/Button.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 8
+ verticalPadding: padding - 4
+ spacing: 8
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ property bool useSystemFocusVisuals: true
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+
+ visible: !control.flat || control.down || control.checked || control.highlighted
+ color: control.down ? control.Universal.baseMediumLowColor :
+ control.enabled && (control.highlighted || control.checked) ? control.Universal.accent :
+ control.Universal.baseLowColor
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ visible: enabled && control.hovered
+ border.width: 2 // ButtonBorderThemeThickness
+ border.color: control.Universal.baseMediumLowColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/CMakeLists.txt b/src/quickcontrols2/universal/CMakeLists.txt
new file mode 100644
index 0000000000..823954e409
--- /dev/null
+++ b/src/quickcontrols2/universal/CMakeLists.txt
@@ -0,0 +1,151 @@
+#####################################################################
+## qtquickcontrols2universalstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "ApplicationWindow.qml"
+ "BusyIndicator.qml"
+ "Button.qml"
+ "CheckBox.qml"
+ "CheckDelegate.qml"
+ "ComboBox.qml"
+ "DelayButton.qml"
+ "Dial.qml"
+ "Dialog.qml"
+ "DialogButtonBox.qml"
+ "Drawer.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "HorizontalHeaderView.qml"
+ "ItemDelegate.qml"
+ "Label.qml"
+ "Menu.qml"
+ "MenuBar.qml"
+ "MenuBarItem.qml"
+ "MenuItem.qml"
+ "MenuSeparator.qml"
+ "Page.qml"
+ "PageIndicator.qml"
+ "Pane.qml"
+ "Popup.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "RadioDelegate.qml"
+ "RangeSlider.qml"
+ "RoundButton.qml"
+ "ScrollView.qml"
+ "ScrollBar.qml"
+ "ScrollIndicator.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "SplitView.qml"
+ "StackView.qml"
+ "SwipeDelegate.qml"
+ "SwitchDelegate.qml"
+ "Switch.qml"
+ "TabBar.qml"
+ "TabButton.qml"
+ "TextArea.qml"
+ "TextField.qml"
+ "ToolBar.qml"
+ "ToolButton.qml"
+ "ToolSeparator.qml"
+ "ToolTip.qml"
+ "Tumbler.qml"
+ "VerticalHeaderView.qml"
+)
+set_source_files_properties(DelayButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.2;6.0"
+)
+set_source_files_properties(Dialog.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(DialogButtonBox.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(HorizontalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+set_source_files_properties(MenuBar.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuBarItem.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.3;6.0"
+)
+set_source_files_properties(MenuSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(RoundButton.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(SplitView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.13;6.0"
+)
+set_source_files_properties(ToolSeparator.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.1;6.0"
+)
+set_source_files_properties(VerticalHeaderView.qml PROPERTIES
+ QT_QML_SOURCE_VERSIONS "2.15;6.0"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2universalstyleplugin
+ URI "QtQuick.Controls.Universal"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2UniversalStylePlugin
+ IMPORTS
+ QtQuick.Controls.Basic/auto
+ PLUGIN_TARGET qtquickcontrols2universalstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickuniversalstyle.cpp qquickuniversalstyle_p.h
+ qquickuniversaltheme.cpp qquickuniversaltheme_p.h
+ qtquickcontrols2universalstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_internal_add_resource(qtquickcontrols2universalstyleplugin "qtquickcontrols2universalstyleplugin"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Controls/Universal"
+ FILES
+ "images/checkmark.png"
+ "images/checkmark@2x.png"
+ "images/checkmark@3x.png"
+ "images/checkmark@4x.png"
+ "images/downarrow.png"
+ "images/downarrow@2x.png"
+ "images/downarrow@3x.png"
+ "images/downarrow@4x.png"
+ "images/leftarrow.png"
+ "images/leftarrow@2x.png"
+ "images/leftarrow@3x.png"
+ "images/leftarrow@4x.png"
+ "images/rightarrow.png"
+ "images/rightarrow@2x.png"
+ "images/rightarrow@3x.png"
+ "images/rightarrow@4x.png"
+)
+
+add_subdirectory(impl)
+
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2universalstyleplugin quickwindow)
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2universalstyleplugin
+ qtquickcontrols2universalstyleimplplugin)
+
+# Basic style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2universalstyleplugin
+ qtquickcontrols2basicstyleplugin)
diff --git a/src/quickcontrols2/universal/CheckBox.qml b/src/quickcontrols2/universal/CheckBox.qml
new file mode 100644
index 0000000000..ff35d37268
--- /dev/null
+++ b/src/quickcontrols2/universal/CheckBox.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+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)
+
+ padding: 6
+ spacing: 8
+
+ property bool useSystemFocusVisuals: true
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+}
diff --git a/src/quickcontrols2/universal/CheckDelegate.qml b/src/quickcontrols2/universal/CheckDelegate.qml
new file mode 100644
index 0000000000..26a6d923a2
--- /dev/null
+++ b/src/quickcontrols2/universal/CheckDelegate.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.CheckDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ indicator: CheckIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ visible: enabled && (control.down || control.highlighted || control.visualFocus || control.hovered)
+ color: control.down ? control.Universal.listMediumColor :
+ control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+
+ }
+}
diff --git a/src/quickcontrols2/universal/ComboBox.qml b/src/quickcontrols2/universal/ComboBox.qml
new file mode 100644
index 0000000000..f2de4ec562
--- /dev/null
+++ b/src/quickcontrols2/universal/ComboBox.qml
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ComboBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: padding + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+ rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
+
+ Universal.theme: editable && activeFocus ? Universal.Light : undefined
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ indicator: ColorImage {
+ x: control.mirrored ? control.padding : control.width - width - control.padding
+ y: control.topPadding + (control.availableHeight - height) / 2
+ color: !control.enabled ? control.Universal.baseLowColor : control.Universal.baseMediumHighColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/downarrow.png"
+
+ Rectangle {
+ z: -1
+ width: parent.width
+ height: parent.height
+ color: control.activeFocus ? control.Universal.accent :
+ control.pressed ? control.Universal.baseMediumLowColor :
+ control.hovered ? control.Universal.baseLowColor : "transparent"
+ visible: control.editable && !control.contentItem.hovered && (control.pressed || control.hovered)
+ opacity: control.activeFocus && !control.pressed ? 0.4 : 1.0
+ }
+ }
+
+ contentItem: T.TextField {
+ leftPadding: control.mirrored ? 1 : 12
+ rightPadding: control.mirrored ? 10 : 1
+ topPadding: 5 - control.topPadding
+ bottomPadding: 7 - control.bottomPadding
+
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: !control.enabled ? control.Universal.chromeDisabledLowColor :
+ control.editable && control.activeFocus ? control.Universal.chromeBlackHighColor : control.Universal.foreground
+ selectionColor: control.Universal.accent
+ selectedTextColor: control.Universal.chromeWhiteColor
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: Rectangle {
+ implicitWidth: 120
+ implicitHeight: 32
+
+ border.width: control.flat ? 0 : 2 // ComboBoxBorderThemeThickness
+ border.color: !control.enabled ? control.Universal.baseLowColor :
+ control.editable && control.activeFocus ? control.Universal.accent :
+ control.down ? control.Universal.baseMediumLowColor :
+ control.hovered ? control.Universal.baseMediumColor : control.Universal.baseMediumLowColor
+ color: !control.enabled ? control.Universal.baseLowColor :
+ control.down ? control.Universal.listMediumColor :
+ control.flat && control.hovered ? control.Universal.listLowColor :
+ control.editable && control.activeFocus ? control.Universal.background : control.Universal.altMediumLowColor
+ visible: !control.flat || control.pressed || control.hovered || control.visualFocus
+
+ Rectangle {
+ x: 2
+ y: 2
+ width: parent.width - 4
+ height: parent.height - 4
+
+ visible: control.visualFocus && !control.editable
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+ }
+
+ popup: T.Popup {
+ width: control.width
+ height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
+ topMargin: 8
+ bottomMargin: 8
+
+ Universal.theme: control.Universal.theme
+ Universal.accent: control.Universal.accent
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/DelayButton.qml b/src/quickcontrols2/universal/DelayButton.qml
new file mode 100644
index 0000000000..a30f04b7f7
--- /dev/null
+++ b/src/quickcontrols2/universal/DelayButton.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.DelayButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 8
+ verticalPadding: padding - 4
+
+ property bool useSystemFocusVisuals: true
+
+ transition: Transition {
+ NumberAnimation {
+ duration: control.delay * (control.pressed ? 1.0 - control.progress : 0.3 * control.progress)
+ }
+ }
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+
+ color: control.down ? control.Universal.baseMediumLowColor :
+ control.enabled && control.checked ? control.Universal.accent : control.Universal.baseLowColor
+
+ Rectangle {
+ visible: !control.checked
+ width: parent.width * control.progress
+ height: parent.height
+ color: control.Universal.accent
+ }
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ visible: enabled && control.hovered
+ border.width: 2 // ButtonBorderThemeThickness
+ border.color: control.Universal.baseMediumLowColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/Dial.qml b/src/quickcontrols2/universal/Dial.qml
new file mode 100644
index 0000000000..cd9e615edb
--- /dev/null
+++ b/src/quickcontrols2/universal/Dial.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Dial {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 100
+
+ x: control.width / 2 - width / 2
+ y: control.height / 2 - height / 2
+ width: Math.max(64, Math.min(control.width, control.height))
+ height: width
+ radius: width / 2
+ color: "transparent"
+ border.color: !control.enabled ? control.Universal.baseLowColor : control.Universal.baseMediumColor
+ border.width: 2
+ }
+
+ handle: Rectangle {
+ implicitWidth: 14
+ implicitHeight: 14
+
+ x: control.background.x + control.background.width / 2 - width / 2
+ y: control.background.y + control.background.height / 2 - height / 2
+
+ radius: width / 2
+ color: !control.enabled ? control.Universal.baseLowColor :
+ control.pressed ? control.Universal.baseMediumColor :
+ control.hovered ? control.Universal.baseHighColor : control.Universal.baseMediumHighColor
+
+ transform: [
+ Translate {
+ y: -control.background.height * 0.4 + control.handle.height / 2
+ },
+ Rotation {
+ angle: control.angle
+ origin.x: control.handle.width / 2
+ origin.y: control.handle.height / 2
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols2/universal/Dialog.qml b/src/quickcontrols2/universal/Dialog.qml
new file mode 100644
index 0000000000..3cebf7f07b
--- /dev/null
+++ b/src/quickcontrols2/universal/Dialog.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Dialog {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 24
+ verticalPadding: 18
+
+ background: Rectangle {
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title
+ elide: Label.ElideRight
+ topPadding: 18
+ leftPadding: 24
+ rightPadding: 24
+ // TODO: QPlatformTheme::TitleBarFont
+ font.pixelSize: 20
+ background: Rectangle {
+ x: 1; y: 1 // // FlyoutBorderThemeThickness
+ color: control.Universal.chromeMediumLowColor
+ width: parent.width - 2
+ height: parent.height - 1
+ }
+ }
+
+ footer: DialogButtonBox {
+ visible: count > 0
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/DialogButtonBox.qml b/src/quickcontrols2/universal/DialogButtonBox.qml
new file mode 100644
index 0000000000..bf3f5af0a4
--- /dev/null
+++ b/src/quickcontrols2/universal/DialogButtonBox.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.DialogButtonBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ (control.count === 1 ? implicitContentWidth * 2 : implicitContentWidth) + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ contentWidth: contentItem.contentWidth
+
+ spacing: 4
+ padding: 24
+ topPadding: position === T.DialogButtonBox.Footer ? 6 : 24
+ bottomPadding: position === T.DialogButtonBox.Header ? 6 : 24
+ alignment: count === 1 ? Qt.AlignRight : undefined
+
+ delegate: Button {
+ width: control.count === 1 ? control.availableWidth / 2 : undefined
+ }
+
+ contentItem: ListView {
+ implicitWidth: contentWidth
+ model: control.contentModel
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ snapMode: ListView.SnapToItem
+ }
+
+ background: Rectangle {
+ implicitHeight: 32
+ color: control.Universal.chromeMediumLowColor
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ }
+}
diff --git a/src/quickcontrols2/universal/Drawer.qml b/src/quickcontrols2/universal/Drawer.qml
new file mode 100644
index 0000000000..19f78f1e4b
--- /dev/null
+++ b/src/quickcontrols2/universal/Drawer.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Drawer {
+ id: control
+
+ parent: T.Overlay.overlay
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ topPadding: control.edge === Qt.BottomEdge
+ leftPadding: control.edge === Qt.RightEdge
+ rightPadding: control.edge === Qt.LeftEdge
+ bottomPadding: control.edge === Qt.TopEdge
+
+ enter: Transition { SmoothedAnimation { velocity: 5 } }
+ exit: Transition { SmoothedAnimation { velocity: 5 } }
+
+ background: Rectangle {
+ color: control.Universal.chromeMediumLowColor
+ Rectangle {
+ readonly property bool horizontal: control.edge === Qt.LeftEdge || control.edge === Qt.RightEdge
+ width: horizontal ? 1 : parent.width
+ height: horizontal ? parent.height : 1
+ color: control.Universal.chromeHighColor
+ x: control.edge === Qt.LeftEdge ? parent.width - 1 : 0
+ y: control.edge === Qt.TopEdge ? parent.height - 1 : 0
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/Frame.qml b/src/quickcontrols2/universal/Frame.qml
new file mode 100644
index 0000000000..780ba7348b
--- /dev/null
+++ b/src/quickcontrols2/universal/Frame.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Frame {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: control.Universal.chromeDisabledLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/GroupBox.qml b/src/quickcontrols2/universal/GroupBox.qml
new file mode 100644
index 0000000000..5104b710ca
--- /dev/null
+++ b/src/quickcontrols2/universal/GroupBox.qml
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.GroupBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ spacing: 12
+ padding: 12
+ topPadding: padding + (implicitLabelWidth > 0 ? implicitLabelHeight + spacing : 0)
+
+ label: Text {
+ x: control.leftPadding
+ width: control.availableWidth
+
+ text: control.title
+ font: control.font
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+
+ background: Rectangle {
+ y: control.topPadding - control.bottomPadding
+ width: parent.width
+ height: parent.height - control.topPadding + control.bottomPadding
+
+ color: "transparent"
+ border.color: control.Universal.chromeDisabledLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/HorizontalHeaderView.qml b/src/quickcontrols2/universal/HorizontalHeaderView.qml
new file mode 100644
index 0000000000..0bf88ebcc8
--- /dev/null
+++ b/src/quickcontrols2/universal/HorizontalHeaderView.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.HorizontalHeaderView {
+ id: control
+
+ implicitWidth: syncView ? syncView.width : 0
+ implicitHeight: contentHeight
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: text.implicitWidth + (cellPadding * 2)
+ implicitHeight: Math.max(control.height, text.implicitHeight + (cellPadding * 2))
+ color: control.Universal.background
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/ItemDelegate.qml b/src/quickcontrols2/universal/ItemDelegate.qml
new file mode 100644
index 0000000000..561a6b6997
--- /dev/null
+++ b/src/quickcontrols2/universal/ItemDelegate.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.ItemDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ visible: enabled && (control.down || control.highlighted || control.visualFocus || control.hovered)
+ color: control.down ? control.Universal.listMediumColor :
+ control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+
+ }
+}
diff --git a/src/quickcontrols2/universal/Label.qml b/src/quickcontrols2/universal/Label.qml
new file mode 100644
index 0000000000..9460c997eb
--- /dev/null
+++ b/src/quickcontrols2/universal/Label.qml
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Label {
+ id: control
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ linkColor: Universal.accent
+}
diff --git a/src/quickcontrols2/universal/Menu.qml b/src/quickcontrols2/universal/Menu.qml
new file mode 100644
index 0000000000..c4723f32aa
--- /dev/null
+++ b/src/quickcontrols2/universal/Menu.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Window
+
+T.Menu {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 0
+ overlap: 1
+
+ delegate: MenuItem { }
+
+ contentItem: ListView {
+ implicitHeight: contentHeight
+ model: control.contentModel
+ interactive: Window.window
+ ? contentHeight + control.topPadding + control.bottomPadding > Window.window.height
+ : false
+ clip: true
+ currentIndex: control.currentIndex
+
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/MenuBar.qml b/src/quickcontrols2/universal/MenuBar.qml
new file mode 100644
index 0000000000..2ab5891960
--- /dev/null
+++ b/src/quickcontrols2/universal/MenuBar.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.MenuBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ delegate: MenuBarItem { }
+
+ contentItem: Row {
+ spacing: control.spacing
+ Repeater {
+ model: control.contentModel
+ }
+ }
+
+ background: Rectangle {
+ implicitHeight: 40
+ color: control.Universal.chromeMediumColor
+ }
+}
diff --git a/src/quickcontrols2/universal/MenuBarItem.qml b/src/quickcontrols2/universal/MenuBarItem.qml
new file mode 100644
index 0000000000..786be1325c
--- /dev/null
+++ b/src/quickcontrols2/universal/MenuBarItem.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+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)
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+ spacing: 12
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: !enabled ? Universal.baseLowColor : Universal.baseHighColor
+
+ 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.enabled ? control.Universal.baseLowColor : control.Universal.baseHighColor
+ }
+
+ background: Rectangle {
+ implicitWidth: 40
+ implicitHeight: 40
+
+ color: !control.enabled ? control.Universal.baseLowColor :
+ control.down ? control.Universal.listMediumColor :
+ control.highlighted ? control.Universal.listLowColor : "transparent"
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+
+ visible: control.visualFocus
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/MenuItem.qml b/src/quickcontrols2/universal/MenuItem.qml
new file mode 100644
index 0000000000..8287b0a828
--- /dev/null
+++ b/src/quickcontrols2/universal/MenuItem.qml
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+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)
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+ spacing: 12
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: !enabled ? Universal.baseLowColor : Universal.baseHighColor
+
+ contentItem: IconLabel {
+ readonly property real arrowPadding: control.subMenu && control.arrow ? control.arrow.width + control.spacing : 0
+ readonly property real indicatorPadding: control.checkable && control.indicator ? control.indicator.width + control.spacing : 0
+ leftPadding: !control.mirrored ? indicatorPadding : arrowPadding
+ rightPadding: control.mirrored ? indicatorPadding : arrowPadding
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: !control.enabled ? control.Universal.baseLowColor : control.Universal.baseHighColor
+ }
+
+ arrow: ColorImage {
+ x: control.mirrored ? control.leftPadding : control.width - width - control.rightPadding
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.subMenu
+ mirror: control.mirrored
+ color: !enabled ? control.Universal.baseLowColor : control.Universal.baseHighColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/rightarrow.png"
+ }
+
+ indicator: ColorImage {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+
+ visible: control.checked
+ color: !control.enabled ? control.Universal.baseLowColor : control.down ? control.Universal.baseHighColor : control.Universal.baseMediumHighColor
+ source: !control.checkable ? "" : "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/checkmark.png"
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 40
+
+ color: !control.enabled ? control.Universal.baseLowColor :
+ control.down ? control.Universal.listMediumColor :
+ control.highlighted ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+
+ Rectangle {
+ x: 1; y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+
+ visible: control.visualFocus
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/MenuSeparator.qml b/src/quickcontrols2/universal/MenuSeparator.qml
new file mode 100644
index 0000000000..be6fad4580
--- /dev/null
+++ b/src/quickcontrols2/universal/MenuSeparator.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.MenuSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 12
+ topPadding: 9
+ bottomPadding: 10
+
+ contentItem: Rectangle {
+ implicitWidth: 188
+ implicitHeight: 1
+ color: control.Universal.baseMediumLowColor
+ }
+
+ background: Rectangle {
+ color: control.Universal.altMediumLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/Page.qml b/src/quickcontrols2/universal/Page.qml
new file mode 100644
index 0000000000..8946e7adbf
--- /dev/null
+++ b/src/quickcontrols2/universal/Page.qml
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Page {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ background: Rectangle {
+ color: control.Universal.background
+ }
+}
diff --git a/src/quickcontrols2/universal/PageIndicator.qml b/src/quickcontrols2/universal/PageIndicator.qml
new file mode 100644
index 0000000000..1225bdab33
--- /dev/null
+++ b/src/quickcontrols2/universal/PageIndicator.qml
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.PageIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 7
+
+ delegate: Rectangle {
+ implicitWidth: 5
+ implicitHeight: 5
+
+ radius: width / 2
+ color: index === control.currentIndex ? control.Universal.baseMediumHighColor :
+ pressed ? control.Universal.baseMediumLowColor : control.Universal.baseLowColor
+
+ required property int index
+ }
+
+ contentItem: Row {
+ spacing: control.spacing
+
+ Repeater {
+ model: control.count
+ delegate: control.delegate
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/Pane.qml b/src/quickcontrols2/universal/Pane.qml
new file mode 100644
index 0000000000..257f9cafd0
--- /dev/null
+++ b/src/quickcontrols2/universal/Pane.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Pane {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.Universal.background
+ }
+}
diff --git a/src/quickcontrols2/universal/Popup.qml b/src/quickcontrols2/universal/Popup.qml
new file mode 100644
index 0000000000..5e972ea993
--- /dev/null
+++ b/src/quickcontrols2/universal/Popup.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Popup {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ padding: 12
+
+ background: Rectangle {
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/ProgressBar.qml b/src/quickcontrols2/universal/ProgressBar.qml
new file mode 100644
index 0000000000..4f8cc87428
--- /dev/null
+++ b/src/quickcontrols2/universal/ProgressBar.qml
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.ProgressBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: ProgressBarImpl {
+ implicitHeight: 10
+
+ scale: control.mirrored ? -1 : 1
+ color: control.Universal.accent
+ progress: control.position
+ indeterminate: control.visible && control.indeterminate
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 10
+ y: (control.height - height) / 2
+ height: 10
+
+ visible: !control.indeterminate
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/README.md b/src/quickcontrols2/universal/README.md
new file mode 100644
index 0000000000..8d02d18ba3
--- /dev/null
+++ b/src/quickcontrols2/universal/README.md
@@ -0,0 +1,9 @@
+# Universal Style
+
+This style is based on the [Microsoft Universal Design Guidelines](https://dev.windows.com/design).
+
+The colors and metrics used all around the QML and C++ files originate from the Windows 10 SDK. The files are called **generic.xaml** and **themeresources.xml**, and they are located in the following folder:
+
+ \(Program Files)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<SDK version>\Generic
+
+See also [XAML theme resources](https://msdn.microsoft.com/en-us/library/windows/apps/mt187274.aspx).
diff --git a/src/quickcontrols2/universal/RadioButton.qml b/src/quickcontrols2/universal/RadioButton.qml
new file mode 100644
index 0000000000..abd386ce9d
--- /dev/null
+++ b/src/quickcontrols2/universal/RadioButton.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+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)
+
+ padding: 6
+ spacing: 8
+
+ property bool useSystemFocusVisuals: true
+
+ indicator: RadioIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+}
diff --git a/src/quickcontrols2/universal/RadioDelegate.qml b/src/quickcontrols2/universal/RadioDelegate.qml
new file mode 100644
index 0000000000..5f7a129546
--- /dev/null
+++ b/src/quickcontrols2/universal/RadioDelegate.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.RadioDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ indicator: RadioIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ visible: enabled && (control.down || control.highlighted || control.visualFocus || control.hovered)
+ color: control.down ? control.Universal.listMediumColor :
+ control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+
+ }
+}
diff --git a/src/quickcontrols2/universal/RangeSlider.qml b/src/quickcontrols2/universal/RangeSlider.qml
new file mode 100644
index 0000000000..1156f5789e
--- /dev/null
+++ b/src/quickcontrols2/universal/RangeSlider.qml
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+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)
+
+ padding: 6
+
+ first.handle: Rectangle {
+ implicitWidth: control.horizontal ? 8 : 24
+ implicitHeight: control.horizontal ? 24 : 8
+
+ x: control.leftPadding + (control.horizontal ? control.first.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.first.visualPosition * (control.availableHeight - height))
+
+ radius: 4
+ color: control.first.pressed ? control.Universal.chromeHighColor :
+ control.first.hovered ? control.Universal.chromeAltLowColor :
+ control.enabled ? control.Universal.accent : control.Universal.chromeDisabledHighColor
+ }
+
+ second.handle: Rectangle {
+ implicitWidth: control.horizontal ? 8 : 24
+ implicitHeight: control.horizontal ? 24 : 8
+
+ x: control.leftPadding + (control.horizontal ? control.second.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.second.visualPosition * (control.availableHeight - height))
+
+ radius: 4
+ color: control.second.pressed ? control.Universal.chromeHighColor :
+ control.second.hovered ? control.Universal.chromeAltLowColor :
+ control.enabled ? control.Universal.accent : control.Universal.chromeDisabledHighColor
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal ? 200 : 18
+ implicitHeight: control.horizontal ? 18 : 200
+
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ width: control.horizontal ? control.availableWidth : implicitWidth
+ height: control.horizontal ? implicitHeight : control.availableHeight
+
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ Rectangle {
+ x: control.horizontal ? 0 : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : 0
+ width: control.horizontal ? parent.width : 2 // SliderBackgroundThemeHeight
+ height: control.vertical ? parent.height : 2 // SliderBackgroundThemeHeight
+
+ color: enabled && control.hovered && !control.pressed ? control.Universal.baseMediumColor :
+ control.enabled ? control.Universal.baseMediumLowColor : control.Universal.chromeDisabledHighColor
+ }
+
+ Rectangle {
+ x: control.horizontal ? control.first.position * parent.width : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : control.second.visualPosition * parent.height
+ width: control.horizontal ? control.second.position * parent.width - control.first.position * parent.width : 2 // SliderBackgroundThemeHeight
+ height: control.vertical ? control.second.position * parent.height - control.first.position * parent.height : 2 // SliderBackgroundThemeHeight
+
+ color: control.enabled ? control.Universal.accent : control.Universal.chromeDisabledHighColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/RoundButton.qml b/src/quickcontrols2/universal/RoundButton.qml
new file mode 100644
index 0000000000..0592596b76
--- /dev/null
+++ b/src/quickcontrols2/universal/RoundButton.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.RoundButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 8
+ spacing: 8
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ property bool useSystemFocusVisuals: true
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ implicitWidth: 32
+ implicitHeight: 32
+
+ radius: control.radius
+ visible: !control.flat || control.down || control.checked || control.highlighted
+ color: control.down ? control.Universal.baseMediumLowColor :
+ control.enabled && (control.highlighted || control.checked) ? control.Universal.accent :
+ control.Universal.baseLowColor
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ radius: control.radius
+ color: "transparent"
+ visible: enabled && control.hovered
+ border.width: 2 // ButtonBorderThemeThickness
+ border.color: control.Universal.baseMediumLowColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/ScrollBar.qml b/src/quickcontrols2/universal/ScrollBar.qml
new file mode 100644
index 0000000000..c0cfd081f6
--- /dev/null
+++ b/src/quickcontrols2/universal/ScrollBar.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ScrollBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ visible: control.policy !== T.ScrollBar.AlwaysOff
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ // TODO: arrows
+
+ contentItem: Rectangle {
+ implicitWidth: control.interactive ? 12 : 6
+ implicitHeight: control.interactive ? 12: 6
+
+ color: control.pressed ? control.Universal.baseMediumColor :
+ enabled && control.interactive && control.hovered ? control.Universal.baseMediumLowColor :
+ control.Universal.chromeHighColor
+ opacity: 0.0
+ }
+
+ background: Rectangle {
+ implicitWidth: control.interactive ? 12 : 6
+ implicitHeight: control.interactive ? 12: 6
+
+ color: control.Universal.chromeLowColor
+ visible: control.size < 1.0
+ opacity: 0.0
+ }
+
+ states: [
+ State {
+ name: "active"
+ when: control.policy === T.ScrollBar.AlwaysOn || (control.active && control.size < 1.0)
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "active"
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 1.0 }
+ },
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PropertyAction{ targets: [control.contentItem, control.background]; property: "opacity"; value: 1.0 }
+ PauseAnimation { duration: 3000 }
+ NumberAnimation { targets: [control.contentItem, control.background]; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+}
diff --git a/src/quickcontrols2/universal/ScrollIndicator.qml b/src/quickcontrols2/universal/ScrollIndicator.qml
new file mode 100644
index 0000000000..f66a96587c
--- /dev/null
+++ b/src/quickcontrols2/universal/ScrollIndicator.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ScrollIndicator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ contentItem: Rectangle {
+ implicitWidth: 6
+ implicitHeight: 6
+
+ color: control.Universal.baseMediumLowColor
+ visible: control.size < 1.0
+ opacity: 0.0
+
+ states: [
+ State {
+ name: "active"
+ when: control.active
+ }
+ ]
+
+ transitions: [
+ Transition {
+ to: "active"
+ NumberAnimation { target: control.contentItem; property: "opacity"; to: 1.0 }
+ },
+ Transition {
+ from: "active"
+ SequentialAnimation {
+ PauseAnimation { duration: 5000 }
+ NumberAnimation { target: control.contentItem; property: "opacity"; to: 0.0 }
+ }
+ }
+ ]
+ }
+}
diff --git a/src/quickcontrols2/universal/ScrollView.qml b/src/quickcontrols2/universal/ScrollView.qml
new file mode 100644
index 0000000000..a6bba9de05
--- /dev/null
+++ b/src/quickcontrols2/universal/ScrollView.qml
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: control.topPadding
+ height: control.availableHeight
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: control.leftPadding
+ y: control.height - height
+ width: control.availableWidth
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/universal/SelectionRectangle.qml b/src/quickcontrols2/universal/SelectionRectangle.qml
new file mode 100644
index 0000000000..708e701c9c
--- /dev/null
+++ b/src/quickcontrols2/universal/SelectionRectangle.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: handle
+ bottomRightHandle: handle
+
+ Component {
+ id: handle
+ Rectangle {
+ implicitWidth: 8
+ implicitHeight: 24
+ radius: 4
+ color: tapHandler.pressed || SelectionRectangle.dragging ? control.Universal.chromeHighColor :
+ hoverHandler.hovered ? control.Universal.chromeAltLowColor :
+ control.Universal.accent
+ visible: control.active
+
+ property Item control: SelectionRectangle.control
+
+ HoverHandler {
+ id: hoverHandler
+ }
+
+ TapHandler {
+ id: tapHandler
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/Slider.qml b/src/quickcontrols2/universal/Slider.qml
new file mode 100644
index 0000000000..47ea58773c
--- /dev/null
+++ b/src/quickcontrols2/universal/Slider.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding)
+
+ padding: 6
+
+ property bool useSystemFocusVisuals: true
+
+ handle: Rectangle {
+ implicitWidth: control.horizontal ? 8 : 24
+ implicitHeight: control.horizontal ? 24 : 8
+
+ x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+
+ radius: 4
+ color: control.pressed ? control.Universal.chromeHighColor :
+ control.enabled ? control.hovered ? control.Universal.chromeAltLowColor :
+ control.Universal.accent : control.Universal.chromeDisabledHighColor
+ }
+
+ background: Item {
+ implicitWidth: control.horizontal ? 200 : 18
+ implicitHeight: control.horizontal ? 18 : 200
+
+ x: control.leftPadding + (control.horizontal ? 0 : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
+ width: control.horizontal ? control.availableWidth : implicitWidth
+ height: control.horizontal ? implicitHeight : control.availableHeight
+
+ scale: control.horizontal && control.mirrored ? -1 : 1
+
+ Rectangle {
+ x: control.horizontal ? 0 : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : 0
+ width: control.horizontal ? parent.width : 2 // SliderTrackThemeHeight
+ height: !control.horizontal ? parent.height : 2 // SliderTrackThemeHeight
+
+ color: enabled && control.hovered && !control.pressed ? control.Universal.baseMediumColor :
+ control.enabled ? control.Universal.baseMediumLowColor : control.Universal.chromeDisabledHighColor
+ }
+
+ Rectangle {
+ x: control.horizontal ? 0 : (parent.width - width) / 2
+ y: control.horizontal ? (parent.height - height) / 2 : control.visualPosition * parent.height
+ width: control.horizontal ? control.position * parent.width : 2 // SliderTrackThemeHeight
+ height: !control.horizontal ? control.position * parent.height : 2 // SliderTrackThemeHeight
+
+ color: control.enabled ? control.Universal.accent : control.Universal.chromeDisabledHighColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/SpinBox.qml b/src/quickcontrols2/universal/SpinBox.qml
new file mode 100644
index 0000000000..0bb5e4b19b
--- /dev/null
+++ b/src/quickcontrols2/universal/SpinBox.qml
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.SpinBox {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentItem.implicitWidth + 16 +
+ up.implicitIndicatorWidth +
+ down.implicitIndicatorWidth)
+ implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight,
+ up.implicitIndicatorHeight,
+ down.implicitIndicatorHeight)
+
+ // TextControlThemePadding + 2 (border)
+ padding: 12
+ topPadding: padding - 7
+ leftPadding: padding + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
+ rightPadding: padding - 4 + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
+ bottomPadding: padding - 5
+
+ Universal.theme: activeFocus ? Universal.Light : undefined
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ text: control.displayText
+
+ font: control.font
+ color: !enabled ? control.Universal.chromeDisabledLowColor :
+ activeFocus ? control.Universal.chromeBlackHighColor : control.Universal.foreground
+ selectionColor: control.Universal.accent
+ selectedTextColor: control.Universal.chromeWhiteColor
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: TextInput.AlignVCenter
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+ }
+
+ up.indicator: Item {
+ implicitWidth: 28
+ height: control.height + 4
+ y: -2
+ x: control.mirrored ? 0 : control.width - width
+
+ Rectangle {
+ x: 2; y: 4
+ width: parent.width - 4
+ height: parent.height - 8
+ color: control.activeFocus ? control.Universal.accent :
+ control.up.pressed ? control.Universal.baseMediumLowColor :
+ control.up.hovered ? control.Universal.baseLowColor : "transparent"
+ visible: control.up.pressed || control.up.hovered
+ opacity: control.activeFocus && !control.up.pressed ? 0.4 : 1.0
+ }
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ color: !enabled ? control.Universal.chromeDisabledLowColor :
+ control.activeFocus ? control.Universal.chromeBlackHighColor : control.Universal.baseHighColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/" + (control.mirrored ? "left" : "right") + "arrow.png"
+ }
+ }
+
+ down.indicator: Item {
+ implicitWidth: 28
+ height: control.height + 4
+ y: -2
+ x: control.mirrored ? control.width - width : 0
+
+ Rectangle {
+ x: 2; y: 4
+ width: parent.width - 4
+ height: parent.height - 8
+ color: control.activeFocus ? control.Universal.accent :
+ control.down.pressed ? control.Universal.baseMediumLowColor :
+ control.down.hovered ? control.Universal.baseLowColor : "transparent"
+ visible: control.down.pressed || control.down.hovered
+ opacity: control.activeFocus && !control.down.pressed ? 0.4 : 1.0
+ }
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ color: !enabled ? control.Universal.chromeDisabledLowColor :
+ control.activeFocus ? control.Universal.chromeBlackHighColor : control.Universal.baseHighColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/" + (control.mirrored ? "right" : "left") + "arrow.png"
+ }
+ }
+
+ background: Rectangle {
+ implicitWidth: 60 + 28 // TextControlThemeMinWidth - 4 (border)
+ implicitHeight: 28 // TextControlThemeMinHeight - 4 (border)
+
+ border.width: 2 // TextControlBorderThemeThickness
+ border.color: !control.enabled ? control.Universal.baseLowColor :
+ control.activeFocus ? control.Universal.accent :
+ control.hovered ? control.Universal.baseMediumColor : control.Universal.chromeDisabledLowColor
+ color: control.enabled ? control.Universal.background : control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/SplitView.qml b/src/quickcontrols2/universal/SplitView.qml
new file mode 100644
index 0000000000..ff753708f1
--- /dev/null
+++ b/src/quickcontrols2/universal/SplitView.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.SplitView {
+ id: control
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ handle: Rectangle {
+ implicitWidth: control.orientation === Qt.Horizontal ? 6 : control.width
+ implicitHeight: control.orientation === Qt.Horizontal ? control.height : 6
+ color: T.SplitHandle.pressed ? control.Universal.baseMediumColor
+ : (enabled && T.SplitHandle.hovered ? control.Universal.baseMediumLowColor : control.Universal.chromeHighColor)
+ }
+}
diff --git a/src/quickcontrols2/universal/StackView.qml b/src/quickcontrols2/universal/StackView.qml
new file mode 100644
index 0000000000..41611dd36b
--- /dev/null
+++ b/src/quickcontrols2/universal/StackView.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.StackView {
+ id: control
+
+ popEnter: Transition {
+ ParallelAnimation {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200; easing.type: Easing.InQuint }
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.3 : 0.3) * -control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+
+ popExit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200; easing.type: Easing.OutQuint }
+ }
+
+ pushEnter: Transition {
+ ParallelAnimation {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200; easing.type: Easing.InQuint }
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.3 : 0.3) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+
+ pushExit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200; easing.type: Easing.OutQuint }
+ }
+
+ replaceEnter: Transition {
+ ParallelAnimation {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200; easing.type: Easing.InQuint }
+ NumberAnimation { property: "x"; from: (control.mirrored ? -0.3 : 0.3) * control.width; to: 0; duration: 400; easing.type: Easing.OutCubic }
+ }
+ }
+
+ replaceExit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 200; easing.type: Easing.OutQuint }
+ }
+}
diff --git a/src/quickcontrols2/universal/SwipeDelegate.qml b/src/quickcontrols2/universal/SwipeDelegate.qml
new file mode 100644
index 0000000000..507c77023e
--- /dev/null
+++ b/src/quickcontrols2/universal/SwipeDelegate.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.SwipeDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ swipe.transition: Transition { SmoothedAnimation { velocity: 3; easing.type: Easing.InOutCubic } }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ color: control.Universal.background
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ color: control.down ? control.Universal.listMediumColor :
+ enabled && control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/Switch.qml b/src/quickcontrols2/universal/Switch.qml
new file mode 100644
index 0000000000..33ee4abb96
--- /dev/null
+++ b/src/quickcontrols2/universal/Switch.qml
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.Switch {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 5
+ spacing: 8
+
+ property bool useSystemFocusVisuals: true
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ 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
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+}
diff --git a/src/quickcontrols2/universal/SwitchDelegate.qml b/src/quickcontrols2/universal/SwitchDelegate.qml
new file mode 100644
index 0000000000..d3b6cf2da8
--- /dev/null
+++ b/src/quickcontrols2/universal/SwitchDelegate.qml
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.SwitchDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ indicator: SwitchIndicator {
+ x: control.text ? (control.mirrored ? control.leftPadding : control.width - width - control.rightPadding) : control.leftPadding + (control.availableWidth - width) / 2
+ y: control.topPadding + (control.availableHeight - height) / 2
+ control: control
+ }
+
+ contentItem: IconLabel {
+ leftPadding: !control.mirrored ? 0 : control.indicator.width + control.spacing
+ rightPadding: control.mirrored ? 0 : control.indicator.width + control.spacing
+
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+ alignment: control.display === IconLabel.IconOnly || control.display === IconLabel.TextUnderIcon ? Qt.AlignCenter : Qt.AlignLeft
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ visible: enabled && (control.down || control.highlighted || control.visualFocus || control.hovered)
+ color: control.down ? control.Universal.listMediumColor :
+ control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+
+ }
+}
diff --git a/src/quickcontrols2/universal/TabBar.qml b/src/quickcontrols2/universal/TabBar.qml
new file mode 100644
index 0000000000..9b98c10e78
--- /dev/null
+++ b/src/quickcontrols2/universal/TabBar.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.TabBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ contentItem: ListView {
+ model: control.contentModel
+ currentIndex: control.currentIndex
+
+ spacing: control.spacing
+ orientation: ListView.Horizontal
+ boundsBehavior: Flickable.StopAtBounds
+ flickableDirection: Flickable.AutoFlickIfNeeded
+ snapMode: ListView.SnapToItem
+
+ highlightMoveDuration: 100
+ highlightRangeMode: ListView.ApplyRange
+ preferredHighlightBegin: 48
+ preferredHighlightEnd: width - 48
+ }
+
+ background: Rectangle {
+ implicitWidth: 200
+ implicitHeight: 48
+ color: control.Universal.background
+ }
+}
diff --git a/src/quickcontrols2/universal/TabButton.qml b/src/quickcontrols2/universal/TabButton.qml
new file mode 100644
index 0000000000..a9e8aad47a
--- /dev/null
+++ b/src/quickcontrols2/universal/TabButton.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.TabButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 12 // PivotItemMargin
+ spacing: 8
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(control.hovered ? control.Universal.baseMediumHighColor : control.Universal.foreground,
+ control.checked || control.down || control.hovered ? 1.0 : 0.2)
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(enabled && control.hovered ? control.Universal.baseMediumHighColor : control.Universal.foreground,
+ control.checked || control.down || (enabled && control.hovered) ? 1.0 : 0.2)
+ }
+}
diff --git a/src/quickcontrols2/universal/TextArea.qml b/src/quickcontrols2/universal/TextArea.qml
new file mode 100644
index 0000000000..6fa0066b75
--- /dev/null
+++ b/src/quickcontrols2/universal/TextArea.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ // TextControlThemePadding + 2 (border)
+ padding: 12
+ topPadding: padding - 7
+ rightPadding: padding - 4
+ bottomPadding: padding - 5
+
+ Universal.theme: activeFocus ? Universal.Light : undefined
+
+ color: !enabled ? Universal.chromeDisabledLowColor : Universal.foreground
+ selectionColor: Universal.accent
+ selectedTextColor: Universal.chromeWhiteColor
+ placeholderTextColor: !enabled ? Universal.chromeDisabledLowColor :
+ activeFocus ? Universal.chromeBlackMediumLowColor :
+ Universal.baseMediumColor
+
+ 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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ verticalAlignment: control.verticalAlignment
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: Rectangle {
+ implicitWidth: 60 // TextControlThemeMinWidth - 4 (border)
+ implicitHeight: 28 // TextControlThemeMinHeight - 4 (border)
+
+ border.width: 2 // TextControlBorderThemeThickness
+ border.color: !control.enabled ? control.Universal.baseLowColor :
+ control.activeFocus ? control.Universal.accent :
+ control.hovered ? control.Universal.baseMediumColor : control.Universal.chromeDisabledLowColor
+ color: control.enabled ? control.Universal.background : control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/TextField.qml b/src/quickcontrols2/universal/TextField.qml
new file mode 100644
index 0000000000..903f672830
--- /dev/null
+++ b/src/quickcontrols2/universal/TextField.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+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)
+
+ // TextControlThemePadding + 2 (border)
+ padding: 12
+ topPadding: padding - 7
+ rightPadding: padding - 4
+ bottomPadding: padding - 5
+
+ Universal.theme: activeFocus ? Universal.Light : undefined
+
+ color: !enabled ? Universal.chromeDisabledLowColor : Universal.foreground
+ selectionColor: Universal.accent
+ selectedTextColor: Universal.chromeWhiteColor
+ placeholderTextColor: !enabled ? Universal.chromeDisabledLowColor :
+ activeFocus ? Universal.chromeBlackMediumLowColor :
+ Universal.baseMediumColor
+ verticalAlignment: TextInput.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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ verticalAlignment: control.verticalAlignment
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: Rectangle {
+ implicitWidth: 60 // TextControlThemeMinWidth - 4 (border)
+ implicitHeight: 28 // TextControlThemeMinHeight - 4 (border)
+
+ border.width: 2 // TextControlBorderThemeThickness
+ border.color: !control.enabled ? control.Universal.baseLowColor :
+ control.activeFocus ? control.Universal.accent :
+ control.hovered ? control.Universal.baseMediumColor : control.Universal.chromeDisabledLowColor
+ color: control.enabled ? control.Universal.background : control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/ToolBar.qml b/src/quickcontrols2/universal/ToolBar.qml
new file mode 100644
index 0000000000..0266056f13
--- /dev/null
+++ b/src/quickcontrols2/universal/ToolBar.qml
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ToolBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ background: Rectangle {
+ implicitHeight: 48 // AppBarThemeCompactHeight
+ color: control.Universal.chromeMediumColor
+ }
+}
diff --git a/src/quickcontrols2/universal/ToolButton.qml b/src/quickcontrols2/universal/ToolButton.qml
new file mode 100644
index 0000000000..5450ac3cdc
--- /dev/null
+++ b/src/quickcontrols2/universal/ToolButton.qml
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+T.ToolButton {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 8
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+
+ property bool useSystemFocusVisuals: true
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+
+ background: Rectangle {
+ implicitWidth: 68
+ implicitHeight: 48 // AppBarThemeCompactHeight
+
+ color: control.enabled && (control.highlighted || control.checked) ? control.Universal.accent : "transparent"
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: enabled && (control.down || control.hovered)
+ color: control.down ? control.Universal.listMediumColor : control.Universal.listLowColor
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/ToolSeparator.qml b/src/quickcontrols2/universal/ToolSeparator.qml
new file mode 100644
index 0000000000..c0be4df444
--- /dev/null
+++ b/src/quickcontrols2/universal/ToolSeparator.qml
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ToolSeparator {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ leftPadding: vertical ? 16 : 12
+ rightPadding: vertical ? 15 : 12
+ topPadding: vertical ? 12 : 16
+ bottomPadding: vertical ? 12 : 15
+
+ contentItem: Rectangle {
+ implicitWidth: control.vertical ? 1 : 20
+ implicitHeight: control.vertical ? 20 : 1
+ color: control.Universal.baseMediumLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/ToolTip.qml b/src/quickcontrols2/universal/ToolTip.qml
new file mode 100644
index 0000000000..bf931a4c84
--- /dev/null
+++ b/src/quickcontrols2/universal/ToolTip.qml
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+T.ToolTip {
+ id: control
+
+ x: parent ? (parent.width - implicitWidth) / 2 : 0
+ y: -implicitHeight - 16
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ margins: 8
+ padding: 8
+ topPadding: padding - 3
+ bottomPadding: padding - 1
+
+ closePolicy: T.Popup.CloseOnEscape | T.Popup.CloseOnPressOutsideParent | T.Popup.CloseOnReleaseOutsideParent
+
+ contentItem: Text {
+ text: control.text
+ font: control.font
+ wrapMode: Text.Wrap
+ opacity: enabled ? 1.0 : 0.2
+ color: control.Universal.foreground
+ }
+
+ background: Rectangle {
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // ToolTipBorderThemeThickness
+ }
+}
diff --git a/src/quickcontrols2/universal/Tumbler.qml b/src/quickcontrols2/universal/Tumbler.qml
new file mode 100644
index 0000000000..1d1faa6c55
--- /dev/null
+++ b/src/quickcontrols2/universal/Tumbler.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.impl
+
+T.Tumbler {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ delegate: Text {
+ text: modelData
+ font: control.font
+ color: control.Universal.foreground
+ opacity: (1.0 - Math.abs(Tumbler.displacement) / (control.visibleItemCount / 2)) * (control.enabled ? 1 : 0.6)
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ required property var modelData
+ required property int index
+ }
+
+ contentItem: TumblerView {
+ implicitWidth: 60
+ implicitHeight: 200
+ model: control.model
+ delegate: control.delegate
+ path: Path {
+ startX: control.contentItem.width / 2
+ startY: -control.contentItem.delegateHeight / 2
+ PathLine {
+ x: control.contentItem.width / 2
+ y: (control.visibleItemCount + 1) * control.contentItem.delegateHeight - control.contentItem.delegateHeight / 2
+ }
+ }
+
+ property real delegateHeight: control.availableHeight / control.visibleItemCount
+ }
+}
diff --git a/src/quickcontrols2/universal/VerticalHeaderView.qml b/src/quickcontrols2/universal/VerticalHeaderView.qml
new file mode 100644
index 0000000000..7dc1efd359
--- /dev/null
+++ b/src/quickcontrols2/universal/VerticalHeaderView.qml
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+import QtQuick.Controls.Universal.impl
+
+T.VerticalHeaderView {
+ id: control
+
+ implicitWidth: contentWidth
+ implicitHeight: syncView ? syncView.height : 0
+
+ delegate: Rectangle {
+ // Qt6: add cellPadding (and font etc) as public API in headerview
+ readonly property real cellPadding: 8
+
+ implicitWidth: Math.max(control.width, text.implicitWidth + (cellPadding * 2))
+ implicitHeight: text.implicitHeight + (cellPadding * 2)
+ color: control.Universal.background
+
+ Text {
+ id: text
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
+ width: parent.width
+ height: parent.height
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/images/checkmark.png b/src/quickcontrols2/universal/images/checkmark.png
new file mode 100644
index 0000000000..e2aae6fe0f
--- /dev/null
+++ b/src/quickcontrols2/universal/images/checkmark.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/checkmark@2x.png b/src/quickcontrols2/universal/images/checkmark@2x.png
new file mode 100644
index 0000000000..0df4159a7c
--- /dev/null
+++ b/src/quickcontrols2/universal/images/checkmark@2x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/checkmark@3x.png b/src/quickcontrols2/universal/images/checkmark@3x.png
new file mode 100644
index 0000000000..43466cbcb6
--- /dev/null
+++ b/src/quickcontrols2/universal/images/checkmark@3x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/checkmark@4x.png b/src/quickcontrols2/universal/images/checkmark@4x.png
new file mode 100644
index 0000000000..7a47bd2159
--- /dev/null
+++ b/src/quickcontrols2/universal/images/checkmark@4x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/downarrow.png b/src/quickcontrols2/universal/images/downarrow.png
new file mode 100644
index 0000000000..b66e2efc22
--- /dev/null
+++ b/src/quickcontrols2/universal/images/downarrow.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/downarrow@2x.png b/src/quickcontrols2/universal/images/downarrow@2x.png
new file mode 100644
index 0000000000..a704376c8f
--- /dev/null
+++ b/src/quickcontrols2/universal/images/downarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/downarrow@3x.png b/src/quickcontrols2/universal/images/downarrow@3x.png
new file mode 100644
index 0000000000..3b6d55ab4c
--- /dev/null
+++ b/src/quickcontrols2/universal/images/downarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/downarrow@4x.png b/src/quickcontrols2/universal/images/downarrow@4x.png
new file mode 100644
index 0000000000..818c6b24ff
--- /dev/null
+++ b/src/quickcontrols2/universal/images/downarrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/leftarrow.png b/src/quickcontrols2/universal/images/leftarrow.png
new file mode 100644
index 0000000000..0153ccd421
--- /dev/null
+++ b/src/quickcontrols2/universal/images/leftarrow.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/leftarrow@2x.png b/src/quickcontrols2/universal/images/leftarrow@2x.png
new file mode 100644
index 0000000000..fa692d5b0f
--- /dev/null
+++ b/src/quickcontrols2/universal/images/leftarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/leftarrow@3x.png b/src/quickcontrols2/universal/images/leftarrow@3x.png
new file mode 100644
index 0000000000..06b0207a60
--- /dev/null
+++ b/src/quickcontrols2/universal/images/leftarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/leftarrow@4x.png b/src/quickcontrols2/universal/images/leftarrow@4x.png
new file mode 100644
index 0000000000..1049f616e4
--- /dev/null
+++ b/src/quickcontrols2/universal/images/leftarrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/rightarrow.png b/src/quickcontrols2/universal/images/rightarrow.png
new file mode 100644
index 0000000000..b24d117d79
--- /dev/null
+++ b/src/quickcontrols2/universal/images/rightarrow.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/rightarrow@2x.png b/src/quickcontrols2/universal/images/rightarrow@2x.png
new file mode 100644
index 0000000000..80aca7c18f
--- /dev/null
+++ b/src/quickcontrols2/universal/images/rightarrow@2x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/rightarrow@3x.png b/src/quickcontrols2/universal/images/rightarrow@3x.png
new file mode 100644
index 0000000000..ba01724065
--- /dev/null
+++ b/src/quickcontrols2/universal/images/rightarrow@3x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/images/rightarrow@4x.png b/src/quickcontrols2/universal/images/rightarrow@4x.png
new file mode 100644
index 0000000000..21f7ed4d15
--- /dev/null
+++ b/src/quickcontrols2/universal/images/rightarrow@4x.png
Binary files differ
diff --git a/src/quickcontrols2/universal/impl/CMakeLists.txt b/src/quickcontrols2/universal/impl/CMakeLists.txt
new file mode 100644
index 0000000000..8a60cab817
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/CMakeLists.txt
@@ -0,0 +1,36 @@
+#####################################################################
+## qtquickcontrols2universalstyleimplplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "CheckIndicator.qml"
+ "RadioIndicator.qml"
+ "SwitchIndicator.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2universalstyleimplplugin
+ URI "QtQuick.Controls.Universal.impl"
+ VERSION "${PROJECT_VERSION}"
+ PAST_MAJOR_VERSIONS 2
+ CLASS_NAME QtQuickControls2UniversalStyleImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2universalstyleimplplugin
+ NO_PLUGIN_OPTIONAL
+ SOURCES
+ qquickuniversalbusyindicator.cpp qquickuniversalbusyindicator_p.h
+ qquickuniversalfocusrectangle.cpp qquickuniversalfocusrectangle_p.h
+ qquickuniversalprogressbar.cpp qquickuniversalprogressbar_p.h
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::Gui
+ Qt::QmlPrivate
+ Qt::QuickControls2ImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
diff --git a/src/quickcontrols2/universal/impl/CheckIndicator.qml b/src/quickcontrols2/universal/impl/CheckIndicator.qml
new file mode 100644
index 0000000000..90c0c466df
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/CheckIndicator.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+
+Rectangle {
+ id: indicator
+ implicitWidth: 20
+ implicitHeight: 20
+
+ color: !control.enabled ? "transparent" :
+ control.down && !partiallyChecked ? control.Universal.baseMediumColor :
+ control.checkState === Qt.Checked ? control.Universal.accent : "transparent"
+ border.color: !control.enabled ? control.Universal.baseLowColor :
+ control.down ? control.Universal.baseMediumColor :
+ control.checked ? control.Universal.accent : control.Universal.baseMediumHighColor
+ border.width: 2 // CheckBoxBorderThemeThickness
+
+ property Item control
+ readonly property bool partiallyChecked: control.checkState === Qt.PartiallyChecked
+
+ ColorImage {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ visible: indicator.control.checkState === Qt.Checked
+ color: !indicator.control.enabled ? indicator.control.Universal.baseLowColor : indicator.control.Universal.chromeWhiteColor
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls/Universal/images/checkmark.png"
+ }
+
+ Rectangle {
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: indicator.partiallyChecked ? parent.width / 2 : parent.width
+ height: indicator.partiallyChecked ? parent.height / 2 : parent.height
+
+ visible: !indicator.control.pressed && enabled && indicator.control.hovered || indicator.partiallyChecked
+ color: !indicator.partiallyChecked ? "transparent" :
+ !indicator.control.enabled ? indicator.control.Universal.baseLowColor :
+ indicator.control.down ? indicator.control.Universal.baseMediumColor :
+ indicator.control.hovered ? indicator.control.Universal.baseHighColor : indicator.control.Universal.baseMediumHighColor
+ border.width: indicator.partiallyChecked ? 0 : 2 // CheckBoxBorderThemeThickness
+ border.color: indicator.control.Universal.baseMediumLowColor
+ }
+}
diff --git a/src/quickcontrols2/universal/impl/RadioIndicator.qml b/src/quickcontrols2/universal/impl/RadioIndicator.qml
new file mode 100644
index 0000000000..3cf1bf3728
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/RadioIndicator.qml
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.Universal
+
+Rectangle {
+ id: indicator
+ implicitWidth: 20
+ implicitHeight: 20
+ radius: width / 2
+ color: "transparent"
+ border.width: 2 // RadioButtonBorderThemeThickness
+ border.color: control.checked ? "transparent" :
+ !control.enabled ? control.Universal.baseLowColor :
+ control.down ? control.Universal.baseMediumColor :
+ control.hovered ? control.Universal.baseHighColor : control.Universal.baseMediumHighColor
+
+ property var control
+
+ Rectangle {
+ id: checkOuterEllipse
+ width: parent.width
+ height: parent.height
+
+ radius: width / 2
+ opacity: indicator.control.checked ? 1 : 0
+ color: "transparent"
+ border.width: 2 // RadioButtonBorderThemeThickness
+ border.color: !indicator.control.enabled ? indicator.control.Universal.baseLowColor :
+ indicator.control.down ? indicator.control.Universal.baseMediumColor : indicator.control.Universal.accent
+ }
+
+ Rectangle {
+ id: checkGlyph
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+ width: parent.width / 2
+ height: parent.height / 2
+
+ radius: width / 2
+ opacity: indicator.control.checked ? 1 : 0
+ color: !indicator.control.enabled ? indicator.control.Universal.baseLowColor :
+ indicator.control.down ? indicator.control.Universal.baseMediumColor :
+ indicator.control.hovered ? indicator.control.Universal.baseHighColor : indicator.control.Universal.baseMediumHighColor
+ }
+}
diff --git a/src/quickcontrols2/universal/impl/SwitchIndicator.qml b/src/quickcontrols2/universal/impl/SwitchIndicator.qml
new file mode 100644
index 0000000000..7a75838674
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/SwitchIndicator.qml
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Universal
+
+Item {
+ id: indicator
+ implicitWidth: 44
+ implicitHeight: 20
+
+ property T.AbstractButton control
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+
+ radius: 10
+ color: !indicator.control.enabled ? "transparent" :
+ indicator.control.pressed ? indicator.control.Universal.baseMediumColor :
+ indicator.control.checked ? indicator.control.Universal.accent : "transparent"
+ border.color: !indicator.control.enabled ? indicator.control.Universal.baseLowColor :
+ indicator.control.checked && !indicator.control.pressed ? indicator.control.Universal.accent :
+ indicator.control.hovered && !indicator.control.checked && !indicator.control.pressed ? indicator.control.Universal.baseHighColor : indicator.control.Universal.baseMediumColor
+ opacity: enabled && indicator.control.hovered && indicator.control.checked && !indicator.control.pressed ? (indicator.control.Universal.theme === Universal.Light ? 0.7 : 0.9) : 1.0
+ border.width: 2
+ }
+
+ Rectangle {
+ width: 10
+ height: 10
+ radius: 5
+
+ color: !indicator.control.enabled ? indicator.control.Universal.baseLowColor :
+ indicator.control.pressed || indicator.control.checked ? indicator.control.Universal.chromeWhiteColor :
+ indicator.control.hovered && !indicator.control.checked ? indicator.control.Universal.baseHighColor : indicator.control.Universal.baseMediumHighColor
+
+ x: Math.max(5, Math.min(parent.width - width - 5,
+ indicator.control.visualPosition * parent.width - (width / 2)))
+ y: (parent.height - height) / 2
+
+ Behavior on x {
+ enabled: !indicator.control.pressed
+ SmoothedAnimation { velocity: 200 }
+ }
+ }
+}
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator.cpp b/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator.cpp
new file mode 100644
index 0000000000..b624d41e61
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversalbusyindicator_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int PhaseCount = 6;
+static const int Interval = 167;
+static const int TotalDuration = 4052;
+
+class QQuickUniversalBusyIndicatorNode : public QQuickAnimatedNode
+{
+public:
+ QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ struct Phase {
+ Phase() = default;
+ Phase(int d, qreal f, qreal t, QEasingCurve::Type c) : duration(d), from(f), to(t), curve(c) { }
+ int duration = 0;
+ qreal from = 0;
+ qreal to = 0;
+ QEasingCurve curve = QEasingCurve::Linear;
+ };
+
+ Phase m_phases[PhaseCount];
+};
+
+QQuickUniversalBusyIndicatorNode::QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item)
+ : QQuickAnimatedNode(item)
+{
+ setLoopCount(Infinite);
+ setDuration(TotalDuration);
+ setCurrentTime(item->elapsed());
+
+ m_phases[0] = Phase(433, -110, 10, QEasingCurve::BezierSpline);
+ m_phases[1] = Phase(767, 10, 93, QEasingCurve::Linear );
+ m_phases[2] = Phase(417, 93, 205, QEasingCurve::BezierSpline);
+ m_phases[3] = Phase(400, 205, 357, QEasingCurve::BezierSpline);
+ m_phases[4] = Phase(766, 357, 439, QEasingCurve::Linear );
+ m_phases[5] = Phase(434, 439, 585, QEasingCurve::BezierSpline);
+
+ m_phases[0].curve.addCubicBezierSegment(QPointF(0.02, 0.33), QPointF(0.38, 0.77), QPointF(1.00, 1.00));
+ m_phases[2].curve.addCubicBezierSegment(QPointF(0.57, 0.17), QPointF(0.95, 0.75), QPointF(1.00, 1.00));
+ m_phases[3].curve.addCubicBezierSegment(QPointF(0.00, 0.19), QPointF(0.07, 0.72), QPointF(1.00, 1.00));
+ m_phases[5].curve.addCubicBezierSegment(QPointF(0.00, 0.00), QPointF(0.95, 0.37), QPointF(1.00, 1.00));
+}
+
+void QQuickUniversalBusyIndicatorNode::updateCurrentTime(int time)
+{
+ int nodeIndex = 0;
+ int count = childCount();
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(firstChild());
+ while (transformNode) {
+ Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType);
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(transformNode->firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ int begin = nodeIndex * Interval;
+ int end = TotalDuration - (PhaseCount - nodeIndex - 1) * Interval;
+
+ bool visible = time >= begin && time <= end;
+ opacityNode->setOpacity(visible ? 1.0 : 0.0);
+
+ if (visible) {
+ int phaseIndex, remain = time, elapsed = 0;
+ for (phaseIndex = 0; phaseIndex < PhaseCount - 1; ++phaseIndex) {
+ if (remain <= m_phases[phaseIndex].duration + begin)
+ break;
+ remain -= m_phases[phaseIndex].duration;
+ elapsed += m_phases[phaseIndex].duration;
+ }
+
+ const Phase &phase = m_phases[phaseIndex];
+
+ qreal from = phase.from - nodeIndex * count;
+ qreal to = phase.to - nodeIndex * count;
+ qreal pos = time - elapsed - begin;
+
+ qreal value = phase.curve.valueForProgress(pos / phase.duration);
+ qreal rotation = from + (to - from) * value;
+
+ QMatrix4x4 matrix;
+ matrix.rotate(rotation, 0, 0, 1);
+ transformNode->setMatrix(matrix);
+ }
+
+ transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling());
+ ++nodeIndex;
+ }
+}
+
+void QQuickUniversalBusyIndicatorNode::sync(QQuickItem *item)
+{
+ QQuickUniversalBusyIndicator *indicator = static_cast<QQuickUniversalBusyIndicator *>(item);
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+
+ QMatrix4x4 matrix;
+ matrix.translate(item->width() / 2, item->height() / 2);
+ setMatrix(matrix);
+
+ qreal size = qMin(item->width(), item->height());
+ qreal diameter = size / 10.0;
+ qreal radius = diameter / 2;
+ qreal offset = (size - diameter * 2) / M_PI;
+ const QRectF rect(offset, offset, diameter, diameter);
+
+ int count = indicator->count();
+ QSGNode *transformNode = firstChild();
+ for (int i = 0; i < count; ++i) {
+ if (!transformNode) {
+ transformNode = new QSGTransformNode;
+ appendChildNode(transformNode);
+
+ QSGOpacityNode *opacityNode = new QSGOpacityNode;
+ transformNode->appendChildNode(opacityNode);
+
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ opacityNode->appendChildNode(rectNode);
+ }
+
+ QSGNode *opacityNode = transformNode->firstChild();
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ rectNode->setRect(rect);
+ rectNode->setColor(indicator->color());
+ rectNode->setRadius(radius);
+ rectNode->update();
+
+ transformNode = transformNode->nextSibling();
+ }
+
+ while (transformNode) {
+ QSGNode *nextSibling = transformNode->nextSibling();
+ delete transformNode;
+ transformNode = nextSibling;
+ }
+}
+
+QQuickUniversalBusyIndicator::QQuickUniversalBusyIndicator(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+int QQuickUniversalBusyIndicator::count() const
+{
+ return m_count;
+}
+
+void QQuickUniversalBusyIndicator::setCount(int count)
+{
+ if (m_count == count)
+ return;
+
+ m_count = count;
+ update();
+}
+
+QColor QQuickUniversalBusyIndicator::color() const
+{
+ return m_color;
+}
+
+void QQuickUniversalBusyIndicator::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+int QQuickUniversalBusyIndicator::elapsed() const
+{
+ return m_elapsed;
+}
+
+void QQuickUniversalBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ if (change == ItemVisibleHasChanged)
+ update();
+}
+
+QSGNode *QQuickUniversalBusyIndicator::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
+{
+ QQuickUniversalBusyIndicatorNode *node = static_cast<QQuickUniversalBusyIndicatorNode *>(oldNode);
+ if (isVisible() && width() > 0 && height() > 0) {
+ if (!node) {
+ node = new QQuickUniversalBusyIndicatorNode(this);
+ node->start();
+ }
+ node->sync(this);
+ } else {
+ m_elapsed = node ? node->currentTime() : 0;
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickuniversalbusyindicator_p.cpp"
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator_p.h b/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator_p.h
new file mode 100644
index 0000000000..6d3ebb8493
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalbusyindicator_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKUNIVERSALBUSYINDICATOR_P_H
+#define QQUICKUNIVERSALBUSYINDICATOR_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/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickUniversalBusyIndicator : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count WRITE setCount FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ QML_NAMED_ELEMENT(BusyIndicatorImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickUniversalBusyIndicator(QQuickItem *parent = nullptr);
+
+ int count() const;
+ void setCount(int count);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ int elapsed() const;
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ int m_count = 5;
+ int m_elapsed = 0;
+ QColor m_color = Qt::black;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickUniversalBusyIndicator)
+
+#endif // QQUICKUNIVERSALBUSYINDICATOR_P_H
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle.cpp b/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle.cpp
new file mode 100644
index 0000000000..3f4d8251ab
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversalfocusrectangle_p.h"
+
+#include <QtGui/qpixmap.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickUniversalFocusRectangle::QQuickUniversalFocusRectangle(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+ QQuickItemPrivate::get(this)->setTransparentForPositioner(true);
+}
+
+void QQuickUniversalFocusRectangle::paint(QPainter *painter)
+{
+ if (!isVisible() || width() <= 0 || height() <= 0)
+ return;
+
+ QRect bounds = boundingRect().toAlignedRect();
+ const int boundsWidth = bounds.width();
+ const int boundsHeight = bounds.width();
+ const QString key = QStringLiteral("qquickuniversalfocusrectangle_%1_%2").arg(QString::number(boundsWidth), QString::number(boundsHeight));
+
+ QPixmap pixmap(boundsWidth, boundsHeight);
+ if (!QPixmapCache::find(key, &pixmap)) {
+ bounds.adjust(0, 0, -1, -1);
+ pixmap.fill(Qt::transparent);
+ QPainter p(&pixmap);
+
+ QPen pen;
+ pen.setWidth(1);
+ pen.setColor(Qt::white);
+ p.setPen(pen);
+ p.drawRect(bounds);
+
+ pen.setColor(Qt::black);
+ pen.setDashPattern(QList<qreal>(2, 1));
+ p.setPen(pen);
+ p.drawRect(bounds);
+
+ QPixmapCache::insert(key, pixmap);
+ }
+ painter->drawPixmap(0, 0, pixmap);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickuniversalfocusrectangle_p.cpp"
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle_p.h b/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle_p.h
new file mode 100644
index 0000000000..f309b51227
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalfocusrectangle_p.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKUNIVERSALFOCUSRECTANGLE_P_H
+#define QQUICKUNIVERSALFOCUSRECTANGLE_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/qquickpainteditem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickUniversalFocusRectangle : public QQuickPaintedItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(FocusRectangle)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ QQuickUniversalFocusRectangle(QQuickItem *parent = nullptr);
+
+ void paint(QPainter *painter) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKUNIVERSALFOCUSRECTANGLE_P_H
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalprogressbar.cpp b/src/quickcontrols2/universal/impl/qquickuniversalprogressbar.cpp
new file mode 100644
index 0000000000..ab7e6c129b
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalprogressbar.cpp
@@ -0,0 +1,340 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversalprogressbar_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qeasingcurve.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+#include <QtQuick/qsgrectanglenode.h>
+#include <QtQuickControls2Impl/private/qquickanimatednode_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int PhaseCount = 4;
+static const int EllipseCount = 5;
+static const int Interval = 167;
+static const int TotalDuration = 3917;
+static const int VisibleDuration = 3000;
+static const qreal EllipseDiameter = 4;
+static const qreal EllipseOffset = 4;
+static const qreal ContainerAnimationStartPosition = -34; // absolute
+static const qreal ContainerAnimationEndPosition = 0.435222; // relative
+static const qreal EllipseAnimationWellPosition = 0.333333333333333; // relative
+static const qreal EllipseAnimationEndPosition = 0.666666666666667; // relative
+
+class QQuickUniversalProgressBarNode : public QQuickAnimatedNode
+{
+public:
+ QQuickUniversalProgressBarNode(QQuickUniversalProgressBar *item);
+
+ void updateCurrentTime(int time) override;
+ void sync(QQuickItem *item) override;
+
+private:
+ struct Phase {
+ Phase() = default;
+ Phase(int d, qreal f, qreal t) : duration(d), from(f), to(t) { }
+ int duration = 0;
+ qreal from = 0;
+ qreal to = 0;
+ };
+
+ bool m_indeterminate = false;
+ Phase m_borderPhases[PhaseCount];
+ Phase m_ellipsePhases[PhaseCount];
+};
+
+QQuickUniversalProgressBarNode::QQuickUniversalProgressBarNode(QQuickUniversalProgressBar *item)
+ : QQuickAnimatedNode(item)
+{
+ setLoopCount(Infinite);
+ setDuration(TotalDuration);
+
+ m_borderPhases[0] = Phase( 500, -50, 0);
+ m_borderPhases[1] = Phase(1500, 0, 0);
+ m_borderPhases[2] = Phase(1000, 0, 100);
+ m_borderPhases[3] = Phase( 917, 100, 100);
+
+ m_ellipsePhases[0] = Phase(1000, 0, EllipseAnimationWellPosition);
+ m_ellipsePhases[1] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationWellPosition);
+ m_ellipsePhases[2] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationEndPosition);
+ m_ellipsePhases[3] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationEndPosition);
+}
+
+void QQuickUniversalProgressBarNode::updateCurrentTime(int time)
+{
+ QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
+ Q_ASSERT(!geometryNode || geometryNode->type() == QSGNode::GeometryNodeType);
+ if (!geometryNode)
+ return;
+
+ QSGTransformNode *gridNode = static_cast<QSGTransformNode *>(geometryNode->firstChild());
+ Q_ASSERT(!gridNode || gridNode->type() == QSGNode::TransformNodeType);
+ if (!gridNode)
+ return;
+
+ qreal width = geometryNode->rect().width();
+ {
+ qreal from = ContainerAnimationStartPosition;
+ qreal to = from + ContainerAnimationEndPosition * width;
+ qreal progress = static_cast<qreal>(time) / TotalDuration;
+ qreal dx = from + (to - from) * progress;
+
+ QMatrix4x4 matrix;
+ matrix.translate(dx, 0);
+ gridNode->setMatrix(matrix);
+ }
+
+ int nodeIndex = 0;
+ QSGTransformNode *borderNode = static_cast<QSGTransformNode *>(gridNode->firstChild());
+ while (borderNode) {
+ Q_ASSERT(borderNode->type() == QSGNode::TransformNodeType);
+
+ QSGTransformNode *ellipseNode = static_cast<QSGTransformNode *>(borderNode->firstChild());
+ Q_ASSERT(ellipseNode->type() == QSGNode::TransformNodeType);
+
+ QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode *>(ellipseNode->firstChild());
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ int begin = nodeIndex * Interval;
+ int end = VisibleDuration + nodeIndex * Interval;
+
+ bool visible = time >= begin && time <= end;
+ opacityNode->setOpacity(visible ? 1.0 : 0.0);
+
+ if (visible) {
+ {
+ int phaseIndex, remain = time, elapsed = 0;
+ for (phaseIndex = 0; phaseIndex < PhaseCount - 1; ++phaseIndex) {
+ if (remain <= m_borderPhases[phaseIndex].duration + begin)
+ break;
+ remain -= m_borderPhases[phaseIndex].duration;
+ elapsed += m_borderPhases[phaseIndex].duration;
+ }
+
+ const Phase &phase = m_borderPhases[phaseIndex];
+
+ qreal pos = time - elapsed - begin;
+ qreal progress = pos / phase.duration;
+ qreal dx = phase.from + (phase.to - phase.from) * progress;
+
+ QMatrix4x4 matrix;
+ matrix.translate(dx, 0);
+ borderNode->setMatrix(matrix);
+ }
+
+ {
+ QEasingCurve curve(QEasingCurve::BezierSpline);
+ curve.addCubicBezierSegment(QPointF(0.4, 0.0), QPointF(0.6, 1.0), QPointF(1.0, 1.0));
+
+ int phaseIndex, remain = time, elapsed = 0;
+ for (phaseIndex = 0; phaseIndex < PhaseCount - 1; ++phaseIndex) {
+ if (remain <= m_ellipsePhases[phaseIndex].duration + begin)
+ break;
+ remain -= m_ellipsePhases[phaseIndex].duration;
+ elapsed += m_ellipsePhases[phaseIndex].duration;
+ }
+
+ const Phase &phase = m_ellipsePhases[phaseIndex];
+
+ qreal from = phase.from * width;
+ qreal to = phase.to * width;
+ qreal pos = time - elapsed - begin;
+ qreal progress = curve.valueForProgress(pos / phase.duration);
+ qreal dx = from + (to - from) * progress;
+
+ QMatrix4x4 matrix;
+ matrix.translate(dx, 0);
+ ellipseNode->setMatrix(matrix);
+ }
+ }
+
+ borderNode = static_cast<QSGTransformNode *>(borderNode->nextSibling());
+ ++nodeIndex;
+ }
+}
+
+void QQuickUniversalProgressBarNode::sync(QQuickItem *item)
+{
+ QQuickUniversalProgressBar *bar = static_cast<QQuickUniversalProgressBar *>(item);
+ if (m_indeterminate != bar->isIndeterminate()) {
+ m_indeterminate = bar->isIndeterminate();
+ if (m_indeterminate)
+ start();
+ else
+ stop();
+ }
+
+ QQuickItemPrivate *d = QQuickItemPrivate::get(item);
+
+ QRectF bounds = item->boundingRect();
+ bounds.setHeight(item->implicitHeight());
+ bounds.moveTop((item->height() - bounds.height()) / 2.0);
+ if (!m_indeterminate)
+ bounds.setWidth(bar->progress() * bounds.width());
+
+ QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild());
+ if (!geometryNode) {
+ geometryNode = item->window()->createRectangleNode();
+ appendChildNode(geometryNode);
+ }
+ geometryNode->setRect(bounds);
+ geometryNode->setColor(m_indeterminate ? Qt::transparent : bar->color());
+
+ if (!m_indeterminate) {
+ while (QSGNode *node = geometryNode->firstChild())
+ delete node;
+ return;
+ }
+
+ QSGTransformNode *gridNode = static_cast<QSGTransformNode *>(geometryNode->firstChild());
+ if (!gridNode) {
+ gridNode = new QSGTransformNode;
+ geometryNode->appendChildNode(gridNode);
+ }
+ Q_ASSERT(gridNode->type() == QSGNode::TransformNodeType);
+
+ QSGNode *borderNode = gridNode->firstChild();
+ for (int i = 0; i < EllipseCount; ++i) {
+ if (!borderNode) {
+ borderNode = new QSGTransformNode;
+ gridNode->appendChildNode(borderNode);
+
+ QSGTransformNode *ellipseNode = new QSGTransformNode;
+ borderNode->appendChildNode(ellipseNode);
+
+ QSGOpacityNode *opacityNode = new QSGOpacityNode;
+ ellipseNode->appendChildNode(opacityNode);
+
+ QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode();
+ rectNode->setAntialiasing(true);
+ rectNode->setRadius(EllipseDiameter / 2);
+ opacityNode->appendChildNode(rectNode);
+ }
+ Q_ASSERT(borderNode->type() == QSGNode::TransformNodeType);
+
+ QSGNode *ellipseNode = borderNode->firstChild();
+ Q_ASSERT(ellipseNode->type() == QSGNode::TransformNodeType);
+
+ QSGNode *opacityNode = ellipseNode->firstChild();
+ Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType);
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild());
+ Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType);
+
+ rectNode->setRect(QRectF((EllipseCount - i - 1) * (EllipseDiameter + EllipseOffset), (item->height() - EllipseDiameter) / 2, EllipseDiameter, EllipseDiameter));
+ rectNode->setColor(bar->color());
+ rectNode->update();
+
+ borderNode = borderNode->nextSibling();
+ }
+}
+
+QQuickUniversalProgressBar::QQuickUniversalProgressBar(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(ItemHasContents);
+}
+
+QColor QQuickUniversalProgressBar::color() const
+{
+ return m_color;
+}
+
+void QQuickUniversalProgressBar::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ update();
+}
+
+qreal QQuickUniversalProgressBar::progress() const
+{
+ return m_progress;
+}
+
+void QQuickUniversalProgressBar::setProgress(qreal progress)
+{
+ if (progress == m_progress)
+ return;
+
+ m_progress = progress;
+ update();
+}
+
+bool QQuickUniversalProgressBar::isIndeterminate() const
+{
+ return m_indeterminate;
+}
+
+void QQuickUniversalProgressBar::setIndeterminate(bool indeterminate)
+{
+ if (indeterminate == m_indeterminate)
+ return;
+
+ m_indeterminate = indeterminate;
+ setClip(m_indeterminate);
+ update();
+}
+
+void QQuickUniversalProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+ if (change == ItemVisibleHasChanged)
+ update();
+}
+
+QSGNode *QQuickUniversalProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QQuickUniversalProgressBarNode *node = static_cast<QQuickUniversalProgressBarNode *>(oldNode);
+ if (isVisible() && width() > 0 && height() > 0) {
+ if (!node)
+ node = new QQuickUniversalProgressBarNode(this);
+ node->sync(this);
+ } else {
+ delete node;
+ node = nullptr;
+ }
+ return node;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickuniversalprogressbar_p.cpp"
diff --git a/src/quickcontrols2/universal/impl/qquickuniversalprogressbar_p.h b/src/quickcontrols2/universal/impl/qquickuniversalprogressbar_p.h
new file mode 100644
index 0000000000..31cb4a322e
--- /dev/null
+++ b/src/quickcontrols2/universal/impl/qquickuniversalprogressbar_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKUNIVERSALPROGRESSBAR_P_H
+#define QQUICKUNIVERSALPROGRESSBAR_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/qquickitem.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickUniversalProgressBar : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress FINAL)
+ Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate FINAL)
+ QML_NAMED_ELEMENT(ProgressBarImpl)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickUniversalProgressBar(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ bool isIndeterminate() const;
+ void setIndeterminate(bool indeterminate);
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override;
+
+private:
+ QColor m_color = Qt::black;
+ qreal m_progress = 0.0;
+ bool m_indeterminate = false;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickUniversalProgressBar)
+
+#endif // QQUICKUNIVERSALPROGRESSBAR_P_H
diff --git a/src/quickcontrols2/universal/qquickuniversalstyle.cpp b/src/quickcontrols2/universal/qquickuniversalstyle.cpp
new file mode 100644
index 0000000000..3965b4618e
--- /dev/null
+++ b/src/quickcontrols2/universal/qquickuniversalstyle.cpp
@@ -0,0 +1,620 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversalstyle_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qsettings.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QRgb qquickuniversal_light_color(QQuickUniversalStyle::SystemColor role)
+{
+ static const QRgb colors[] = {
+ 0xFFFFFFFF, // SystemAltHighColor
+ 0x33FFFFFF, // SystemAltLowColor
+ 0x99FFFFFF, // SystemAltMediumColor
+ 0xCCFFFFFF, // SystemAltMediumHighColor
+ 0x66FFFFFF, // SystemAltMediumLowColor
+ 0xFF000000, // SystemBaseHighColor
+ 0x33000000, // SystemBaseLowColor
+ 0x99000000, // SystemBaseMediumColor
+ 0xCC000000, // SystemBaseMediumHighColor
+ 0x66000000, // SystemBaseMediumLowColor
+ 0xFF171717, // SystemChromeAltLowColor
+ 0xFF000000, // SystemChromeBlackHighColor
+ 0x33000000, // SystemChromeBlackLowColor
+ 0x66000000, // SystemChromeBlackMediumLowColor
+ 0xCC000000, // SystemChromeBlackMediumColor
+ 0xFFCCCCCC, // SystemChromeDisabledHighColor
+ 0xFF7A7A7A, // SystemChromeDisabledLowColor
+ 0xFFCCCCCC, // SystemChromeHighColor
+ 0xFFF2F2F2, // SystemChromeLowColor
+ 0xFFE6E6E6, // SystemChromeMediumColor
+ 0xFFF2F2F2, // SystemChromeMediumLowColor
+ 0xFFFFFFFF, // SystemChromeWhiteColor
+ 0x19000000, // SystemListLowColor
+ 0x33000000 // SystemListMediumColor
+ };
+ return colors[role];
+}
+
+static QRgb qquickuniversal_dark_color(QQuickUniversalStyle::SystemColor role)
+{
+ static const QRgb colors[] = {
+ 0xFF000000, // SystemAltHighColor
+ 0x33000000, // SystemAltLowColor
+ 0x99000000, // SystemAltMediumColor
+ 0xCC000000, // SystemAltMediumHighColor
+ 0x66000000, // SystemAltMediumLowColor
+ 0xFFFFFFFF, // SystemBaseHighColor
+ 0x33FFFFFF, // SystemBaseLowColor
+ 0x99FFFFFF, // SystemBaseMediumColor
+ 0xCCFFFFFF, // SystemBaseMediumHighColor
+ 0x66FFFFFF, // SystemBaseMediumLowColor
+ 0xFFF2F2F2, // SystemChromeAltLowColor
+ 0xFF000000, // SystemChromeBlackHighColor
+ 0x33000000, // SystemChromeBlackLowColor
+ 0x66000000, // SystemChromeBlackMediumLowColor
+ 0xCC000000, // SystemChromeBlackMediumColor
+ 0xFF333333, // SystemChromeDisabledHighColor
+ 0xFF858585, // SystemChromeDisabledLowColor
+ 0xFF767676, // SystemChromeHighColor
+ 0xFF171717, // SystemChromeLowColor
+ 0xFF1F1F1F, // SystemChromeMediumColor
+ 0xFF2B2B2B, // SystemChromeMediumLowColor
+ 0xFFFFFFFF, // SystemChromeWhiteColor
+ 0x19FFFFFF, // SystemListLowColor
+ 0x33FFFFFF // SystemListMediumColor
+ };
+ return colors[role];
+}
+
+static QRgb qquickuniversal_accent_color(QQuickUniversalStyle::Color accent)
+{
+ static const QRgb colors[] = {
+ 0xFFA4C400, // Lime
+ 0xFF60A917, // Green
+ 0xFF008A00, // Emerald
+ 0xFF00ABA9, // Teal
+ 0xFF1BA1E2, // Cyan
+ 0xFF3E65FF, // Cobalt
+ 0xFF6A00FF, // Indigo
+ 0xFFAA00FF, // Violet
+ 0xFFF472D0, // Pink
+ 0xFFD80073, // Magenta
+ 0xFFA20025, // Crimson
+ 0xFFE51400, // Red
+ 0xFFFA6800, // Orange
+ 0xFFF0A30A, // Amber
+ 0xFFE3C800, // Yellow
+ 0xFF825A2C, // Brown
+ 0xFF6D8764, // Olive
+ 0xFF647687, // Steel
+ 0xFF76608A, // Mauve
+ 0xFF87794E // Taupe
+ };
+ return colors[accent];
+}
+
+static QQuickUniversalStyle::Theme qquickuniversal_effective_theme(QQuickUniversalStyle::Theme theme)
+{
+ if (theme == QQuickUniversalStyle::System)
+ theme = QQuickStylePrivate::isDarkSystemTheme() ? QQuickUniversalStyle::Dark : QQuickUniversalStyle::Light;
+ return theme;
+}
+
+// If no value was inherited from a parent or explicitly set, the "global" values are used.
+// The initial, default values of the globals are hard-coded here, but the environment
+// variables and .conf file override them if specified.
+static QQuickUniversalStyle::Theme GlobalTheme = QQuickUniversalStyle::Light;
+static QRgb GlobalAccent = qquickuniversal_accent_color(QQuickUniversalStyle::Cobalt);
+static QRgb GlobalForeground = qquickuniversal_light_color(QQuickUniversalStyle::BaseHigh);
+static QRgb GlobalBackground = qquickuniversal_light_color(QQuickUniversalStyle::AltHigh);
+// These represent whether a global foreground/background was set.
+// Each style's m_hasForeground/m_hasBackground are initialized to these values.
+static bool HasGlobalForeground = false;
+static bool HasGlobalBackground = false;
+
+QQuickUniversalStyle::QQuickUniversalStyle(QObject *parent) : QQuickAttachedObject(parent),
+ m_hasForeground(HasGlobalForeground), m_hasBackground(HasGlobalBackground), m_theme(GlobalTheme),
+ m_accent(GlobalAccent), m_foreground(GlobalForeground), m_background(GlobalBackground)
+{
+ init();
+}
+
+QQuickUniversalStyle *QQuickUniversalStyle::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickUniversalStyle(object);
+}
+
+QQuickUniversalStyle::Theme QQuickUniversalStyle::theme() const
+{
+ return m_theme;
+}
+
+void QQuickUniversalStyle::setTheme(Theme theme)
+{
+ theme = qquickuniversal_effective_theme(theme);
+ m_explicitTheme = true;
+ if (m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ emit themeChanged();
+ emit paletteChanged();
+ emit foregroundChanged();
+ emit backgroundChanged();
+}
+
+void QQuickUniversalStyle::inheritTheme(Theme theme)
+{
+ if (m_explicitTheme || m_theme == theme)
+ return;
+
+ m_theme = theme;
+ propagateTheme();
+ emit themeChanged();
+ emit paletteChanged();
+ emit foregroundChanged();
+ emit backgroundChanged();
+}
+
+void QQuickUniversalStyle::propagateTheme()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
+ if (universal)
+ universal->inheritTheme(m_theme);
+ }
+}
+
+void QQuickUniversalStyle::resetTheme()
+{
+ if (!m_explicitTheme)
+ return;
+
+ m_explicitTheme = false;
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
+ inheritTheme(universal ? universal->theme() : GlobalTheme);
+}
+
+QVariant QQuickUniversalStyle::accent() const
+{
+ return QColor::fromRgba(m_accent);
+}
+
+void QQuickUniversalStyle::setAccent(const QVariant &var)
+{
+ QRgb accent = 0;
+ if (!variantToRgba(var, "accent", &accent))
+ return;
+
+ m_explicitAccent = true;
+ if (m_accent == accent)
+ return;
+
+ m_accent = accent;
+ propagateAccent();
+ emit accentChanged();
+}
+
+void QQuickUniversalStyle::inheritAccent(QRgb accent)
+{
+ if (m_explicitAccent || m_accent == accent)
+ return;
+
+ m_accent = accent;
+ propagateAccent();
+ emit accentChanged();
+}
+
+void QQuickUniversalStyle::propagateAccent()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
+ if (universal)
+ universal->inheritAccent(m_accent);
+ }
+}
+
+void QQuickUniversalStyle::resetAccent()
+{
+ if (!m_explicitAccent)
+ return;
+
+ m_explicitAccent = false;
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
+ inheritAccent(universal ? universal->m_accent : GlobalAccent);
+}
+
+QVariant QQuickUniversalStyle::foreground() const
+{
+ if (m_hasForeground)
+ return QColor::fromRgba(m_foreground);
+ return baseHighColor();
+}
+
+void QQuickUniversalStyle::setForeground(const QVariant &var)
+{
+ QRgb foreground = 0;
+ if (!variantToRgba(var, "foreground", &foreground))
+ return;
+
+ m_hasForeground = true;
+ m_explicitForeground = true;
+ if (m_foreground == foreground)
+ return;
+
+ m_foreground = foreground;
+ propagateForeground();
+ emit foregroundChanged();
+}
+
+void QQuickUniversalStyle::inheritForeground(QRgb foreground, bool has)
+{
+ if (m_explicitForeground || m_foreground == foreground)
+ return;
+
+ m_hasForeground = has;
+ m_foreground = foreground;
+ propagateForeground();
+ emit foregroundChanged();
+}
+
+void QQuickUniversalStyle::propagateForeground()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
+ if (universal)
+ universal->inheritForeground(m_foreground, m_hasForeground);
+ }
+}
+
+void QQuickUniversalStyle::resetForeground()
+{
+ if (!m_explicitForeground)
+ return;
+
+ m_hasForeground = false;
+ m_explicitForeground = false;
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
+ inheritForeground(universal ? universal->m_foreground : GlobalForeground, universal ? universal->m_hasForeground : false);
+}
+
+QVariant QQuickUniversalStyle::background() const
+{
+ if (m_hasBackground)
+ return QColor::fromRgba(m_background);
+ return altHighColor();
+}
+
+void QQuickUniversalStyle::setBackground(const QVariant &var)
+{
+ QRgb background = 0;
+ if (!variantToRgba(var, "background", &background))
+ return;
+
+ m_hasBackground = true;
+ m_explicitBackground = true;
+ if (m_background == background)
+ return;
+
+ m_background = background;
+ propagateBackground();
+ emit backgroundChanged();
+}
+
+void QQuickUniversalStyle::inheritBackground(QRgb background, bool has)
+{
+ if (m_explicitBackground || m_background == background)
+ return;
+
+ m_hasBackground = has;
+ m_background = background;
+ propagateBackground();
+ emit backgroundChanged();
+}
+
+void QQuickUniversalStyle::propagateBackground()
+{
+ const auto styles = attachedChildren();
+ for (QQuickAttachedObject *child : styles) {
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(child);
+ if (universal)
+ universal->inheritBackground(m_background, m_hasBackground);
+ }
+}
+
+void QQuickUniversalStyle::resetBackground()
+{
+ if (!m_explicitBackground)
+ return;
+
+ m_hasBackground = false;
+ m_explicitBackground = false;
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(attachedParent());
+ inheritBackground(universal ? universal->m_background : GlobalBackground, universal ? universal->m_hasBackground : false);
+}
+
+QColor QQuickUniversalStyle::color(Color color) const
+{
+ return qquickuniversal_accent_color(color);
+}
+
+QColor QQuickUniversalStyle::altHighColor() const
+{
+ return systemColor(AltHigh);
+}
+
+QColor QQuickUniversalStyle::altLowColor() const
+{
+ return systemColor(AltLow);
+}
+
+QColor QQuickUniversalStyle::altMediumColor() const
+{
+ return systemColor(AltMedium);
+}
+
+QColor QQuickUniversalStyle::altMediumHighColor() const
+{
+ return systemColor(AltMediumHigh);
+}
+
+QColor QQuickUniversalStyle::altMediumLowColor() const
+{
+ return systemColor(AltMediumLow);
+}
+
+QColor QQuickUniversalStyle::baseHighColor() const
+{
+ return systemColor(BaseHigh);
+}
+
+QColor QQuickUniversalStyle::baseLowColor() const
+{
+ return systemColor(BaseLow);
+}
+
+QColor QQuickUniversalStyle::baseMediumColor() const
+{
+ return systemColor(BaseMedium);
+}
+
+QColor QQuickUniversalStyle::baseMediumHighColor() const
+{
+ return systemColor(BaseMediumHigh);
+}
+
+QColor QQuickUniversalStyle::baseMediumLowColor() const
+{
+ return systemColor(BaseMediumLow);
+}
+
+QColor QQuickUniversalStyle::chromeAltLowColor() const
+{
+ return systemColor(ChromeAltLow);
+}
+
+QColor QQuickUniversalStyle::chromeBlackHighColor() const
+{
+ return systemColor(ChromeBlackHigh);
+}
+
+QColor QQuickUniversalStyle::chromeBlackLowColor() const
+{
+ return systemColor(ChromeBlackLow);
+}
+
+QColor QQuickUniversalStyle::chromeBlackMediumLowColor() const
+{
+ return systemColor(ChromeBlackMediumLow);
+}
+
+QColor QQuickUniversalStyle::chromeBlackMediumColor() const
+{
+ return systemColor(ChromeBlackMedium);
+}
+
+QColor QQuickUniversalStyle::chromeDisabledHighColor() const
+{
+ return systemColor(ChromeDisabledHigh);
+}
+
+QColor QQuickUniversalStyle::chromeDisabledLowColor() const
+{
+ return systemColor(ChromeDisabledLow);
+}
+
+QColor QQuickUniversalStyle::chromeHighColor() const
+{
+ return systemColor(ChromeHigh);
+}
+
+QColor QQuickUniversalStyle::chromeLowColor() const
+{
+ return systemColor(ChromeLow);
+}
+
+QColor QQuickUniversalStyle::chromeMediumColor() const
+{
+ return systemColor(ChromeMedium);
+}
+
+QColor QQuickUniversalStyle::chromeMediumLowColor() const
+{
+ return systemColor(ChromeMediumLow);
+}
+
+QColor QQuickUniversalStyle::chromeWhiteColor() const
+{
+ return systemColor(ChromeWhite);
+}
+
+QColor QQuickUniversalStyle::listLowColor() const
+{
+ return systemColor(ListLow);
+}
+
+QColor QQuickUniversalStyle::listMediumColor() const
+{
+ return systemColor(ListMedium);
+}
+
+QColor QQuickUniversalStyle::systemColor(SystemColor role) const
+{
+ return QColor::fromRgba(m_theme == QQuickUniversalStyle::Dark ? qquickuniversal_dark_color(role) : qquickuniversal_light_color(role));
+}
+
+void QQuickUniversalStyle::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+{
+ Q_UNUSED(oldParent);
+ QQuickUniversalStyle *universal = qobject_cast<QQuickUniversalStyle *>(newParent);
+ if (universal) {
+ inheritTheme(universal->theme());
+ inheritAccent(universal->m_accent);
+ inheritForeground(universal->m_foreground, universal->m_hasForeground);
+ inheritBackground(universal->m_background, universal->m_hasBackground);
+ }
+}
+
+template <typename Enum>
+static Enum toEnumValue(const QByteArray &value, bool *ok)
+{
+ QMetaEnum enumeration = QMetaEnum::fromType<Enum>();
+ return static_cast<Enum>(enumeration.keyToValue(value, ok));
+}
+
+static QByteArray resolveSetting(const QByteArray &env, const QSharedPointer<QSettings> &settings, const QString &name)
+{
+ QByteArray value = qgetenv(env);
+#if QT_CONFIG(settings)
+ if (value.isNull() && !settings.isNull())
+ value = settings->value(name).toByteArray();
+#endif
+ return value;
+}
+
+void QQuickUniversalStyle::initGlobals()
+{
+ QSharedPointer<QSettings> settings = QQuickStylePrivate::settings(QStringLiteral("Universal"));
+
+ bool ok = false;
+ QByteArray themeValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_THEME", settings, QStringLiteral("Theme"));
+ Theme themeEnum = toEnumValue<Theme>(themeValue, &ok);
+ if (ok)
+ GlobalTheme = qquickuniversal_effective_theme(themeEnum);
+ else if (!themeValue.isEmpty())
+ qWarning().nospace().noquote() << "Universal: unknown theme value: " << themeValue;
+
+ QByteArray accentValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_ACCENT", settings, QStringLiteral("Accent"));
+ Color accentEnum = toEnumValue<Color>(accentValue, &ok);
+ if (ok) {
+ GlobalAccent = qquickuniversal_accent_color(accentEnum);
+ } else if (!accentValue.isEmpty()) {
+ QColor color(accentValue.constData());
+ if (color.isValid())
+ GlobalAccent = color.rgba();
+ else
+ qWarning().nospace().noquote() << "Universal: unknown accent value: " << accentValue;
+ }
+
+ QByteArray foregroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_FOREGROUND", settings, QStringLiteral("Foreground"));
+ Color foregroundEnum = toEnumValue<Color>(foregroundValue, &ok);
+ if (ok) {
+ GlobalForeground = qquickuniversal_accent_color(foregroundEnum);
+ HasGlobalForeground = true;
+ } else if (!foregroundValue.isEmpty()) {
+ QColor color(foregroundValue.constData());
+ if (color.isValid()) {
+ GlobalForeground = color.rgba();
+ HasGlobalForeground = true;
+ } else {
+ qWarning().nospace().noquote() << "Universal: unknown foreground value: " << foregroundValue;
+ }
+ }
+
+ QByteArray backgroundValue = resolveSetting("QT_QUICK_CONTROLS_UNIVERSAL_BACKGROUND", settings, QStringLiteral("Background"));
+ Color backgroundEnum = toEnumValue<Color>(backgroundValue, &ok);
+ if (ok) {
+ GlobalBackground = qquickuniversal_accent_color(backgroundEnum);
+ HasGlobalBackground = true;
+ } else if (!backgroundValue.isEmpty()) {
+ QColor color(backgroundValue.constData());
+ if (color.isValid()) {
+ GlobalBackground = color.rgba();
+ HasGlobalBackground = true;
+ } else {
+ qWarning().nospace().noquote() << "Universal: unknown background value: " << backgroundValue;
+ }
+ }
+}
+
+bool QQuickUniversalStyle::variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const
+{
+ if (var.metaType().id() == QMetaType::Int) {
+ int val = var.toInt();
+ if (val < Lime || val > Taupe) {
+ qmlWarning(parent()) << "unknown Universal." << name << " value: " << val;
+ return false;
+ }
+ *rgba = qquickuniversal_accent_color(static_cast<Color>(val));
+ } else {
+ int val = QMetaEnum::fromType<Color>().keyToValue(var.toByteArray());
+ if (val != -1) {
+ *rgba = qquickuniversal_accent_color(static_cast<Color>(val));
+ } else {
+ QColor color(var.toString());
+ if (!color.isValid()) {
+ qmlWarning(parent()) << "unknown Universal." << name << " value: " << var.toString();
+ return false;
+ }
+ *rgba = color.rgba();
+ }
+ }
+ return true;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickuniversalstyle_p.cpp"
diff --git a/src/quickcontrols2/universal/qquickuniversalstyle_p.h b/src/quickcontrols2/universal/qquickuniversalstyle_p.h
new file mode 100644
index 0000000000..50b07071fc
--- /dev/null
+++ b/src/quickcontrols2/universal/qquickuniversalstyle_p.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKUNIVERSALSTYLE_P_H
+#define QQUICKUNIVERSALSTYLE_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 <QtQuickControls2Impl/private/qquickattachedobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickUniversalStylePrivate;
+
+class QQuickUniversalStyle : public QQuickAttachedObject
+{
+ Q_OBJECT
+ Q_PROPERTY(Theme theme READ theme WRITE setTheme RESET resetTheme NOTIFY themeChanged FINAL)
+ Q_PROPERTY(QVariant accent READ accent WRITE setAccent RESET resetAccent NOTIFY accentChanged FINAL)
+ Q_PROPERTY(QVariant foreground READ foreground WRITE setForeground RESET resetForeground NOTIFY foregroundChanged FINAL)
+ Q_PROPERTY(QVariant background READ background WRITE setBackground RESET resetBackground NOTIFY backgroundChanged FINAL)
+
+ Q_PROPERTY(QColor altHighColor READ altHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor altLowColor READ altLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor altMediumColor READ altMediumColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor altMediumHighColor READ altMediumHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor altMediumLowColor READ altMediumLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor baseHighColor READ baseHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor baseLowColor READ baseLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor baseMediumColor READ baseMediumColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor baseMediumHighColor READ baseMediumHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor baseMediumLowColor READ baseMediumLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeAltLowColor READ chromeAltLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeBlackHighColor READ chromeBlackHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeBlackLowColor READ chromeBlackLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeBlackMediumLowColor READ chromeBlackMediumLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeBlackMediumColor READ chromeBlackMediumColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeDisabledHighColor READ chromeDisabledHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeDisabledLowColor READ chromeDisabledLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeHighColor READ chromeHighColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeLowColor READ chromeLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeMediumColor READ chromeMediumColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeMediumLowColor READ chromeMediumLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor chromeWhiteColor READ chromeWhiteColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor listLowColor READ listLowColor NOTIFY paletteChanged FINAL)
+ Q_PROPERTY(QColor listMediumColor READ listMediumColor NOTIFY paletteChanged FINAL)
+
+ QML_NAMED_ELEMENT(Universal)
+ QML_ATTACHED(QQuickUniversalStyle)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickUniversalStyle(QObject *parent = nullptr);
+
+ static QQuickUniversalStyle *qmlAttachedProperties(QObject *object);
+
+ enum Theme { Light, Dark, System };
+ Q_ENUM(Theme)
+
+ Theme theme() const;
+ void setTheme(Theme theme);
+ void inheritTheme(Theme theme);
+ void propagateTheme();
+ void resetTheme();
+
+ enum Color {
+ Lime,
+ Green,
+ Emerald,
+ Teal,
+ Cyan,
+ Cobalt,
+ Indigo,
+ Violet,
+ Pink,
+ Magenta,
+ Crimson,
+ Red,
+ Orange,
+ Amber,
+ Yellow,
+ Brown,
+ Olive,
+ Steel,
+ Mauve,
+ Taupe
+ };
+ Q_ENUM(Color)
+
+ QVariant accent() const;
+ void setAccent(const QVariant &accent);
+ void inheritAccent(QRgb accent);
+ void propagateAccent();
+ void resetAccent();
+
+ QVariant foreground() const;
+ void setForeground(const QVariant &foreground);
+ void inheritForeground(QRgb foreground, bool has);
+ void propagateForeground();
+ void resetForeground();
+
+ QVariant background() const;
+ void setBackground(const QVariant &background);
+ void inheritBackground(QRgb background, bool has);
+ void propagateBackground();
+ void resetBackground();
+
+ Q_INVOKABLE QColor color(Color color) const;
+
+ QColor altHighColor() const;
+ QColor altLowColor() const;
+ QColor altMediumColor() const;
+ QColor altMediumHighColor() const;
+ QColor altMediumLowColor() const;
+ QColor baseHighColor() const;
+ QColor baseLowColor() const;
+ QColor baseMediumColor() const;
+ QColor baseMediumHighColor() const;
+ QColor baseMediumLowColor() const;
+ QColor chromeAltLowColor() const;
+ QColor chromeBlackHighColor() const;
+ QColor chromeBlackLowColor() const;
+ QColor chromeBlackMediumLowColor() const;
+ QColor chromeBlackMediumColor() const;
+ QColor chromeDisabledHighColor() const;
+ QColor chromeDisabledLowColor() const;
+ QColor chromeHighColor() const;
+ QColor chromeLowColor() const;
+ QColor chromeMediumColor() const;
+ QColor chromeMediumLowColor() const;
+ QColor chromeWhiteColor() const;
+ QColor listLowColor() const;
+ QColor listMediumColor() const;
+
+ enum SystemColor {
+ AltHigh,
+ AltLow,
+ AltMedium,
+ AltMediumHigh,
+ AltMediumLow,
+ BaseHigh,
+ BaseLow,
+ BaseMedium,
+ BaseMediumHigh,
+ BaseMediumLow,
+ ChromeAltLow,
+ ChromeBlackHigh,
+ ChromeBlackLow,
+ ChromeBlackMediumLow,
+ ChromeBlackMedium,
+ ChromeDisabledHigh,
+ ChromeDisabledLow,
+ ChromeHigh,
+ ChromeLow,
+ ChromeMedium,
+ ChromeMediumLow,
+ ChromeWhite,
+ ListLow,
+ ListMedium
+ };
+
+ QColor systemColor(SystemColor role) const;
+
+ static void initGlobals();
+
+Q_SIGNALS:
+ void themeChanged();
+ void accentChanged();
+ void foregroundChanged();
+ void backgroundChanged();
+ void paletteChanged();
+
+protected:
+ void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override;
+
+private:
+ bool variantToRgba(const QVariant &var, const char *name, QRgb *rgba) const;
+
+ // These reflect whether a color value was explicitly set on the specific
+ // item that this attached style object represents.
+ bool m_explicitTheme = false;
+ bool m_explicitAccent = false;
+ bool m_explicitForeground = false;
+ bool m_explicitBackground = false;
+ // These will be true when this item has an explicit or inherited foreground/background
+ // color, or these colors were declared globally via settings (e.g. conf or env vars).
+ // Some color properties of the style will return different values depending on whether
+ // or not these are set.
+ bool m_hasForeground = false;
+ bool m_hasBackground = false;
+ // The actual values for this item, whether explicit, inherited or globally set.
+ Theme m_theme = Light;
+ QRgb m_accent = Qt::blue;
+ QRgb m_foreground = Qt::black;
+ QRgb m_background = Qt::white;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPEINFO(QQuickUniversalStyle, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKUNIVERSALSTYLE_P_H
diff --git a/src/quickcontrols2/universal/qquickuniversaltheme.cpp b/src/quickcontrols2/universal/qquickuniversaltheme.cpp
new file mode 100644
index 0000000000..46f7c52e0a
--- /dev/null
+++ b/src/quickcontrols2/universal/qquickuniversaltheme.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversaltheme_p.h"
+
+#include <QtGui/qfontinfo.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickUniversalTheme::initialize(QQuickTheme *theme)
+{
+ QFont systemFont;
+ QFont groupBoxTitleFont;
+ QFont tabButtonFont;
+
+ const QFont font(QLatin1String("Segoe UI"));
+ if (QFontInfo(font).family() == QLatin1String("Segoe UI")) {
+ const QStringList families{font.family()};
+ systemFont.setFamilies(families);
+ groupBoxTitleFont.setFamilies(families);
+ tabButtonFont.setFamilies(families);
+ }
+
+ systemFont.setPixelSize(15);
+ theme->setFont(QQuickTheme::System, systemFont);
+
+ groupBoxTitleFont.setPixelSize(15);
+ groupBoxTitleFont.setWeight(QFont::DemiBold);
+ theme->setFont(QQuickTheme::GroupBox, groupBoxTitleFont);
+
+ tabButtonFont.setPixelSize(24);
+ tabButtonFont.setWeight(QFont::Light);
+ theme->setFont(QQuickTheme::TabBar, tabButtonFont);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/universal/qquickuniversaltheme_p.h b/src/quickcontrols2/universal/qquickuniversaltheme_p.h
new file mode 100644
index 0000000000..f762d0e339
--- /dev/null
+++ b/src/quickcontrols2/universal/qquickuniversaltheme_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKUNIVERSALTHEME_P_H
+#define QQUICKUNIVERSALTHEME_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 QQuickUniversalTheme
+{
+public:
+ static void initialize(QQuickTheme *theme);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKUNIVERSALTHEME_P_H
diff --git a/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.cpp b/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.cpp
new file mode 100644
index 0000000000..46e36bea3e
--- /dev/null
+++ b/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickuniversalstyle_p.h"
+#include "qquickuniversaltheme_p.h"
+
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+extern void qml_register_types_QtQuick_Controls_Universal();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Universal);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2UniversalStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2UniversalStylePlugin(QObject *parent = nullptr);
+
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+
+ QQuickUniversalTheme theme;
+};
+
+QtQuickControls2UniversalStylePlugin::QtQuickControls2UniversalStylePlugin(QObject *parent) : QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Universal;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2UniversalStylePlugin::name() const
+{
+ return QStringLiteral("Universal");
+}
+
+void QtQuickControls2UniversalStylePlugin::initializeTheme(QQuickTheme *theme)
+{
+ QQuickUniversalStyle::initGlobals();
+ this->theme.initialize(theme);
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2universalstyleplugin.moc"
diff --git a/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.qrc b/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.qrc
new file mode 100644
index 0000000000..bfcb0974ce
--- /dev/null
+++ b/src/quickcontrols2/universal/qtquickcontrols2universalstyleplugin.qrc
@@ -0,0 +1,20 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="qt-project.org/imports/QtQuick/Controls/Universal">
+ <file>images/checkmark.png</file>
+ <file>images/checkmark@2x.png</file>
+ <file>images/checkmark@3x.png</file>
+ <file>images/checkmark@4x.png</file>
+ <file>images/downarrow.png</file>
+ <file>images/downarrow@2x.png</file>
+ <file>images/downarrow@3x.png</file>
+ <file>images/downarrow@4x.png</file>
+ <file>images/leftarrow.png</file>
+ <file>images/leftarrow@2x.png</file>
+ <file>images/leftarrow@3x.png</file>
+ <file>images/leftarrow@4x.png</file>
+ <file>images/rightarrow.png</file>
+ <file>images/rightarrow@2x.png</file>
+ <file>images/rightarrow@3x.png</file>
+ <file>images/rightarrow@4x.png</file>
+</qresource>
+</RCC>
diff --git a/src/quickcontrols2/universal/universal.pri b/src/quickcontrols2/universal/universal.pri
new file mode 100644
index 0000000000..44fb584af9
--- /dev/null
+++ b/src/quickcontrols2/universal/universal.pri
@@ -0,0 +1,60 @@
+HEADERS += \
+ $$PWD/qquickuniversalstyle_p.h \
+ $$PWD/qquickuniversaltheme_p.h
+
+SOURCES += \
+ $$PWD/qquickuniversalstyle.cpp \
+ $$PWD/qquickuniversaltheme.cpp
+
+QML_FILES += \
+ $$PWD/ApplicationWindow.qml \
+ $$PWD/BusyIndicator.qml \
+ $$PWD/Button.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/CheckDelegate.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/DelayButton.qml \
+ $$PWD/Dial.qml \
+ $$PWD/Dialog.qml \
+ $$PWD/DialogButtonBox.qml \
+ $$PWD/Drawer.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/HorizontalHeaderView.qml \
+ $$PWD/ItemDelegate.qml \
+ $$PWD/Label.qml \
+ $$PWD/Menu.qml \
+ $$PWD/MenuBar.qml \
+ $$PWD/MenuBarItem.qml \
+ $$PWD/MenuItem.qml \
+ $$PWD/MenuSeparator.qml \
+ $$PWD/Page.qml \
+ $$PWD/PageIndicator.qml \
+ $$PWD/Pane.qml \
+ $$PWD/Popup.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/RadioDelegate.qml \
+ $$PWD/RangeSlider.qml \
+ $$PWD/RoundButton.qml \
+ $$PWD/ScrollView.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollIndicator.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/SplitView.qml \
+ $$PWD/StackView.qml \
+ $$PWD/SwipeDelegate.qml \
+ $$PWD/SwitchDelegate.qml \
+ $$PWD/Switch.qml \
+ $$PWD/TabBar.qml \
+ $$PWD/TabButton.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TextField.qml \
+ $$PWD/ToolBar.qml \
+ $$PWD/ToolButton.qml \
+ $$PWD/ToolSeparator.qml \
+ $$PWD/ToolTip.qml \
+ $$PWD/Tumbler.qml \
+ $$PWD/VerticalHeaderView.qml
diff --git a/src/quickcontrols2/windows/Button.qml b/src/quickcontrols2/windows/Button.qml
new file mode 100644
index 0000000000..6b28f8e7c5
--- /dev/null
+++ b/src/quickcontrols2/windows/Button.qml
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultButton {
+ id: control
+
+ background: NativeStyle.Button {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ useNinePatchImage: false
+ overrideState: NativeStyle.StyleItem.NeverHovered
+ }
+
+ NativeStyle.Button {
+ id: hoverButton
+ control: control
+ x: background.x
+ y: background.y
+ width: background.width
+ height: background.height
+ useNinePatchImage: false
+ overrideState: NativeStyle.StyleItem.AlwaysHovered
+ opacity: control.hovered ? 1 : 0
+ visible: opacity !== 0
+ Behavior on opacity { NumberAnimation { duration: hoverButton.transitionDuration } }
+ }
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.flat && !control.down ? (control.visualFocus ? control.palette.highlight : control.palette.windowText) : control.palette.buttonText
+ }
+}
diff --git a/src/quickcontrols2/windows/CMakeLists.txt b/src/quickcontrols2/windows/CMakeLists.txt
new file mode 100644
index 0000000000..3ac58054a2
--- /dev/null
+++ b/src/quickcontrols2/windows/CMakeLists.txt
@@ -0,0 +1,53 @@
+#####################################################################
+## qtquickcontrols2windowsstyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "Button.qml"
+ "CheckBox.qml"
+ "ComboBox.qml"
+ "Frame.qml"
+ "GroupBox.qml"
+ "ProgressBar.qml"
+ "RadioButton.qml"
+ "SelectionRectangle.qml"
+ "Slider.qml"
+ "SpinBox.qml"
+ "TextArea.qml"
+ "TextField.qml"
+ "ScrollBar.qml"
+ "ScrollView.qml"
+)
+
+qt_internal_add_qml_module(qtquickcontrols2windowsstyleplugin
+ URI "QtQuick.Controls.Windows"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickControls2WindowsStylePlugin
+ IMPORTS
+ QtQuick.Controls.Fusion/auto
+ PAST_MAJOR_VERSIONS 2
+ PLUGIN_TARGET qtquickcontrols2windowsstyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qtquickcontrols2windowsstyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+# Native style is a dependency of the Windows style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2windowsstyleplugin
+ qtquickcontrols2nativestyleplugin)
+# Fusion style is the required fallback style.
+_qt_internal_add_qml_static_plugin_dependency(qtquickcontrols2windowsstyleplugin
+ qtquickcontrols2fusionstyleplugin)
diff --git a/src/quickcontrols2/windows/CheckBox.qml b/src/quickcontrols2/windows/CheckBox.qml
new file mode 100644
index 0000000000..eaf70a3f35
--- /dev/null
+++ b/src/quickcontrols2/windows/CheckBox.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.NativeStyle as NativeStyle
+
+T.CheckBox {
+ id: control
+
+ readonly property bool nativeIndicator: indicator instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: nativeIndicator ? 0 : 6
+ padding: nativeIndicator ? 0 : 6
+
+ indicator: NativeStyle.CheckBox {
+ control: control
+ y: control.topPadding + (control.availableHeight - height) >> 1
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ useNinePatchImage: false
+ overrideState: NativeStyle.StyleItem.NeverHovered
+ }
+
+ NativeStyle.CheckBox {
+ id: hoverCheckBox
+ control: control
+ x: indicator.x
+ y: indicator.y
+ z: 99 // Needs to be above the "unhovered" indicator
+ width: indicator.width
+ height: indicator.height
+ useNinePatchImage: false
+ overrideState: NativeStyle.StyleItem.AlwaysHovered
+ opacity: control.hovered ? 1 : 0
+ visible: opacity !== 0
+ Behavior on opacity { NumberAnimation { duration: hoverCheckBox.transitionDuration } }
+ }
+
+ contentItem: CheckLabel {
+ text: control.text
+ font: control.font
+ color: control.palette.windowText
+
+ // For some reason, the other styles set padding here (in the delegate), instead of in
+ // the control above. And they also adjust the indicator position by setting x and y
+ // explicitly (instead of using insets). So we follow the same pattern to ensure that
+ // setting a custom contentItem delegate from the app will end up looking the same for
+ // all styles. But this should probably be fixed for all styles (to make them work the
+ // same way as e.g Buttons).
+ leftPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.left
+ else
+ indicator && !mirrored ? indicator.width + spacing : 0
+ }
+
+ topPadding: nativeIndicator ? indicator.contentPadding.top : 0
+ rightPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.right
+ else
+ indicator && mirrored ? indicator.width + spacing : 0
+ }
+ }
+}
diff --git a/src/quickcontrols2/windows/ComboBox.qml b/src/quickcontrols2/windows/ComboBox.qml
new file mode 100644
index 0000000000..13fa844dae
--- /dev/null
+++ b/src/quickcontrols2/windows/ComboBox.qml
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.ComboBox {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ 90 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: __nativeBackground ? background.contentPadding.left : 5
+ rightPadding: __nativeBackground ? background.contentPadding.right : 5
+ topPadding: __nativeBackground ? background.contentPadding.top : 5
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom : 5
+
+ contentItem: T.TextField {
+ implicitWidth: contentWidth
+ implicitHeight: contentHeight
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NativeStyle.ComboBox {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ useNinePatchImage: false
+ }
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ palette.text: control.palette.text
+ palette.highlightedText: control.palette.highlightedText
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ popup: T.Popup {
+ readonly property var layoutMargins: control.__nativeBackground ? control.background.layoutMargins : null
+ x: layoutMargins ? layoutMargins.left : 0
+ y: control.height - (layoutMargins ? layoutMargins.bottom : 0)
+ width: control.width - (layoutMargins ? layoutMargins.left + layoutMargins.right : 0)
+ height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
+ topMargin: 6
+ bottomMargin: 6
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ Rectangle {
+ z: 10
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ border.color: control.palette.mid
+ }
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+ }
+}
diff --git a/src/quickcontrols2/windows/Frame.qml b/src/quickcontrols2/windows/Frame.qml
new file mode 100644
index 0000000000..f16a083517
--- /dev/null
+++ b/src/quickcontrols2/windows/Frame.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultFrame {
+}
diff --git a/src/quickcontrols2/windows/GroupBox.qml b/src/quickcontrols2/windows/GroupBox.qml
new file mode 100644
index 0000000000..4ffbaae6d3
--- /dev/null
+++ b/src/quickcontrols2/windows/GroupBox.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultGroupBox {
+}
diff --git a/src/quickcontrols2/windows/ProgressBar.qml b/src/quickcontrols2/windows/ProgressBar.qml
new file mode 100644
index 0000000000..59a1689dba
--- /dev/null
+++ b/src/quickcontrols2/windows/ProgressBar.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultProgressBar {
+}
diff --git a/src/quickcontrols2/windows/RadioButton.qml b/src/quickcontrols2/windows/RadioButton.qml
new file mode 100644
index 0000000000..82b85698d2
--- /dev/null
+++ b/src/quickcontrols2/windows/RadioButton.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultRadioButton {
+}
diff --git a/src/quickcontrols2/windows/ScrollBar.qml b/src/quickcontrols2/windows/ScrollBar.qml
new file mode 100644
index 0000000000..8972cfc53c
--- /dev/null
+++ b/src/quickcontrols2/windows/ScrollBar.qml
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultScrollBar {
+ id: controlRoot
+
+ topPadding: orientation === Qt.Vertical ? controlRoot.__decreaseVisual.indicator.height : 0
+ bottomPadding: orientation === Qt.Vertical ? controlRoot.__increaseVisual.indicator.height : 0
+ leftPadding: orientation === Qt.Horizontal ? controlRoot.__decreaseVisual.indicator.width : 0
+ rightPadding: orientation === Qt.Horizontal ? controlRoot.__increaseVisual.indicator.width : 0
+
+ contentItem: NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.Handle
+ }
+
+ NativeStyle.ScrollBar {
+ // Fade a hovered-looking version of the handle
+ // on top of the default handle when hovering it
+ x: contentItem.x
+ y: contentItem.y
+ z: 1
+ width: contentItem.width
+ height: contentItem.height
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.Handle
+ overrideState: NativeStyle.StyleItem.AlwaysHovered
+ opacity: controlRoot.hovered || control.pressed ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } }
+ }
+
+ // The groove background should have window color
+ Rectangle {
+ x: background.x
+ y: background.y
+ z: -1
+ width: background.width
+ height: background.height
+ color: controlRoot.palette.window
+ }
+
+ background: NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.Groove
+ overrideState: NativeStyle.ScrollBar.NeverHovered
+ }
+
+ __decreaseVisual.indicator: NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.SubLine
+ overrideState: NativeStyle.ScrollBar.AlwaysHovered
+ opacity: controlRoot.__decreaseVisual.hovered ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } }
+ useNinePatchImage: false
+ }
+
+ NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.SubLine
+ overrideState: NativeStyle.ScrollBar.AlwaysSunken
+ opacity: controlRoot.__decreaseVisual.pressed ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ useNinePatchImage: false
+ z: 1
+ }
+
+ __increaseVisual.indicator: NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.AddLine
+ x: orientation === Qt.Horizontal ? controlRoot.width - width : 0
+ y: orientation === Qt.Vertical ? controlRoot.height - height : 0
+ overrideState: NativeStyle.ScrollBar.AlwaysHovered
+ opacity: controlRoot.__increaseVisual.hovered ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ Behavior on opacity { NumberAnimation { duration: contentItem.transitionDuration } }
+ useNinePatchImage: false
+ }
+
+ NativeStyle.ScrollBar {
+ control: controlRoot
+ subControl: NativeStyle.ScrollBar.AddLine
+ x: __increaseVisual.indicator.x
+ y: __increaseVisual.indicator.y
+ z: 1
+ overrideState: NativeStyle.ScrollBar.AlwaysSunken
+ opacity: controlRoot.__increaseVisual.pressed ? 1 : 0
+ visible: contentItem instanceof NativeStyle.StyleItem
+ useNinePatchImage: false
+ }
+}
diff --git a/src/quickcontrols2/windows/ScrollView.qml b/src/quickcontrols2/windows/ScrollView.qml
new file mode 100644
index 0000000000..0e5ffff4b6
--- /dev/null
+++ b/src/quickcontrols2/windows/ScrollView.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+
+T.ScrollView {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ rightPadding: ScrollBar.vertical.visible ? ScrollBar.vertical.width : 0
+ bottomPadding: ScrollBar.horizontal.visible ? ScrollBar.horizontal.height : 0
+
+ ScrollBar.vertical: ScrollBar {
+ parent: control
+ x: control.mirrored ? 0 : control.width - width
+ y: 0
+ height: control.height - (control.ScrollBar.horizontal.visible ? control.ScrollBar.horizontal.height : 0)
+ active: control.ScrollBar.horizontal.active
+ }
+
+ ScrollBar.horizontal: ScrollBar {
+ parent: control
+ x: 0
+ y: control.height - height
+ width: control.width - (control.ScrollBar.vertical.visible ? control.ScrollBar.vertical.width : 0)
+ active: control.ScrollBar.vertical.active
+ }
+}
diff --git a/src/quickcontrols2/windows/SelectionRectangle.qml b/src/quickcontrols2/windows/SelectionRectangle.qml
new file mode 100644
index 0000000000..d54b6e9b42
--- /dev/null
+++ b/src/quickcontrols2/windows/SelectionRectangle.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Shapes
+
+T.SelectionRectangle {
+ id: control
+
+ topLeftHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+
+ bottomRightHandle: Item {
+ width: 20
+ height: 20
+ visible: SelectionRectangle.control.active
+ // This item is deliberately empty. Selection handles don't feel at home
+ // for this style. But we provide an invisible handle that the user can
+ // drag on.
+ }
+
+}
diff --git a/src/quickcontrols2/windows/Slider.qml b/src/quickcontrols2/windows/Slider.qml
new file mode 100644
index 0000000000..ab72fcaabd
--- /dev/null
+++ b/src/quickcontrols2/windows/Slider.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultSlider {
+}
diff --git a/src/quickcontrols2/windows/SpinBox.qml b/src/quickcontrols2/windows/SpinBox.qml
new file mode 100644
index 0000000000..2f50f0d5e5
--- /dev/null
+++ b/src/quickcontrols2/windows/SpinBox.qml
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.SpinBox {
+ id: control
+
+ property bool nativeIndicators: up.indicator.hasOwnProperty("_qt_default")
+ && down.indicator.hasOwnProperty("_qt_default")
+
+ implicitWidth: Math.max(contentItem.implicitWidth + leftInset + rightInset,
+ 90 /* minimum */ )
+ implicitHeight: Math.max(contentItem.implicitHeight, up.implicitIndicatorHeight + down.implicitIndicatorHeight)
+ + topInset + bottomInset
+
+ spacing: 2
+
+ leftPadding: 0
+ topPadding: 0
+ rightPadding: rightInset
+ bottomPadding: 0
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextField {
+ text: control.displayText
+ font: control.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignLeft
+ verticalAlignment: Qt.AlignVCenter
+
+ topPadding: 0
+ bottomPadding: 0
+ leftPadding: 10
+ rightPadding: 10
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+
+ // Since the indicators are embedded inside the TextField we need to avoid that
+ // the TextField consumes mouse events for that area.
+ // We achieve that by setting a containmentMask
+ containmentMask: Item { height: contentItem.height; width: contentItem.width - upAndDown.width }
+ }
+
+ NativeStyle.SpinBox {
+ id: upAndDown
+ control: control
+ subControl: NativeStyle.SpinBox.Up
+ visible: nativeIndicators
+ x: up.indicator.x
+ y: up.indicator.y
+ //implicitHeight: contentItem.implicitHeight-2
+ height: parent.height-2
+ useNinePatchImage: false
+ z:99
+ }
+
+ up.indicator: Item {
+ x: parent.width - width - 2
+ y: 1
+ height: upAndDown.height >> 1
+ implicitWidth: upAndDown.implicitWidth
+ implicitHeight: (upAndDown.implicitHeight >> 1)
+ property bool _qt_default
+ }
+
+ down.indicator: Item {
+ x: parent.width - width - 2
+ y: up.indicator.y + (upAndDown.height >> 1)
+ height: upAndDown.height - up.indicator.height
+ implicitWidth: upAndDown.implicitWidth
+ implicitHeight: upAndDown.implicitHeight >> 1
+ property bool _qt_default
+ }
+
+ background: Item {} // No background, the TextField will cover the whole control
+}
diff --git a/src/quickcontrols2/windows/TextArea.qml b/src/quickcontrols2/windows/TextArea.qml
new file mode 100644
index 0000000000..f6b883038b
--- /dev/null
+++ b/src/quickcontrols2/windows/TextArea.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultTextArea {
+}
diff --git a/src/quickcontrols2/windows/TextField.qml b/src/quickcontrols2/windows/TextField.qml
new file mode 100644
index 0000000000..bc0e2cb77a
--- /dev/null
+++ b/src/quickcontrols2/windows/TextField.qml
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.NativeStyle as NativeStyle
+
+NativeStyle.DefaultTextField {
+}
diff --git a/src/quickcontrols2/windows/qtquickcontrols2windowsstyleplugin.cpp b/src/quickcontrols2/windows/qtquickcontrols2windowsstyleplugin.cpp
new file mode 100644
index 0000000000..90ff1fe417
--- /dev/null
+++ b/src/quickcontrols2/windows/qtquickcontrols2windowsstyleplugin.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtQuickControls2/qquickstyle.h>
+
+extern void qml_register_types_QtQuick_Controls_Windows();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Controls_Windows);
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickControls2WindowsStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2WindowsStylePlugin(QObject *parent = nullptr);
+ QString name() const override;
+ void initializeTheme(QQuickTheme *theme) override;
+};
+
+QtQuickControls2WindowsStylePlugin::QtQuickControls2WindowsStylePlugin(QObject *parent):
+ QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Controls_Windows;
+ Q_UNUSED(registration);
+}
+
+QString QtQuickControls2WindowsStylePlugin::name() const
+{
+ return QStringLiteral("Windows");
+}
+
+void QtQuickControls2WindowsStylePlugin::initializeTheme(QQuickTheme * /*theme*/)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2windowsstyleplugin.moc"
diff --git a/src/quickcontrols2/windows/windows.pri b/src/quickcontrols2/windows/windows.pri
new file mode 100644
index 0000000000..155730e048
--- /dev/null
+++ b/src/quickcontrols2/windows/windows.pri
@@ -0,0 +1,15 @@
+QML_FILES += \
+ $$PWD/Button.qml \
+ $$PWD/CheckBox.qml \
+ $$PWD/ComboBox.qml \
+ $$PWD/Frame.qml \
+ $$PWD/GroupBox.qml \
+ $$PWD/ProgressBar.qml \
+ $$PWD/RadioButton.qml \
+ $$PWD/SelectionRectangle.qml \
+ $$PWD/Slider.qml \
+ $$PWD/SpinBox.qml \
+ $$PWD/TextArea.qml \
+ $$PWD/TextField.qml \
+ $$PWD/ScrollBar.qml \
+ $$PWD/ScrollView.qml \
diff --git a/src/quickcontrols2impl/CMakeLists.txt b/src/quickcontrols2impl/CMakeLists.txt
new file mode 100644
index 0000000000..048938a8ce
--- /dev/null
+++ b/src/quickcontrols2impl/CMakeLists.txt
@@ -0,0 +1,47 @@
+#####################################################################
+## QuickControls2Impl Module:
+#####################################################################
+
+qt_internal_add_qml_module(QuickControls2Impl
+ URI "QtQuick.Controls.impl"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickControls2ImplPlugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquickcontrols2implplugin
+ SOURCES
+ qquickanimatednode.cpp qquickanimatednode_p.h
+ qquickattachedobject.cpp qquickattachedobject_p.h
+ qquickchecklabel.cpp qquickchecklabel_p.h
+ qquickclippedtext.cpp qquickclippedtext_p.h
+ qquickcolor.cpp qquickcolor_p.h
+ qquickcolorimage.cpp qquickcolorimage_p.h
+ qquickiconimage.cpp qquickiconimage_p.h
+ qquickiconimage_p_p.h
+ qquickiconlabel.cpp qquickiconlabel_p.h
+ qquickiconlabel_p_p.h
+ qquickitemgroup.cpp qquickitemgroup_p.h
+ qquickmnemoniclabel.cpp qquickmnemoniclabel_p.h
+ qquickpaddedrectangle.cpp qquickpaddedrectangle_p.h
+ qquickplaceholdertext.cpp qquickplaceholdertext_p.h
+ qtquickcontrols2foreign_p.h
+ qtquickcontrols2implglobal_p.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+qt_internal_extend_target(QuickControls2Impl CONDITION QT_FEATURE_quick_listview AND QT_FEATURE_quick_pathview
+ SOURCES
+ qquicktumblerview.cpp qquicktumblerview_p.h
+)
diff --git a/src/quickcontrols2impl/qquickanimatednode.cpp b/src/quickcontrols2impl/qquickanimatednode.cpp
new file mode 100644
index 0000000000..510f643cb2
--- /dev/null
+++ b/src/quickcontrols2impl/qquickanimatednode.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickanimatednode_p.h"
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
+
+// based on qtdeclarative/examples/quick/scenegraph/threadedanimation
+
+QT_BEGIN_NAMESPACE
+
+QQuickAnimatedNode::QQuickAnimatedNode(QQuickItem *target)
+ : m_window(target->window())
+{
+}
+
+bool QQuickAnimatedNode::isRunning() const
+{
+ return m_running;
+}
+
+int QQuickAnimatedNode::currentTime() const
+{
+ int time = m_currentTime;
+ if (m_running)
+ time += m_timer.elapsed();
+ return time;
+}
+
+void QQuickAnimatedNode::setCurrentTime(int time)
+{
+ m_currentTime = time;
+ m_timer.restart();
+}
+
+int QQuickAnimatedNode::duration() const
+{
+ return m_duration;
+}
+
+void QQuickAnimatedNode::setDuration(int duration)
+{
+ m_duration = duration;
+}
+
+int QQuickAnimatedNode::loopCount() const
+{
+ return m_loopCount;
+}
+
+void QQuickAnimatedNode::setLoopCount(int count)
+{
+ m_loopCount = count;
+}
+
+void QQuickAnimatedNode::sync(QQuickItem *target)
+{
+ Q_UNUSED(target);
+}
+
+QQuickWindow *QQuickAnimatedNode::window() const
+{
+ return m_window;
+}
+
+void QQuickAnimatedNode::start(int duration)
+{
+ if (m_running)
+ return;
+
+ m_running = true;
+ m_currentLoop = 0;
+ m_timer.restart();
+ if (duration > 0)
+ m_duration = duration;
+
+ connect(m_window, &QQuickWindow::beforeRendering, this, &QQuickAnimatedNode::advance, Qt::DirectConnection);
+ connect(m_window, &QQuickWindow::frameSwapped, this, &QQuickAnimatedNode::update, Qt::DirectConnection);
+
+ // If we're inside a QQuickWidget, this call is necessary to ensure the widget
+ // gets updated for the first time.
+ m_window->update();
+
+ emit started();
+}
+
+void QQuickAnimatedNode::restart()
+{
+ stop();
+ start();
+}
+
+void QQuickAnimatedNode::stop()
+{
+ if (!m_running)
+ return;
+
+ m_running = false;
+ disconnect(m_window, &QQuickWindow::beforeRendering, this, &QQuickAnimatedNode::advance);
+ disconnect(m_window, &QQuickWindow::frameSwapped, this, &QQuickAnimatedNode::update);
+ emit stopped();
+}
+
+void QQuickAnimatedNode::updateCurrentTime(int time)
+{
+ Q_UNUSED(time);
+}
+
+void QQuickAnimatedNode::advance()
+{
+ int time = currentTime();
+ if (time > m_duration) {
+ time = 0;
+ setCurrentTime(0);
+
+ if (m_loopCount > 0 && ++m_currentLoop >= m_loopCount) {
+ time = m_duration; // complete
+ stop();
+ }
+ }
+ updateCurrentTime(time);
+
+ // If we're inside a QQuickWidget, this call is necessary to ensure the widget gets updated.
+ m_window->update();
+}
+
+void QQuickAnimatedNode::update()
+{
+ if (m_running)
+ m_window->update();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickanimatednode_p.cpp"
diff --git a/src/quickcontrols2impl/qquickanimatednode_p.h b/src/quickcontrols2impl/qquickanimatednode_p.h
new file mode 100644
index 0000000000..e403f0bf47
--- /dev/null
+++ b/src/quickcontrols2impl/qquickanimatednode_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKANIMATEDNODE_P_H
+#define QQUICKANIMATEDNODE_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/qsgnode.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickWindow;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickAnimatedNode : public QObject, public QSGTransformNode
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickAnimatedNode(QQuickItem *target);
+
+ bool isRunning() const;
+
+ int currentTime() const;
+ void setCurrentTime(int time);
+
+ int duration() const;
+ void setDuration(int duration);
+
+ enum LoopCount { Infinite = -1 };
+
+ int loopCount() const;
+ void setLoopCount(int count);
+
+ virtual void sync(QQuickItem *target);
+
+ QQuickWindow *window() const;
+
+ // must be called from sync() or updatePaintNode()
+ void start(int duration = 0);
+ void restart();
+ void stop();
+
+Q_SIGNALS:
+ void started();
+ void stopped();
+
+protected:
+ virtual void updateCurrentTime(int time);
+
+private Q_SLOTS:
+ void advance();
+ void update();
+
+private:
+ bool m_running = false;
+ int m_duration = 0;
+ int m_loopCount = 1;
+ int m_currentTime = 0;
+ int m_currentLoop = 0;
+ QElapsedTimer m_timer;
+ QQuickWindow *m_window = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKANIMATEDNODE_P_H
diff --git a/src/quickcontrols2impl/qquickattachedobject.cpp b/src/quickcontrols2impl/qquickattachedobject.cpp
new file mode 100644
index 0000000000..244ff3125a
--- /dev/null
+++ b/src/quickcontrols2impl/qquickattachedobject.cpp
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickattachedobject_p.h"
+
+#include <QtCore/qpointer.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QQuickAttachedObject *attachedObject(const QMetaObject *type, QObject *object, bool create = false)
+{
+ if (!object)
+ return nullptr;
+ auto func = qmlAttachedPropertiesFunction(object, type);
+ return qobject_cast<QQuickAttachedObject *>(qmlAttachedPropertiesObject(object, func, create));
+}
+
+static QQuickAttachedObject *findAttachedParent(const QMetaObject *type, QObject *object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (item) {
+ // lookup parent items and popups
+ QQuickItem *parent = item->parentItem();
+ while (parent) {
+ QQuickAttachedObject *attached = attachedObject(type, parent);
+ if (attached)
+ return attached;
+
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent->parent());
+ if (popup)
+ return attachedObject(type, popup);
+
+ parent = parent->parentItem();
+ }
+
+ // fallback to item's window
+ QQuickAttachedObject *attached = attachedObject(type, item->window());
+ if (attached)
+ return attached;
+ } else {
+ // lookup popup's window
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(object);
+ if (popup)
+ return attachedObject(type, popup->popupItem()->window());
+ }
+
+ // lookup parent window
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
+ if (window) {
+ QQuickWindow *parentWindow = qobject_cast<QQuickWindow *>(window->parent());
+ if (parentWindow) {
+ QQuickAttachedObject *attached = attachedObject(type, window);
+ if (attached)
+ return attached;
+ }
+ }
+
+ // fallback to engine (global)
+ if (object) {
+ QQmlEngine *engine = qmlEngine(object);
+ if (engine) {
+ QByteArray name = QByteArray("_q_") + type->className();
+ QQuickAttachedObject *attached = engine->property(name).value<QQuickAttachedObject *>();
+ if (!attached) {
+ attached = attachedObject(type, engine, true);
+ engine->setProperty(name, QVariant::fromValue(attached));
+ }
+ return attached;
+ }
+ }
+
+ return nullptr;
+}
+
+static QList<QQuickAttachedObject *> findAttachedChildren(const QMetaObject *type, QObject *object)
+{
+ QList<QQuickAttachedObject *> children;
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item) {
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(object);
+ if (window) {
+ item = window->contentItem();
+
+ const auto &windowChildren = window->children();
+ for (QObject *child : windowChildren) {
+ QQuickWindow *childWindow = qobject_cast<QQuickWindow *>(child);
+ if (childWindow) {
+ QQuickAttachedObject *attached = attachedObject(type, childWindow);
+ if (attached)
+ children += attached;
+ }
+ }
+ }
+ }
+
+ if (item) {
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
+ QQuickAttachedObject *attached = attachedObject(type, child);
+ if (attached)
+ children += attached;
+ else
+ children += findAttachedChildren(type, child);
+ }
+ }
+
+ return children;
+}
+
+static QQuickItem *findAttachedItem(QObject *parent)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (!item) {
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent);
+ if (popup)
+ item = popup->popupItem();
+ }
+ return item;
+}
+
+class QQuickAttachedObjectPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickAttachedObject)
+
+public:
+ static QQuickAttachedObjectPrivate *get(QQuickAttachedObject *attachedObject)
+ {
+ return attachedObject->d_func();
+ }
+
+ void attachTo(QObject *object);
+ void detachFrom(QObject *object);
+
+ void itemWindowChanged(QQuickWindow *window);
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
+
+ QList<QQuickAttachedObject *> attachedChildren;
+ QPointer<QQuickAttachedObject> attachedParent;
+};
+
+void QQuickAttachedObjectPrivate::attachTo(QObject *object)
+{
+ QQuickItem *item = findAttachedItem(object);
+ if (item) {
+ connect(item, &QQuickItem::windowChanged, this, &QQuickAttachedObjectPrivate::itemWindowChanged);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
+}
+
+void QQuickAttachedObjectPrivate::detachFrom(QObject *object)
+{
+ QQuickItem *item = findAttachedItem(object);
+ if (item) {
+ disconnect(item, &QQuickItem::windowChanged, this, &QQuickAttachedObjectPrivate::itemWindowChanged);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent);
+ }
+}
+
+void QQuickAttachedObjectPrivate::itemWindowChanged(QQuickWindow *window)
+{
+ Q_Q(QQuickAttachedObject);
+ QQuickAttachedObject *attachedParent = nullptr;
+ QQuickItem *item = qobject_cast<QQuickItem *>(q->sender());
+ if (item)
+ attachedParent = findAttachedParent(q->metaObject(), item);
+ if (!attachedParent)
+ attachedParent = attachedObject(q->metaObject(), window);
+ q->setAttachedParent(attachedParent);
+}
+
+void QQuickAttachedObjectPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ Q_Q(QQuickAttachedObject);
+ Q_UNUSED(parent);
+ q->setAttachedParent(findAttachedParent(q->metaObject(), item));
+}
+
+QQuickAttachedObject::QQuickAttachedObject(QObject *parent)
+ : QObject(*(new QQuickAttachedObjectPrivate), parent)
+{
+ Q_D(QQuickAttachedObject);
+ d->attachTo(parent);
+}
+
+QQuickAttachedObject::~QQuickAttachedObject()
+{
+ Q_D(QQuickAttachedObject);
+ d->detachFrom(parent());
+ setAttachedParent(nullptr);
+}
+
+QList<QQuickAttachedObject *> QQuickAttachedObject::attachedChildren() const
+{
+ Q_D(const QQuickAttachedObject);
+ return d->attachedChildren;
+}
+
+QQuickAttachedObject *QQuickAttachedObject::attachedParent() const
+{
+ Q_D(const QQuickAttachedObject);
+ return d->attachedParent;
+}
+
+void QQuickAttachedObject::setAttachedParent(QQuickAttachedObject *parent)
+{
+ Q_D(QQuickAttachedObject);
+ if (d->attachedParent == parent)
+ return;
+
+ QQuickAttachedObject *oldParent = d->attachedParent;
+ if (d->attachedParent)
+ QQuickAttachedObjectPrivate::get(d->attachedParent)->attachedChildren.removeOne(this);
+ d->attachedParent = parent;
+ if (parent)
+ QQuickAttachedObjectPrivate::get(parent)->attachedChildren.append(this);
+ attachedParentChange(parent, oldParent);
+}
+
+void QQuickAttachedObject::init()
+{
+ QQuickAttachedObject *attachedParent = findAttachedParent(metaObject(), parent());
+ if (attachedParent)
+ setAttachedParent(attachedParent);
+
+ const QList<QQuickAttachedObject *> attachedChildren = findAttachedChildren(metaObject(), parent());
+ for (QQuickAttachedObject *child : attachedChildren)
+ child->setAttachedParent(this);
+}
+
+void QQuickAttachedObject::attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent)
+{
+ Q_UNUSED(newParent);
+ Q_UNUSED(oldParent);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickattachedobject_p.cpp"
diff --git a/src/quickcontrols2impl/qquickattachedobject_p.h b/src/quickcontrols2impl/qquickattachedobject_p.h
new file mode 100644
index 0000000000..cd2404c2e8
--- /dev/null
+++ b/src/quickcontrols2impl/qquickattachedobject_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKATTACHEDOBJECT_P_H
+#define QQUICKATTACHEDOBJECT_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 <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAttachedObjectPrivate;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickAttachedObject : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickAttachedObject(QObject *parent = nullptr);
+ ~QQuickAttachedObject();
+
+ QList<QQuickAttachedObject *> attachedChildren() const;
+
+ QQuickAttachedObject *attachedParent() const;
+ void setAttachedParent(QQuickAttachedObject *parent);
+
+protected:
+ void init();
+
+ virtual void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent);
+
+private:
+ Q_DISABLE_COPY(QQuickAttachedObject)
+ Q_DECLARE_PRIVATE(QQuickAttachedObject)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKATTACHEDOBJECT_P_H
diff --git a/src/quickcontrols2impl/qquickchecklabel.cpp b/src/quickcontrols2impl/qquickchecklabel.cpp
new file mode 100644
index 0000000000..5f8075823b
--- /dev/null
+++ b/src/quickcontrols2impl/qquickchecklabel.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickchecklabel_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickCheckLabel::QQuickCheckLabel(QQuickItem *parent) :
+ QQuickText(parent)
+{
+ setHAlign(AlignLeft);
+ setVAlign(AlignVCenter);
+ setElideMode(ElideRight);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickchecklabel_p.cpp"
diff --git a/src/quickcontrols2impl/qquickchecklabel_p.h b/src/quickcontrols2impl/qquickchecklabel_p.h
new file mode 100644
index 0000000000..823ce9df49
--- /dev/null
+++ b/src/quickcontrols2impl/qquickchecklabel_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCHECKLABEL_P_H
+#define QQUICKCHECKLABEL_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/qquicktext_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickCheckLabel : public QQuickText
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(CheckLabel)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickCheckLabel(QQuickItem *parent = nullptr);
+};
+
+struct QQuickTextForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickText)
+ QML_ADDED_IN_VERSION(2, 3)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickCheckLabel)
+
+#endif // QQUICKCHECKLABEL_P_H
diff --git a/src/quickcontrols2impl/qquickclippedtext.cpp b/src/quickcontrols2impl/qquickclippedtext.cpp
new file mode 100644
index 0000000000..b7fb34102a
--- /dev/null
+++ b/src/quickcontrols2impl/qquickclippedtext.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickclippedtext_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickClippedText::QQuickClippedText(QQuickItem *parent)
+ : QQuickText(parent)
+{
+}
+
+qreal QQuickClippedText::clipX() const
+{
+ return m_clipX;
+}
+
+void QQuickClippedText::setClipX(qreal x)
+{
+ if (qFuzzyCompare(x, m_clipX))
+ return;
+
+ m_clipX = x;
+ markClipDirty();
+}
+
+qreal QQuickClippedText::clipY() const
+{
+ return m_clipY;
+}
+
+void QQuickClippedText::setClipY(qreal y)
+{
+ if (qFuzzyCompare(y, m_clipY))
+ return;
+
+ m_clipY = y;
+ markClipDirty();
+}
+
+qreal QQuickClippedText::clipWidth() const
+{
+ return m_clipWidth ? m_clipWidth : width();
+}
+
+void QQuickClippedText::setClipWidth(qreal width)
+{
+ m_hasClipWidth = true;
+ if (qFuzzyCompare(width, m_clipWidth))
+ return;
+
+ m_clipWidth = width;
+ markClipDirty();
+}
+
+qreal QQuickClippedText::clipHeight() const
+{
+ return m_clipHeight ? m_clipHeight : height();
+}
+
+void QQuickClippedText::setClipHeight(qreal height)
+{
+ m_hasClipHeight = true;
+ if (qFuzzyCompare(height, m_clipHeight))
+ return;
+
+ m_clipHeight = height;
+ markClipDirty();
+}
+
+QRectF QQuickClippedText::clipRect() const
+{
+ return QRectF(clipX(), clipY(), clipWidth(), clipHeight());
+}
+
+void QQuickClippedText::markClipDirty()
+{
+ QQuickItemPrivate::get(this)->dirty(QQuickItemPrivate::Size);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickclippedtext_p.cpp"
diff --git a/src/quickcontrols2impl/qquickclippedtext_p.h b/src/quickcontrols2impl/qquickclippedtext_p.h
new file mode 100644
index 0000000000..f3b011fd9d
--- /dev/null
+++ b/src/quickcontrols2impl/qquickclippedtext_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCLIPPEDTEXT_P_H
+#define QQUICKCLIPPEDTEXT_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/qquicktext_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickClippedText : public QQuickText
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal clipX READ clipX WRITE setClipX FINAL)
+ Q_PROPERTY(qreal clipY READ clipY WRITE setClipY FINAL)
+ Q_PROPERTY(qreal clipWidth READ clipWidth WRITE setClipWidth FINAL)
+ Q_PROPERTY(qreal clipHeight READ clipHeight WRITE setClipHeight FINAL)
+ QML_NAMED_ELEMENT(ClippedText)
+ QML_ADDED_IN_VERSION(2, 2)
+
+public:
+ explicit QQuickClippedText(QQuickItem *parent = nullptr);
+
+ qreal clipX() const;
+ void setClipX(qreal x);
+
+ qreal clipY() const;
+ void setClipY(qreal y);
+
+ qreal clipWidth() const;
+ void setClipWidth(qreal width);
+
+ qreal clipHeight() const;
+ void setClipHeight(qreal height);
+
+ QRectF clipRect() const override;
+
+private:
+ void markClipDirty();
+
+ bool m_hasClipWidth = false;
+ bool m_hasClipHeight = false;
+ qreal m_clipX = 0;
+ qreal m_clipY = 0;
+ qreal m_clipWidth = 0;
+ qreal m_clipHeight = 0;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickClippedText)
+
+#endif // QQUICKCLIPPEDTEXT_P_H
diff --git a/src/quickcontrols2impl/qquickcolor.cpp b/src/quickcontrols2impl/qquickcolor.cpp
new file mode 100644
index 0000000000..cbd4233ccc
--- /dev/null
+++ b/src/quickcontrols2impl/qquickcolor.cpp
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcolor_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickColor::QQuickColor(QObject *parent) :
+ QObject(parent)
+{
+}
+
+QColor QQuickColor::transparent(const QColor &color, qreal opacity) const
+{
+ return QColor(color.red(), color.green(), color.blue(),
+ int(qreal(255) * qBound(qreal(0), opacity, qreal(1))));
+}
+
+QColor QQuickColor::blend(const QColor &a, const QColor &b, qreal factor) const
+{
+ if (factor <= 0.0)
+ return a;
+ if (factor >= 1.0)
+ return b;
+
+ QColor color;
+ color.setRedF(a.redF() * (1.0 - factor) + b.redF() * factor);
+ color.setGreenF(a.greenF() * (1.0 - factor) + b.greenF() * factor);
+ color.setBlueF(a.blueF() * (1.0 - factor) + b.blueF() * factor);
+ return color;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcolor_p.cpp"
diff --git a/src/quickcontrols2impl/qquickcolor_p.h b/src/quickcontrols2impl/qquickcolor_p.h
new file mode 100644
index 0000000000..cd69d0d8e7
--- /dev/null
+++ b/src/quickcontrols2impl/qquickcolor_p.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCOLOR_P_H
+#define QQUICKCOLOR_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 <QtGui/qcolor.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickColor : public QObject
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Color)
+ QML_SINGLETON
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickColor(QObject *parent = nullptr);
+
+ Q_INVOKABLE QColor transparent(const QColor &color, qreal opacity) const;
+ Q_INVOKABLE QColor blend(const QColor &a, const QColor &b, qreal factor) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKCOLOR_P_H
diff --git a/src/quickcontrols2impl/qquickcolorimage.cpp b/src/quickcontrols2impl/qquickcolorimage.cpp
new file mode 100644
index 0000000000..8b9ad0e04f
--- /dev/null
+++ b/src/quickcontrols2impl/qquickcolorimage.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcolorimage_p.h"
+
+#include <QtQuick/private/qquickimagebase_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickColorImage::QQuickColorImage(QQuickItem *parent)
+ : QQuickImage(parent)
+{
+}
+
+QColor QQuickColorImage::color() const
+{
+ return m_color;
+}
+
+void QQuickColorImage::setColor(const QColor &color)
+{
+ if (m_color == color)
+ return;
+
+ m_color = color;
+ if (isComponentComplete())
+ load();
+ emit colorChanged();
+}
+
+void QQuickColorImage::resetColor()
+{
+ setColor(Qt::transparent);
+}
+
+QColor QQuickColorImage::defaultColor() const
+{
+ return m_defaultColor;
+}
+
+void QQuickColorImage::setDefaultColor(const QColor &color)
+{
+ if (m_defaultColor == color)
+ return;
+
+ m_defaultColor = color;
+ emit defaultColorChanged();
+}
+
+void QQuickColorImage::resetDefaultColor()
+{
+ setDefaultColor(Qt::transparent);
+}
+
+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();
+ if (!image.isNull()) {
+ QPainter painter(&image);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ painter.fillRect(image.rect(), m_color);
+ d->pix.setImage(image);
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcolorimage_p.cpp"
diff --git a/src/quickcontrols2impl/qquickcolorimage_p.h b/src/quickcontrols2impl/qquickcolorimage_p.h
new file mode 100644
index 0000000000..faa2e42ccf
--- /dev/null
+++ b/src/quickcontrols2impl/qquickcolorimage_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCOLORIMAGE_P_H
+#define QQUICKCOLORIMAGE_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/private/qquickimage_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickColorImage : public QQuickImage
+{
+ Q_OBJECT
+ Q_PROPERTY(QColor color READ color WRITE setColor RESET resetColor NOTIFY colorChanged FINAL)
+ Q_PROPERTY(QColor defaultColor READ defaultColor WRITE setDefaultColor RESET resetDefaultColor NOTIFY defaultColorChanged FINAL)
+ QML_NAMED_ELEMENT(ColorImage)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickColorImage(QQuickItem *parent = nullptr);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+ void resetColor();
+
+ QColor defaultColor() const;
+ void setDefaultColor(const QColor &color);
+ void resetDefaultColor();
+
+Q_SIGNALS:
+ void colorChanged();
+ void defaultColorChanged();
+
+protected:
+ void pixmapChange() override;
+
+private:
+ QColor m_color = Qt::transparent;
+ QColor m_defaultColor = Qt::transparent;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKCOLORIMAGE_P_H
diff --git a/src/quickcontrols2impl/qquickiconimage.cpp b/src/quickcontrols2impl/qquickiconimage.cpp
new file mode 100644
index 0000000000..c7c7fa628e
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconimage.cpp
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickiconimage_p.h"
+#include "qquickiconimage_p_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtQuick/private/qquickimagebase_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickIconImagePrivate::~QQuickIconImagePrivate()
+{
+ qDeleteAll(icon.entries);
+ icon.entries.clear();
+}
+
+bool QQuickIconImagePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio)
+{
+ if (isThemeIcon) {
+ devicePixelRatio = calculateDevicePixelRatio();
+ return true;
+ }
+
+ return QQuickImagePrivate::updateDevicePixelRatio(targetDevicePixelRatio);
+}
+
+void QQuickIconImagePrivate::updateIcon()
+{
+ Q_Q(QQuickIconImage);
+ // Both geometryChange() and QQuickImageBase::sourceSizeChanged()
+ // (which we connect to updateIcon() in the constructor) can be called as a result
+ // of updateIcon() changing the various sizes, so we must check that we're not recursing.
+ if (updatingIcon)
+ return;
+
+ updatingIcon = true;
+
+ QSize size = sourcesize;
+ // If no size is specified for theme icons, it will use the smallest available size.
+ if (size.width() <= 0)
+ size.setWidth(q->width());
+ if (size.height() <= 0)
+ size.setHeight(q->height());
+
+ const qreal dpr = calculateDevicePixelRatio();
+ const QIconLoaderEngineEntry *entry = QIconLoaderEngine::entryForSize(icon, size * dpr, qCeil(dpr));
+
+ if (entry) {
+ QQmlContext *context = qmlContext(q);
+ const QUrl entryUrl = QUrl::fromLocalFile(entry->filename);
+ url = context ? context->resolvedUrl(entryUrl) : entryUrl;
+ isThemeIcon = true;
+ } else {
+ url = source;
+ isThemeIcon = false;
+ }
+ q->load();
+
+ updatingIcon = false;
+}
+
+void QQuickIconImagePrivate::updateFillMode()
+{
+ Q_Q(QQuickIconImage);
+ // If we start with a sourceSize of 28x28 and then set sourceSize.width to 24, the fillMode
+ // will change to PreserveAspectFit (because pixmapSize.width() > width()), which causes the
+ // pixmap to be reloaded at its original size of 28x28, which causes the fillMode to change
+ // to Pad (because pixmapSize.width() <= width()), and so on.
+ if (updatingFillMode)
+ return;
+
+ updatingFillMode = true;
+
+ const QSize pixmapSize = QSize(pix.width(), pix.height()) / calculateDevicePixelRatio();
+ if (pixmapSize.width() > q->width() || pixmapSize.height() > q->height())
+ q->setFillMode(QQuickImage::PreserveAspectFit);
+ else
+ q->setFillMode(QQuickImage::Pad);
+
+ updatingFillMode = false;
+}
+
+qreal QQuickIconImagePrivate::calculateDevicePixelRatio() const
+{
+ Q_Q(const QQuickIconImage);
+ return q->window() ? q->window()->effectiveDevicePixelRatio() : qApp->devicePixelRatio();
+}
+
+QQuickIconImage::QQuickIconImage(QQuickItem *parent)
+ : QQuickImage(*(new QQuickIconImagePrivate), parent)
+{
+ setFillMode(Pad);
+}
+
+QString QQuickIconImage::name() const
+{
+ Q_D(const QQuickIconImage);
+ return d->icon.iconName;
+}
+
+void QQuickIconImage::setName(const QString &name)
+{
+ Q_D(QQuickIconImage);
+ if (d->icon.iconName == name)
+ return;
+
+ qDeleteAll(d->icon.entries);
+ d->icon = QIconLoader::instance()->loadIcon(name);
+ if (isComponentComplete())
+ d->updateIcon();
+ emit nameChanged();
+}
+
+QColor QQuickIconImage::color() const
+{
+ Q_D(const QQuickIconImage);
+ return d->color;
+}
+
+void QQuickIconImage::setColor(const QColor &color)
+{
+ Q_D(QQuickIconImage);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ if (isComponentComplete())
+ d->updateIcon();
+ emit colorChanged();
+}
+
+void QQuickIconImage::setSource(const QUrl &source)
+{
+ Q_D(QQuickIconImage);
+ if (d->source == source)
+ return;
+
+ d->source = source;
+ if (isComponentComplete())
+ d->updateIcon();
+ emit sourceChanged(source);
+}
+
+void QQuickIconImage::componentComplete()
+{
+ Q_D(QQuickIconImage);
+ QQuickImage::componentComplete();
+ d->updateIcon();
+ QObjectPrivate::connect(this, &QQuickImageBase::sourceSizeChanged, d, &QQuickIconImagePrivate::updateIcon);
+}
+
+void QQuickIconImage::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickIconImage);
+ QQuickImage::geometryChange(newGeometry, oldGeometry);
+ if (isComponentComplete() && newGeometry.size() != oldGeometry.size())
+ d->updateIcon();
+}
+
+void QQuickIconImage::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QQuickIconImage);
+ if (change == ItemDevicePixelRatioHasChanged)
+ d->updateIcon();
+ QQuickImage::itemChange(change, value);
+}
+
+void QQuickIconImage::pixmapChange()
+{
+ Q_D(QQuickIconImage);
+ QQuickImage::pixmapChange();
+ d->updateFillMode();
+
+ // 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();
+ if (!image.isNull()) {
+ QPainter painter(&image);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ painter.fillRect(image.rect(), d->color);
+ d->pix.setImage(image);
+ }
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickiconimage_p.cpp"
diff --git a/src/quickcontrols2impl/qquickiconimage_p.h b/src/quickcontrols2impl/qquickiconimage_p.h
new file mode 100644
index 0000000000..37891476d5
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconimage_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKICONIMAGE_P_H
+#define QQUICKICONIMAGE_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/qquickimage_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIconImagePrivate;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickIconImage : public QQuickImage
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL)
+ QML_NAMED_ELEMENT(IconImage)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickIconImage(QQuickItem *parent = nullptr);
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ void setSource(const QUrl &url) override;
+
+Q_SIGNALS:
+ void nameChanged();
+ void colorChanged();
+
+protected:
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void pixmapChange() override;
+
+private:
+ Q_DISABLE_COPY(QQuickIconImage)
+ Q_DECLARE_PRIVATE(QQuickIconImage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickIconImage)
+
+#endif // QQUICKICONIMAGE_P_H
diff --git a/src/quickcontrols2impl/qquickiconimage_p_p.h b/src/quickcontrols2impl/qquickiconimage_p_p.h
new file mode 100644
index 0000000000..22c51c070f
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconimage_p_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKICONIMAGE_P_P_H
+#define QQUICKICONIMAGE_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/qquickimage_p_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+#include <QtGui/private/qiconloader_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickIconImagePrivate : public QQuickImagePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickIconImage)
+
+public:
+ ~QQuickIconImagePrivate() override;
+ void updateIcon();
+ void updateFillMode();
+ qreal calculateDevicePixelRatio() const;
+ bool updateDevicePixelRatio(qreal targetDevicePixelRatio) override;
+
+ QUrl source;
+ QColor color = Qt::transparent;
+ QThemeIconInfo icon;
+ bool updatingIcon = false;
+ bool isThemeIcon = false;
+ bool updatingFillMode = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKICONIMAGE_P_P_H
diff --git a/src/quickcontrols2impl/qquickiconlabel.cpp b/src/quickcontrols2impl/qquickiconlabel.cpp
new file mode 100644
index 0000000000..7e57a4e68e
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconlabel.cpp
@@ -0,0 +1,645 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickiconlabel_p.h"
+#include "qquickiconlabel_p_p.h"
+#include "qquickiconimage_p.h"
+#include "qquickmnemoniclabel_p.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquicktext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static void beginClass(QQuickItem *item)
+{
+ if (QQmlParserStatus *parserStatus = qobject_cast<QQmlParserStatus *>(item))
+ parserStatus->classBegin();
+}
+
+static void completeComponent(QQuickItem *item)
+{
+ if (QQmlParserStatus *parserStatus = qobject_cast<QQmlParserStatus *>(item))
+ parserStatus->componentComplete();
+}
+
+bool QQuickIconLabelPrivate::hasIcon() const
+{
+ return display != QQuickIconLabel::TextOnly && !icon.isEmpty();
+}
+
+bool QQuickIconLabelPrivate::hasText() const
+{
+ return display != QQuickIconLabel::IconOnly && !text.isEmpty();
+}
+
+bool QQuickIconLabelPrivate::createImage()
+{
+ Q_Q(QQuickIconLabel);
+ if (image)
+ return false;
+
+ image = new QQuickIconImage(q);
+ watchChanges(image);
+ beginClass(image);
+ image->setObjectName(QStringLiteral("image"));
+ image->setName(icon.name());
+ image->setSource(icon.resolvedSource());
+ image->setSourceSize(QSize(icon.width(), icon.height()));
+ image->setColor(icon.color());
+ image->setCache(icon.cache());
+ QQmlEngine::setContextForObject(image, qmlContext(q));
+ if (componentComplete)
+ completeComponent(image);
+ return true;
+}
+
+bool QQuickIconLabelPrivate::destroyImage()
+{
+ if (!image)
+ return false;
+
+ unwatchChanges(image);
+ delete image;
+ image = nullptr;
+ return true;
+}
+
+bool QQuickIconLabelPrivate::updateImage()
+{
+ if (!hasIcon())
+ return destroyImage();
+ return createImage();
+}
+
+void QQuickIconLabelPrivate::syncImage()
+{
+ if (!image || icon.isEmpty())
+ return;
+
+ image->setName(icon.name());
+ image->setSource(icon.resolvedSource());
+ image->setSourceSize(QSize(icon.width(), icon.height()));
+ image->setColor(icon.color());
+ image->setCache(icon.cache());
+ const int valign = alignment & Qt::AlignVertical_Mask;
+ image->setVerticalAlignment(static_cast<QQuickImage::VAlignment>(valign));
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ image->setHorizontalAlignment(static_cast<QQuickImage::HAlignment>(halign));
+}
+
+void QQuickIconLabelPrivate::updateOrSyncImage()
+{
+ if (updateImage()) {
+ if (componentComplete) {
+ updateImplicitSize();
+ layout();
+ }
+ } else {
+ syncImage();
+ }
+}
+
+bool QQuickIconLabelPrivate::createLabel()
+{
+ Q_Q(QQuickIconLabel);
+ if (label)
+ return false;
+
+ label = new QQuickMnemonicLabel(q);
+ watchChanges(label);
+ beginClass(label);
+ label->setObjectName(QStringLiteral("label"));
+ label->setFont(font);
+ label->setColor(color);
+ label->setElideMode(QQuickText::ElideRight);
+ const int valign = alignment & Qt::AlignVertical_Mask;
+ label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
+ label->setText(text);
+ if (componentComplete)
+ completeComponent(label);
+ return true;
+}
+
+bool QQuickIconLabelPrivate::destroyLabel()
+{
+ if (!label)
+ return false;
+
+ unwatchChanges(label);
+ delete label;
+ label = nullptr;
+ return true;
+}
+
+bool QQuickIconLabelPrivate::updateLabel()
+{
+ if (!hasText())
+ return destroyLabel();
+ return createLabel();
+}
+
+void QQuickIconLabelPrivate::syncLabel()
+{
+ if (!label)
+ return;
+
+ label->setText(text);
+}
+
+void QQuickIconLabelPrivate::updateOrSyncLabel()
+{
+ if (updateLabel()) {
+ if (componentComplete) {
+ updateImplicitSize();
+ layout();
+ }
+ } else {
+ syncLabel();
+ }
+}
+
+void QQuickIconLabelPrivate::updateImplicitSize()
+{
+ Q_Q(QQuickIconLabel);
+ const bool showIcon = image && hasIcon();
+ const bool showText = label && hasText();
+ const qreal horizontalPadding = leftPadding + rightPadding;
+ const qreal verticalPadding = topPadding + bottomPadding;
+ const qreal iconImplicitWidth = showIcon ? image->implicitWidth() : 0;
+ const qreal iconImplicitHeight = showIcon ? image->implicitHeight() : 0;
+ const qreal textImplicitWidth = showText ? label->implicitWidth() : 0;
+ const qreal textImplicitHeight = showText ? label->implicitHeight() : 0;
+ const qreal effectiveSpacing = showText && showIcon && image->implicitWidth() > 0 ? spacing : 0;
+ const qreal implicitWidth = display == QQuickIconLabel::TextBesideIcon ? iconImplicitWidth + textImplicitWidth + effectiveSpacing
+ : qMax(iconImplicitWidth, textImplicitWidth);
+ const qreal implicitHeight = display == QQuickIconLabel::TextUnderIcon ? iconImplicitHeight + textImplicitHeight + effectiveSpacing
+ : qMax(iconImplicitHeight, textImplicitHeight);
+ q->setImplicitSize(implicitWidth + horizontalPadding, implicitHeight + verticalPadding);
+}
+
+// adapted from QStyle::alignedRect()
+static QRectF alignedRect(bool mirrored, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
+{
+ alignment = QGuiApplicationPrivate::visualAlignment(mirrored ? Qt::RightToLeft : Qt::LeftToRight, alignment);
+ qreal x = rectangle.x();
+ qreal y = rectangle.y();
+ const qreal w = size.width();
+ const qreal h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += rectangle.height() / 2 - h / 2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rectangle.height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rectangle.width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += rectangle.width() / 2 - w / 2;
+ return QRectF(x, y, w, h);
+}
+
+void QQuickIconLabelPrivate::layout()
+{
+ Q_Q(QQuickIconLabel);
+ if (!componentComplete)
+ return;
+
+ const qreal availableWidth = width - leftPadding - rightPadding;
+ const qreal availableHeight = height - topPadding - bottomPadding;
+
+ switch (display) {
+ case QQuickIconLabel::IconOnly:
+ if (image) {
+ const QRectF iconRect = alignedRect(mirrored, alignment,
+ QSizeF(qMin(image->implicitWidth(), availableWidth),
+ qMin(image->implicitHeight(), availableHeight)),
+ QRectF(leftPadding, topPadding, availableWidth, availableHeight));
+ image->setSize(iconRect.size());
+ image->setPosition(iconRect.topLeft());
+ }
+ break;
+ case QQuickIconLabel::TextOnly:
+ if (label) {
+ const QRectF textRect = alignedRect(mirrored, alignment,
+ QSizeF(qMin(label->implicitWidth(), availableWidth),
+ qMin(label->implicitHeight(), availableHeight)),
+ QRectF(leftPadding, topPadding, availableWidth, availableHeight));
+ label->setSize(textRect.size());
+ label->setPosition(textRect.topLeft());
+ }
+ break;
+
+ case QQuickIconLabel::TextUnderIcon: {
+ // Work out the sizes first, as the positions depend on them.
+ QSizeF iconSize;
+ QSizeF textSize;
+ if (image) {
+ iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
+ iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
+ }
+ qreal effectiveSpacing = 0;
+ if (label) {
+ if (!iconSize.isEmpty())
+ effectiveSpacing = spacing;
+ textSize.setWidth(qMin(label->implicitWidth(), availableWidth));
+ textSize.setHeight(qMin(label->implicitHeight(), availableHeight - iconSize.height() - effectiveSpacing));
+ }
+
+ QRectF combinedRect = alignedRect(mirrored, alignment,
+ QSizeF(qMax(iconSize.width(), textSize.width()),
+ iconSize.height() + effectiveSpacing + textSize.height()),
+ QRectF(leftPadding, topPadding, availableWidth, availableHeight));
+ if (image) {
+ QRectF iconRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignTop, iconSize, combinedRect);
+ image->setSize(iconRect.size());
+ image->setPosition(iconRect.topLeft());
+ }
+ if (label) {
+ QRectF textRect = alignedRect(mirrored, Qt::AlignHCenter | Qt::AlignBottom, textSize, combinedRect);
+ label->setSize(textRect.size());
+ label->setPosition(textRect.topLeft());
+ }
+ break;
+ }
+
+ case QQuickIconLabel::TextBesideIcon:
+ default:
+ // Work out the sizes first, as the positions depend on them.
+ QSizeF iconSize(0, 0);
+ QSizeF textSize(0, 0);
+ if (image) {
+ iconSize.setWidth(qMin(image->implicitWidth(), availableWidth));
+ iconSize.setHeight(qMin(image->implicitHeight(), availableHeight));
+ }
+ qreal effectiveSpacing = 0;
+ if (label) {
+ if (!iconSize.isEmpty())
+ effectiveSpacing = spacing;
+ textSize.setWidth(qMin(label->implicitWidth(), availableWidth - iconSize.width() - effectiveSpacing));
+ textSize.setHeight(qMin(label->implicitHeight(), availableHeight));
+ }
+
+ const QRectF combinedRect = alignedRect(mirrored, alignment,
+ QSizeF(iconSize.width() + effectiveSpacing + textSize.width(),
+ qMax(iconSize.height(), textSize.height())),
+ QRectF(leftPadding, topPadding, availableWidth, availableHeight));
+ if (image) {
+ const QRectF iconRect = alignedRect(mirrored, Qt::AlignLeft | Qt::AlignVCenter, iconSize, combinedRect);
+ image->setSize(iconRect.size());
+ image->setPosition(iconRect.topLeft());
+ }
+ if (label) {
+ const QRectF textRect = alignedRect(mirrored, Qt::AlignRight | Qt::AlignVCenter, textSize, combinedRect);
+ label->setSize(textRect.size());
+ label->setPosition(textRect.topLeft());
+ }
+ break;
+ }
+
+ q->setBaselineOffset(label ? label->y() + label->baselineOffset() : 0);
+}
+
+static const QQuickItemPrivate::ChangeTypes itemChangeTypes =
+ QQuickItemPrivate::ImplicitWidth
+ | QQuickItemPrivate::ImplicitHeight
+ | QQuickItemPrivate::Destroyed;
+
+void QQuickIconLabelPrivate::watchChanges(QQuickItem *item)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, itemChangeTypes);
+}
+
+void QQuickIconLabelPrivate::unwatchChanges(QQuickItem* item)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(this, itemChangeTypes);
+}
+
+void QQuickIconLabelPrivate::itemImplicitWidthChanged(QQuickItem *)
+{
+ updateImplicitSize();
+ layout();
+}
+
+void QQuickIconLabelPrivate::itemImplicitHeightChanged(QQuickItem *)
+{
+ updateImplicitSize();
+ layout();
+}
+
+void QQuickIconLabelPrivate::itemDestroyed(QQuickItem *item)
+{
+ unwatchChanges(item);
+ if (item == image)
+ image = nullptr;
+ else if (item == label)
+ label = nullptr;
+}
+
+QQuickIconLabel::QQuickIconLabel(QQuickItem *parent)
+ : QQuickItem(*(new QQuickIconLabelPrivate), parent)
+{
+}
+
+QQuickIconLabel::~QQuickIconLabel()
+{
+ Q_D(QQuickIconLabel);
+ if (d->image)
+ d->unwatchChanges(d->image);
+ if (d->label)
+ d->unwatchChanges(d->label);
+}
+
+QQuickIcon QQuickIconLabel::icon() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->icon;
+}
+
+void QQuickIconLabel::setIcon(const QQuickIcon &icon)
+{
+ Q_D(QQuickIconLabel);
+ if (d->icon == icon)
+ return;
+
+ d->icon = icon;
+ d->icon.ensureRelativeSourceResolved(this);
+ d->updateOrSyncImage();
+}
+
+QString QQuickIconLabel::text() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->text;
+}
+
+void QQuickIconLabel::setText(const QString &text)
+{
+ Q_D(QQuickIconLabel);
+ if (d->text == text)
+ return;
+
+ d->text = text;
+ d->updateOrSyncLabel();
+}
+
+QFont QQuickIconLabel::font() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->font;
+}
+
+void QQuickIconLabel::setFont(const QFont &font)
+{
+ Q_D(QQuickIconLabel);
+ if (d->font == font)
+ return;
+
+ d->font = font;
+ if (d->label)
+ d->label->setFont(font);
+}
+
+QColor QQuickIconLabel::color() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->color;
+}
+
+void QQuickIconLabel::setColor(const QColor &color)
+{
+ Q_D(QQuickIconLabel);
+ if (d->color == color)
+ return;
+
+ d->color = color;
+ if (d->label)
+ d->label->setColor(color);
+}
+
+QQuickIconLabel::Display QQuickIconLabel::display() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->display;
+}
+
+void QQuickIconLabel::setDisplay(Display display)
+{
+ Q_D(QQuickIconLabel);
+ if (d->display == display)
+ return;
+
+ d->display = display;
+ d->updateImage();
+ d->updateLabel();
+ d->updateImplicitSize();
+ d->layout();
+}
+
+qreal QQuickIconLabel::spacing() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->spacing;
+}
+
+void QQuickIconLabel::setSpacing(qreal spacing)
+{
+ Q_D(QQuickIconLabel);
+ if (qFuzzyCompare(d->spacing, spacing))
+ return;
+
+ d->spacing = spacing;
+ if (d->image && d->label) {
+ d->updateImplicitSize();
+ d->layout();
+ }
+}
+
+bool QQuickIconLabel::isMirrored() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->mirrored;
+}
+
+void QQuickIconLabel::setMirrored(bool mirrored)
+{
+ Q_D(QQuickIconLabel);
+ if (d->mirrored == mirrored)
+ return;
+
+ d->mirrored = mirrored;
+ d->layout();
+}
+
+Qt::Alignment QQuickIconLabel::alignment() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->alignment;
+}
+
+void QQuickIconLabel::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QQuickIconLabel);
+ const int valign = alignment & Qt::AlignVertical_Mask;
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ const uint align = (valign ? valign : Qt::AlignVCenter) | (halign ? halign : Qt::AlignHCenter);
+ if (d->alignment == align)
+ return;
+
+ d->alignment = static_cast<Qt::Alignment>(align);
+ if (d->label) {
+ d->label->setVAlign(static_cast<QQuickText::VAlignment>(valign));
+ d->label->setHAlign(static_cast<QQuickText::HAlignment>(halign));
+ }
+ if (d->image) {
+ d->image->setVerticalAlignment(static_cast<QQuickImage::VAlignment>(valign));
+ d->image->setHorizontalAlignment(static_cast<QQuickImage::HAlignment>(halign));
+ }
+ d->layout();
+}
+
+qreal QQuickIconLabel::topPadding() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->topPadding;
+}
+
+void QQuickIconLabel::setTopPadding(qreal padding)
+{
+ Q_D(QQuickIconLabel);
+ if (qFuzzyCompare(d->topPadding, padding))
+ return;
+
+ d->topPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+}
+
+void QQuickIconLabel::resetTopPadding()
+{
+ setTopPadding(0);
+}
+
+qreal QQuickIconLabel::leftPadding() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->leftPadding;
+}
+
+void QQuickIconLabel::setLeftPadding(qreal padding)
+{
+ Q_D(QQuickIconLabel);
+ if (qFuzzyCompare(d->leftPadding, padding))
+ return;
+
+ d->leftPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+}
+
+void QQuickIconLabel::resetLeftPadding()
+{
+ setLeftPadding(0);
+}
+
+qreal QQuickIconLabel::rightPadding() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->rightPadding;
+}
+
+void QQuickIconLabel::setRightPadding(qreal padding)
+{
+ Q_D(QQuickIconLabel);
+ if (qFuzzyCompare(d->rightPadding, padding))
+ return;
+
+ d->rightPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+}
+
+void QQuickIconLabel::resetRightPadding()
+{
+ setRightPadding(0);
+}
+
+qreal QQuickIconLabel::bottomPadding() const
+{
+ Q_D(const QQuickIconLabel);
+ return d->bottomPadding;
+}
+
+void QQuickIconLabel::setBottomPadding(qreal padding)
+{
+ Q_D(QQuickIconLabel);
+ if (qFuzzyCompare(d->bottomPadding, padding))
+ return;
+
+ d->bottomPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+}
+
+void QQuickIconLabel::resetBottomPadding()
+{
+ setBottomPadding(0);
+}
+
+void QQuickIconLabel::componentComplete()
+{
+ Q_D(QQuickIconLabel);
+ if (d->image)
+ completeComponent(d->image);
+ if (d->label)
+ completeComponent(d->label);
+ QQuickItem::componentComplete();
+ d->layout();
+}
+
+void QQuickIconLabel::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickIconLabel);
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ d->layout();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickiconlabel_p.cpp"
diff --git a/src/quickcontrols2impl/qquickiconlabel_p.h b/src/quickcontrols2impl/qquickiconlabel_p.h
new file mode 100644
index 0000000000..1ea0affb42
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconlabel_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKICONLABEL_P_H
+#define QQUICKICONLABEL_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/qquickitem.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIconLabelPrivate;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickIconLabel : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickIcon icon READ icon WRITE setIcon FINAL)
+ Q_PROPERTY(QString text READ text WRITE setText FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor FINAL)
+ Q_PROPERTY(Display display READ display WRITE setDisplay FINAL)
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing FINAL)
+ Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored FINAL)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment FINAL)
+ Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding FINAL)
+ Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding FINAL)
+ Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding FINAL)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding FINAL)
+ QML_NAMED_ELEMENT(IconLabel)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ enum Display {
+ IconOnly,
+ TextOnly,
+ TextBesideIcon,
+ TextUnderIcon
+ };
+ Q_ENUM(Display)
+
+ explicit QQuickIconLabel(QQuickItem *parent = nullptr);
+ ~QQuickIconLabel();
+
+ QQuickIcon icon() const;
+ void setIcon(const QQuickIcon &icon);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QColor color() const;
+ void setColor(const QColor &color);
+
+ Display display() const;
+ void setDisplay(Display display);
+
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+
+ bool isMirrored() const;
+ void setMirrored(bool mirrored);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment alignment);
+
+ qreal topPadding() const;
+ void setTopPadding(qreal padding);
+ void resetTopPadding();
+
+ qreal leftPadding() const;
+ void setLeftPadding(qreal padding);
+ void resetLeftPadding();
+
+ qreal rightPadding() const;
+ void setRightPadding(qreal padding);
+ void resetRightPadding();
+
+ qreal bottomPadding() const;
+ void setBottomPadding(qreal padding);
+ void resetBottomPadding();
+
+protected:
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private:
+ Q_DISABLE_COPY(QQuickIconLabel)
+ Q_DECLARE_PRIVATE(QQuickIconLabel)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickIconLabel)
+
+#endif // QQUICKICONLABEL_P_H
diff --git a/src/quickcontrols2impl/qquickiconlabel_p_p.h b/src/quickcontrols2impl/qquickiconlabel_p_p.h
new file mode 100644
index 0000000000..d57d49f177
--- /dev/null
+++ b/src/quickcontrols2impl/qquickiconlabel_p_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKICONLABEL_P_P_H
+#define QQUICKICONLABEL_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/qquickitem_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+#include <QtQuickControls2Impl/private/qquickiconlabel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIconImage;
+class QQuickMnemonicLabel;
+
+class Q_AUTOTEST_EXPORT QQuickIconLabelPrivate : public QQuickItemPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickIconLabel)
+
+public:
+ bool hasIcon() const;
+ bool hasText() const;
+
+ bool createImage();
+ bool destroyImage();
+ bool updateImage();
+ void syncImage();
+ void updateOrSyncImage();
+
+ bool createLabel();
+ bool destroyLabel();
+ bool updateLabel();
+ void syncLabel();
+ void updateOrSyncLabel();
+
+ void updateImplicitSize();
+ void layout();
+
+ void watchChanges(QQuickItem *item);
+ void unwatchChanges(QQuickItem *item);
+ void setPositioningDirty();
+
+ bool isLeftToRight() const;
+
+ void itemImplicitWidthChanged(QQuickItem *) override;
+ void itemImplicitHeightChanged(QQuickItem *) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ bool mirrored = false;
+ QQuickIconLabel::Display display = QQuickIconLabel::TextBesideIcon;
+ Qt::Alignment alignment = Qt::AlignCenter;
+ qreal spacing = 0;
+ qreal topPadding = 0;
+ qreal leftPadding = 0;
+ qreal rightPadding = 0;
+ qreal bottomPadding = 0;
+ QFont font;
+ QColor color;
+ QString text;
+ QQuickIcon icon;
+ QQuickIconImage *image = nullptr;
+ QQuickMnemonicLabel *label = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKICONLABEL_P_P_H
diff --git a/src/quickcontrols2impl/qquickitemgroup.cpp b/src/quickcontrols2impl/qquickitemgroup.cpp
new file mode 100644
index 0000000000..1f3be28c7d
--- /dev/null
+++ b/src/quickcontrols2impl/qquickitemgroup.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemgroup_p.h"
+
+#include <QtQuick/private/qquickimplicitsizeitem_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickItemGroup::QQuickItemGroup(QQuickItem *parent)
+ : QQuickImplicitSizeItem(*(new QQuickImplicitSizeItemPrivate), parent)
+{
+}
+
+QQuickItemGroup::~QQuickItemGroup()
+{
+ const auto children = childItems();
+ for (QQuickItem *child : children)
+ unwatch(child);
+}
+
+void QQuickItemGroup::watch(QQuickItem *item)
+{
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+}
+
+void QQuickItemGroup::unwatch(QQuickItem *item)
+{
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+}
+
+QSizeF QQuickItemGroup::calculateImplicitSize() const
+{
+ qreal width = 0;
+ qreal height = 0;
+ const auto children = childItems();
+ for (QQuickItem *child : children) {
+ width = qMax(width, child->implicitWidth());
+ height = qMax(height, child->implicitHeight());
+ }
+ return QSizeF(width, height);
+}
+
+void QQuickItemGroup::updateImplicitSize()
+{
+ QSizeF size = calculateImplicitSize();
+ setImplicitSize(size.width(), size.height());
+}
+
+void QQuickItemGroup::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ QQuickImplicitSizeItem::itemChange(change, data);
+ switch (change) {
+ case ItemChildAddedChange:
+ watch(data.item);
+ data.item->setSize(QSizeF(width(), height()));
+ updateImplicitSize();
+ break;
+ case ItemChildRemovedChange:
+ unwatch(data.item);
+ updateImplicitSize();
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickItemGroup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickImplicitSizeItem::geometryChange(newGeometry, oldGeometry);
+
+ if (newGeometry.size() != oldGeometry.size()) {
+ const auto children = childItems();
+ for (QQuickItem *child : children)
+ child->setSize(newGeometry.size());
+ }
+}
+
+void QQuickItemGroup::itemImplicitWidthChanged(QQuickItem *)
+{
+ setImplicitWidth(calculateImplicitSize().width());
+}
+
+void QQuickItemGroup::itemImplicitHeightChanged(QQuickItem *)
+{
+ setImplicitHeight(calculateImplicitSize().height());
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickitemgroup_p.cpp"
diff --git a/src/quickcontrols2impl/qquickitemgroup_p.h b/src/quickcontrols2impl/qquickitemgroup_p.h
new file mode 100644
index 0000000000..9c04a99074
--- /dev/null
+++ b/src/quickcontrols2impl/qquickitemgroup_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKITEMGROUP_P_H
+#define QQUICKITEMGROUP_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/qquickimplicitsizeitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickItemGroup : public QQuickImplicitSizeItem, protected QQuickItemChangeListener
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ItemGroup)
+ QML_ADDED_IN_VERSION(2, 2)
+
+public:
+ explicit QQuickItemGroup(QQuickItem *parent = nullptr);
+ ~QQuickItemGroup();
+
+protected:
+ void watch(QQuickItem *item);
+ void unwatch(QQuickItem *item);
+
+ QSizeF calculateImplicitSize() const;
+ void updateImplicitSize();
+
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickItemGroup)
+
+#endif // QQUICKITEMGROUP_P_H
diff --git a/src/quickcontrols2impl/qquickmnemoniclabel.cpp b/src/quickcontrols2impl/qquickmnemoniclabel.cpp
new file mode 100644
index 0000000000..798eeae205
--- /dev/null
+++ b/src/quickcontrols2impl/qquickmnemoniclabel.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmnemoniclabel_p.h"
+
+#include <QtQuick/private/qquicktext_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickMnemonicLabel::QQuickMnemonicLabel(QQuickItem *parent)
+ : QQuickText(parent)
+{
+}
+
+QString QQuickMnemonicLabel::text() const
+{
+ return m_fullText;
+}
+
+void QQuickMnemonicLabel::setText(const QString &text)
+{
+ if (m_fullText == text)
+ return;
+
+ m_fullText = text;
+ updateMnemonic();
+}
+
+bool QQuickMnemonicLabel::isMnemonicVisible() const
+{
+ return m_mnemonicVisible;
+}
+
+void QQuickMnemonicLabel::setMnemonicVisible(bool visible)
+{
+ if (m_mnemonicVisible == visible)
+ return;
+
+ m_mnemonicVisible = visible;
+ updateMnemonic();
+
+ if (isComponentComplete())
+ forceLayout();
+}
+
+static QTextLayout::FormatRange underlineRange(int start, int length = 1)
+{
+ QTextLayout::FormatRange range;
+ range.start = start;
+ range.length = length;
+ range.format.setFontUnderline(true);
+ return range;
+}
+
+// based on QPlatformTheme::removeMnemonics()
+void QQuickMnemonicLabel::updateMnemonic()
+{
+ QString text(m_fullText.size(), QChar::Null);
+ int idx = 0;
+ int pos = 0;
+ int len = m_fullText.length();
+ QList<QTextLayout::FormatRange> formats;
+ while (len) {
+ if (m_fullText.at(pos) == QLatin1Char('&') && (len == 1 || m_fullText.at(pos + 1) != QLatin1Char('&'))) {
+ if (m_mnemonicVisible && (pos == 0 || m_fullText.at(pos - 1) != QLatin1Char('&')))
+ formats += underlineRange(pos);
+ ++pos;
+ --len;
+ if (len == 0)
+ break;
+ } else if (m_fullText.at(pos) == QLatin1Char('(') && len >= 4 &&
+ m_fullText.at(pos + 1) == QLatin1Char('&') &&
+ m_fullText.at(pos + 2) != QLatin1Char('&') &&
+ m_fullText.at(pos + 3) == QLatin1Char(')')) {
+ // a mnemonic with format "\s*(&X)"
+ if (m_mnemonicVisible) {
+ formats += underlineRange(pos + 1);
+ } else {
+ int n = 0;
+ while (idx > n && text.at(idx - n - 1).isSpace())
+ ++n;
+ idx -= n;
+ pos += 4;
+ len -= 4;
+ continue;
+ }
+ }
+ text[idx] = m_fullText.at(pos);
+ ++pos;
+ ++idx;
+ --len;
+ }
+ text.truncate(idx);
+
+ QQuickTextPrivate::get(this)->layout.setFormats(formats);
+ QQuickText::setText(text);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmnemoniclabel_p.cpp"
diff --git a/src/quickcontrols2impl/qquickmnemoniclabel_p.h b/src/quickcontrols2impl/qquickmnemoniclabel_p.h
new file mode 100644
index 0000000000..69ddbfb1f7
--- /dev/null
+++ b/src/quickcontrols2impl/qquickmnemoniclabel_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMNEMONICLABEL_P_H
+#define QQUICKMNEMONICLABEL_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/qquicktext_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickMnemonicLabel : public QQuickText
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText FINAL)
+ Q_PROPERTY(bool mnemonicVisible READ isMnemonicVisible WRITE setMnemonicVisible FINAL)
+ QML_NAMED_ELEMENT(MnemonicLabel)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickMnemonicLabel(QQuickItem *parent = nullptr);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ bool isMnemonicVisible() const;
+ void setMnemonicVisible(bool visible);
+
+private:
+ void updateMnemonic();
+
+ bool m_mnemonicVisible = true;
+ QString m_fullText;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMnemonicLabel)
+
+#endif // QQUICKMNEMONICLABEL_P_H
diff --git a/src/quickcontrols2impl/qquickpaddedrectangle.cpp b/src/quickcontrols2impl/qquickpaddedrectangle.cpp
new file mode 100644
index 0000000000..fa3e2ca186
--- /dev/null
+++ b/src/quickcontrols2impl/qquickpaddedrectangle.cpp
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpaddedrectangle_p.h"
+
+#include <QtQuick/private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickPaddedRectangle::QQuickPaddedRectangle(QQuickItem *parent) :
+ QQuickRectangle(parent)
+{
+}
+
+qreal QQuickPaddedRectangle::padding() const
+{
+ return m_padding;
+}
+
+void QQuickPaddedRectangle::setPadding(qreal padding)
+{
+ if (!qFuzzyCompare(m_padding, padding)) {
+ m_padding = padding;
+ update();
+ emit paddingChanged();
+ if (!m_hasTopPadding)
+ emit topPaddingChanged();
+ if (!m_hasLeftPadding)
+ emit leftPaddingChanged();
+ if (!m_hasRightPadding)
+ emit rightPaddingChanged();
+ if (!m_hasBottomPadding)
+ emit bottomPaddingChanged();
+ }
+}
+
+void QQuickPaddedRectangle::resetPadding()
+{
+ setPadding(0);
+}
+
+qreal QQuickPaddedRectangle::topPadding() const
+{
+ return m_hasTopPadding ? m_topPadding : m_padding;
+}
+
+void QQuickPaddedRectangle::setTopPadding(qreal padding)
+{
+ setTopPadding(padding, true);
+}
+
+void QQuickPaddedRectangle::resetTopPadding()
+{
+ setTopPadding(0, false);
+}
+
+qreal QQuickPaddedRectangle::leftPadding() const
+{
+ return m_hasLeftPadding ? m_leftPadding : m_padding;
+}
+
+void QQuickPaddedRectangle::setLeftPadding(qreal padding)
+{
+ setLeftPadding(padding, true);
+}
+
+void QQuickPaddedRectangle::resetLeftPadding()
+{
+ setLeftPadding(0, false);
+}
+
+qreal QQuickPaddedRectangle::rightPadding() const
+{
+ return m_hasRightPadding ? m_rightPadding : m_padding;
+}
+
+void QQuickPaddedRectangle::setRightPadding(qreal padding)
+{
+ setRightPadding(padding, true);
+}
+
+void QQuickPaddedRectangle::resetRightPadding()
+{
+ setRightPadding(0, false);
+}
+
+qreal QQuickPaddedRectangle::bottomPadding() const
+{
+ return m_hasBottomPadding ? m_bottomPadding : m_padding;
+}
+
+void QQuickPaddedRectangle::setBottomPadding(qreal padding)
+{
+ setBottomPadding(padding, true);
+}
+
+void QQuickPaddedRectangle::resetBottomPadding()
+{
+ setBottomPadding(0, false);
+}
+
+void QQuickPaddedRectangle::setTopPadding(qreal padding, bool has)
+{
+ qreal oldPadding = topPadding();
+ m_hasTopPadding = has;
+ m_topPadding = padding;
+ if (!qFuzzyCompare(oldPadding, padding)) {
+ update();
+ emit topPaddingChanged();
+ }
+}
+
+void QQuickPaddedRectangle::setLeftPadding(qreal padding, bool has)
+{
+ qreal oldPadding = leftPadding();
+ m_hasLeftPadding = has;
+ m_leftPadding = padding;
+ if (!qFuzzyCompare(oldPadding, padding)) {
+ update();
+ emit leftPaddingChanged();
+ }
+}
+
+void QQuickPaddedRectangle::setRightPadding(qreal padding, bool has)
+{
+ qreal oldPadding = rightPadding();
+ m_hasRightPadding = has;
+ m_rightPadding = padding;
+ if (!qFuzzyCompare(oldPadding, padding)) {
+ update();
+ emit rightPaddingChanged();
+ }
+}
+
+void QQuickPaddedRectangle::setBottomPadding(qreal padding, bool has)
+{
+ qreal oldPadding = bottomPadding();
+ m_hasBottomPadding = has;
+ m_bottomPadding = padding;
+ if (!qFuzzyCompare(oldPadding, padding)) {
+ update();
+ emit bottomPaddingChanged();
+ }
+}
+
+QSGNode *QQuickPaddedRectangle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *data)
+{
+ QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(node);
+ if (!transformNode)
+ transformNode = new QSGTransformNode;
+
+ QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(QQuickRectangle::updatePaintNode(transformNode->firstChild(), data));
+
+ if (rectNode) {
+ if (!transformNode->firstChild())
+ transformNode->appendChildNode(rectNode);
+
+ qreal top = topPadding();
+ qreal left = leftPadding();
+ qreal right = rightPadding();
+ qreal bottom = bottomPadding();
+
+ if (!qFuzzyIsNull(top) || !qFuzzyIsNull(left) || !qFuzzyIsNull(right) || !qFuzzyIsNull(bottom)) {
+ QMatrix4x4 m;
+ m.translate(left, top);
+ transformNode->setMatrix(m);
+
+ qreal w = qMax<qreal>(0.0, width() -left-right);
+ qreal h = qMax<qreal>(0.0, height() -top-bottom);
+
+ rectNode->setRect(QRectF(0, 0, w, h));
+ rectNode->update();
+ }
+ }
+ return transformNode;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpaddedrectangle_p.cpp"
diff --git a/src/quickcontrols2impl/qquickpaddedrectangle_p.h b/src/quickcontrols2impl/qquickpaddedrectangle_p.h
new file mode 100644
index 0000000000..277432705e
--- /dev/null
+++ b/src/quickcontrols2impl/qquickpaddedrectangle_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPADDEDRECTANGLE_P_H
+#define QQUICKPADDEDRECTANGLE_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/qquickrectangle_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickPaddedRectangle : public QQuickRectangle
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL)
+ Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL)
+ Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL)
+ Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL)
+ QML_NAMED_ELEMENT(PaddedRectangle)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ QQuickPaddedRectangle(QQuickItem *parent = nullptr);
+
+ qreal padding() const;
+ void setPadding(qreal padding);
+ void resetPadding();
+
+ qreal topPadding() const;
+ void setTopPadding(qreal padding);
+ void resetTopPadding();
+
+ qreal leftPadding() const;
+ void setLeftPadding(qreal padding);
+ void resetLeftPadding();
+
+ qreal rightPadding() const;
+ void setRightPadding(qreal padding);
+ void resetRightPadding();
+
+ qreal bottomPadding() const;
+ void setBottomPadding(qreal padding);
+ void resetBottomPadding();
+
+Q_SIGNALS:
+ void paddingChanged();
+ void topPaddingChanged();
+ void leftPaddingChanged();
+ void rightPaddingChanged();
+ void bottomPaddingChanged();
+
+protected:
+ QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override;
+
+private:
+ void setTopPadding(qreal padding, bool has);
+ void setLeftPadding(qreal padding, bool has);
+ void setRightPadding(qreal padding, bool has);
+ void setBottomPadding(qreal padding, bool has);
+
+ qreal m_padding = 0;
+ qreal m_topPadding = 0;
+ qreal m_leftPadding = 0;
+ qreal m_rightPadding = 0;
+ qreal m_bottomPadding = 0;
+ bool m_hasTopPadding = false;
+ bool m_hasLeftPadding = false;
+ bool m_hasRightPadding = false;
+ bool m_hasBottomPadding = false;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPaddedRectangle)
+
+#endif // QQUICKPADDEDRECTANGLE_P_H
diff --git a/src/quickcontrols2impl/qquickplaceholdertext.cpp b/src/quickcontrols2impl/qquickplaceholdertext.cpp
new file mode 100644
index 0000000000..a71fb99eec
--- /dev/null
+++ b/src/quickcontrols2impl/qquickplaceholdertext.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickplaceholdertext_p.h"
+
+#include <QtQuick/private/qquicktext_p_p.h>
+#include <QtQuick/private/qquicktextinput_p_p.h>
+#include <QtQuick/private/qquicktextedit_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickPlaceholderText::QQuickPlaceholderText(QQuickItem *parent) : QQuickText(parent)
+{
+}
+
+void QQuickPlaceholderText::componentComplete()
+{
+ QQuickText::componentComplete();
+ connect(parentItem(), SIGNAL(effectiveHorizontalAlignmentChanged()), this, SLOT(updateAlignment()));
+ updateAlignment();
+}
+
+void QQuickPlaceholderText::updateAlignment()
+{
+ if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(parentItem())) {
+ if (QQuickTextInputPrivate::get(input)->hAlignImplicit)
+ resetHAlign();
+ else
+ setHAlign(static_cast<HAlignment>(input->hAlign()));
+ } else if (QQuickTextEdit *edit = qobject_cast<QQuickTextEdit *>(parentItem())) {
+ if (QQuickTextEditPrivate::get(edit)->hAlignImplicit)
+ resetHAlign();
+ else
+ setHAlign(static_cast<HAlignment>(edit->hAlign()));
+ } else {
+ resetHAlign();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickplaceholdertext_p.cpp"
diff --git a/src/quickcontrols2impl/qquickplaceholdertext_p.h b/src/quickcontrols2impl/qquickplaceholdertext_p.h
new file mode 100644
index 0000000000..0beccd725c
--- /dev/null
+++ b/src/quickcontrols2impl/qquickplaceholdertext_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPLACEHOLDERTEXT_P_H
+#define QQUICKPLACEHOLDERTEXT_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/qquicktext_p.h>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickPlaceholderText : public QQuickText
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(PlaceholderText)
+ QML_ADDED_IN_VERSION(2, 2)
+
+public:
+ explicit QQuickPlaceholderText(QQuickItem *parent = nullptr);
+
+protected:
+ void componentComplete() override;
+
+private Q_SLOTS:
+ void updateAlignment();
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPlaceholderText)
+
+#endif // QQUICKPLACEHOLDERTEXT_P_H
diff --git a/src/quickcontrols2impl/qquicktumblerview.cpp b/src/quickcontrols2impl/qquicktumblerview.cpp
new file mode 100644
index 0000000000..911e2ae8cf
--- /dev/null
+++ b/src/quickcontrols2impl/qquicktumblerview.cpp
@@ -0,0 +1,320 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktumblerview_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquickpathview_p.h>
+
+#include <QtQuickTemplates2/private/qquicktumbler_p.h>
+#include <QtQuickTemplates2/private/qquicktumbler_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTumblerView, "qt.quick.controls.tumblerview")
+
+QQuickTumblerView::QQuickTumblerView(QQuickItem *parent) :
+ QQuickItem(parent)
+{
+ // We don't call createView() here because we don't know what the wrap flag is set to
+ // yet, and we don't want to create a view that might never get used.
+}
+
+QVariant QQuickTumblerView::model() const
+{
+ return m_model;
+}
+
+void QQuickTumblerView::setModel(const QVariant &model)
+{
+ qCDebug(lcTumblerView) << "setting model to:" << model << "on"
+ << (m_pathView ? static_cast<QObject*>(m_pathView) : static_cast<QObject*>(m_listView));
+ if (model == m_model)
+ return;
+
+ m_model = model;
+
+ if (m_pathView) {
+ m_pathView->setModel(m_model);
+ } else if (m_listView) {
+ // QQuickItemView::setModel() resets the current index,
+ // but if we're still creating the Tumbler, it should be maintained.
+ const int oldCurrentIndex = m_listView->currentIndex();
+ m_listView->setModel(m_model);
+ if (!isComponentComplete())
+ m_listView->setCurrentIndex(oldCurrentIndex);
+ }
+
+ emit modelChanged();
+}
+
+QQmlComponent *QQuickTumblerView::delegate() const
+{
+ return m_delegate;
+}
+
+void QQuickTumblerView::setDelegate(QQmlComponent *delegate)
+{
+ qCDebug(lcTumblerView) << "setting delegate to:" << delegate << "on"
+ << (m_pathView ? static_cast<QObject*>(m_pathView) : static_cast<QObject*>(m_listView));
+ if (delegate == m_delegate)
+ return;
+
+ m_delegate = delegate;
+
+ if (m_pathView)
+ m_pathView->setDelegate(m_delegate);
+ else if (m_listView)
+ m_listView->setDelegate(m_delegate);
+
+ emit delegateChanged();
+}
+
+QQuickPath *QQuickTumblerView::path() const
+{
+ return m_path;
+}
+
+void QQuickTumblerView::setPath(QQuickPath *path)
+{
+ if (path == m_path)
+ return;
+
+ m_path = path;
+ emit pathChanged();
+}
+
+void QQuickTumblerView::createView()
+{
+ Q_ASSERT(m_tumbler);
+
+ // We create a view regardless of whether or not we know
+ // the count yet, because we rely on the view to tell us the count.
+ if (m_tumbler->wrap()) {
+ if (m_listView) {
+ // It's necessary to call deleteLater() rather than delete,
+ // as this code is most likely being run in rensponse to a signal
+ // emission somewhere in the list view's internals, so we need to
+ // wait until that has finished.
+ m_listView->deleteLater();
+ QQml_setParent_noEvent(m_listView, nullptr);
+ // The auto tests pass with unparenting the list view alone, but
+ // just to be sure, we unset some other things as well.
+ m_listView->setParentItem(nullptr);
+ m_listView->setVisible(false);
+ m_listView->setModel(QVariant());
+ m_listView = nullptr;
+ }
+
+ if (!m_pathView) {
+ qCDebug(lcTumblerView) << "creating PathView";
+
+ m_pathView = new QQuickPathView;
+ QQmlEngine::setContextForObject(m_pathView, qmlContext(this));
+ QQml_setParent_noEvent(m_pathView, this);
+ m_pathView->setParentItem(this);
+ m_pathView->setPath(m_path);
+ m_pathView->setDelegate(m_delegate);
+ m_pathView->setPreferredHighlightBegin(0.5);
+ m_pathView->setPreferredHighlightEnd(0.5);
+ m_pathView->setHighlightMoveDuration(1000);
+ m_pathView->setClip(true);
+
+ // Give the view a size.
+ updateView();
+ // Set the model.
+ updateModel();
+
+ qCDebug(lcTumblerView) << "finished creating PathView";
+ }
+ } else {
+ if (m_pathView) {
+ m_pathView->deleteLater();
+ QQml_setParent_noEvent(m_pathView, nullptr);
+ m_pathView->setParentItem(nullptr);
+ m_pathView->setVisible(false);
+ m_pathView->setModel(QVariant());
+ m_pathView = nullptr;
+ }
+
+ if (!m_listView) {
+ qCDebug(lcTumblerView) << "creating ListView";
+
+ m_listView = new QQuickListView;
+ QQmlEngine::setContextForObject(m_listView, qmlContext(this));
+ QQml_setParent_noEvent(m_listView, this);
+ m_listView->setParentItem(this);
+ m_listView->setSnapMode(QQuickListView::SnapToItem);
+ m_listView->setClip(true);
+
+ // Give the view a size.
+ updateView();
+ // Set the model.
+ updateModel();
+
+ // Set these after the model is set so that the currentItem animation
+ // happens instantly on startup/after switching models. If we set them too early,
+ // the view animates any potential currentIndex change over one second,
+ // which we don't want when the contentItem has just been created.
+ m_listView->setDelegate(m_delegate);
+ // Set this after setting the delegate to avoid unexpected currentIndex changes: QTBUG-79150
+ m_listView->setHighlightRangeMode(QQuickListView::StrictlyEnforceRange);
+ m_listView->setHighlightMoveDuration(1000);
+
+ qCDebug(lcTumblerView) << "finished creating ListView";
+ }
+ }
+}
+
+// Called whenever the size or visibleItemCount changes.
+void QQuickTumblerView::updateView()
+{
+ QQuickItem *theView = view();
+ if (!theView)
+ return;
+
+ theView->setSize(QSizeF(width(), height()));
+
+ // Can be called in geometryChange when it might not have a parent item yet.
+ if (!m_tumbler)
+ return;
+
+ // Set view-specific properties that have a dependency on the size, etc.
+ if (m_pathView) {
+ m_pathView->setPathItemCount(m_tumbler->visibleItemCount() + 1);
+ m_pathView->setDragMargin(width() / 2);
+ } else {
+ m_listView->setPreferredHighlightBegin(height() / 2 - (height() / m_tumbler->visibleItemCount() / 2));
+ m_listView->setPreferredHighlightEnd(height() / 2 + (height() / m_tumbler->visibleItemCount() / 2));
+ }
+}
+
+void QQuickTumblerView::updateModel()
+{
+ if (m_pathView && !m_pathView->model().isValid() && m_model.isValid()) {
+ // QQuickPathView::setPathItemCount() resets the offset animation,
+ // so we just skip the animation while constructing the view.
+ const int oldHighlightMoveDuration = m_pathView->highlightMoveDuration();
+ m_pathView->setHighlightMoveDuration(0);
+
+ // Setting model can change the count, which can affect the wrap, which can cause
+ // the current view to be deleted before setModel() is finished, which causes a crash.
+ // Since QQuickTumbler can't know about QQuickTumblerView, we use its private API to
+ // inform it that it should delay setting wrap.
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(m_tumbler);
+ tumblerPrivate->beginSetModel();
+ m_pathView->setModel(m_model);
+ tumblerPrivate->endSetModel();
+
+ // The count-depends-on-wrap behavior could cause wrap to change after
+ // the call above, so we must check that we're still using a PathView.
+ if (m_pathView)
+ m_pathView->setHighlightMoveDuration(oldHighlightMoveDuration);
+ } else if (m_listView && !m_listView->model().isValid() && m_model.isValid()) {
+ const int currentIndex = m_tumbler->currentIndex();
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(m_tumbler);
+
+ // setModel() causes QQuickTumblerPrivate::_q_onViewCountChanged() to
+ // be called, which calls QQuickTumbler::setCurrentIndex(),
+ // which results in QQuickItemViewPrivate::createHighlightItem() being
+ // called. When the highlight item is created,
+ // QQuickTumblerPrivate::itemChildAdded() is notified and
+ // QQuickTumblerPrivate::_q_updateItemHeights() is called, which causes
+ // a geometry change in the item and createHighlight() is called again.
+ // However, since the highlight item hadn't been assigned yet in the
+ // previous call frame, the "if (highlight) { delete highlight; }"
+ // check doesn't succeed, so the item is never deleted.
+ //
+ // To avoid this, we tell QQuickTumblerPrivate to ignore signals while
+ // setting the model, and manually call _q_onViewCountChanged() to
+ // ensure the correct sequence of calls happens (_q_onViewCountChanged()
+ // has to be within the ignoreSignals scope, because it also generates
+ // recursion otherwise).
+ tumblerPrivate->ignoreSignals = true;
+ m_listView->setModel(m_model);
+ m_listView->setCurrentIndex(currentIndex);
+
+ tumblerPrivate->_q_onViewCountChanged();
+ tumblerPrivate->ignoreSignals = false;
+ }
+}
+
+void QQuickTumblerView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ updateView();
+}
+
+void QQuickTumblerView::componentComplete()
+{
+ QQuickItem::componentComplete();
+ updateView();
+}
+
+void QQuickTumblerView::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+
+ if (change == QQuickItem::ItemParentHasChanged && data.item) {
+ if (m_tumbler)
+ m_tumbler->disconnect(this);
+
+ m_tumbler = qobject_cast<QQuickTumbler*>(parentItem());
+
+ if (m_tumbler) {
+ // We assume that the parentChanged() signal of the tumbler will be emitted before its wrap property is set...
+ connect(m_tumbler, &QQuickTumbler::wrapChanged, this, &QQuickTumblerView::createView);
+ connect(m_tumbler, &QQuickTumbler::visibleItemCountChanged, this, &QQuickTumblerView::updateView);
+ }
+ }
+}
+
+QQuickItem *QQuickTumblerView::view()
+{
+ if (!m_tumbler)
+ return nullptr;
+
+ if (m_tumbler->wrap())
+ return m_pathView;
+
+ return m_listView;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktumblerview_p.cpp"
diff --git a/src/quickcontrols2impl/qquicktumblerview_p.h b/src/quickcontrols2impl/qquicktumblerview_p.h
new file mode 100644
index 0000000000..44ce5fa626
--- /dev/null
+++ b/src/quickcontrols2impl/qquicktumblerview_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTUMBLERVIEW_P_H
+#define QQUICKTUMBLERVIEW_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 <QQuickItem>
+#include <QtQuickControls2Impl/private/qtquickcontrols2implglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickListView;
+class QQuickPath;
+class QQuickPathView;
+
+class QQuickTumbler;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickTumblerView : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
+ Q_PROPERTY(QQuickPath *path READ path WRITE setPath NOTIFY pathChanged)
+ QML_NAMED_ELEMENT(TumblerView)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ QQuickTumblerView(QQuickItem *parent = nullptr);
+
+ QVariant model() const;
+ void setModel(const QVariant &model);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ QQuickPath *path() const;
+ void setPath(QQuickPath *path);
+
+Q_SIGNALS:
+ void modelChanged();
+ void delegateChanged();
+ void pathChanged();
+
+protected:
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+
+private:
+ QQuickItem *view();
+ void createView();
+ void updateView();
+ void updateModel();
+
+ void wrapChange();
+
+ QQuickTumbler *m_tumbler = nullptr;
+ QVariant m_model;
+ QQmlComponent *m_delegate = nullptr;
+ QQuickPathView *m_pathView = nullptr;
+ QQuickListView *m_listView = nullptr;
+ QQuickPath *m_path = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // TUMBLERVIEW_H
diff --git a/src/quickcontrols2impl/qtquickcontrols2foreign_p.h b/src/quickcontrols2impl/qtquickcontrols2foreign_p.h
new file mode 100644
index 0000000000..d999fc13be
--- /dev/null
+++ b/src/quickcontrols2impl/qtquickcontrols2foreign_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+**
+******************************************************************************/
+#ifndef QTQUICKCONTROLS2FOREIGN_P_H
+
+#include <QtQml/qqml.h>
+#include <QtQuickTemplates2/private/qquickoverlay_p.h>
+#include <QtQuickTemplates2/private/qquicksplitview_p.h>
+
+QT_BEGIN_NAMESPACE
+
+//
+// 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.
+//
+
+// These are necessary in order to use C++ types in a file where only QtQuick.Controls has been imported.
+// Control types like Button don't need this done for them, as each style module provides a Button type,
+// and QtQuick.Controls is a sort of alias for the active style import.
+
+struct QQuickOverlayAttachedForeign
+{
+ Q_GADGET
+ QML_NAMED_ELEMENT(Overlay)
+ QML_FOREIGN(QQuickOverlay)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 3)
+};
+
+struct QQuickSplitHandleAttachedForeign
+{
+ Q_GADGET
+ QML_NAMED_ELEMENT(SplitHandle)
+ QML_FOREIGN(QQuickSplitHandleAttached)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 13)
+};
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKCONTROLS2FOREIGN_P_H
diff --git a/src/quickcontrols2impl/qtquickcontrols2implglobal_p.h b/src/quickcontrols2impl/qtquickcontrols2implglobal_p.h
new file mode 100644
index 0000000000..1065aa7876
--- /dev/null
+++ b/src/quickcontrols2impl/qtquickcontrols2implglobal_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKCONTROLS2IMPLGLOBAL_H
+#define QTQUICKCONTROLS2IMPLGLOBAL_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>
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKCONTROLS2IMPL_LIB)
+# define Q_QUICKCONTROLS2IMPL_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKCONTROLS2IMPL_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKCONTROLS2IMPL_EXPORT
+#endif
+
+#define Q_QUICKCONTROLS2_PRIVATE_EXPORT Q_QUICKCONTROLS2IMPL_EXPORT
+
+#endif // QTQUICKCONTROLS2IMPLGLOBAL_H
diff --git a/src/quickcontrolstestutils/CMakeLists.txt b/src/quickcontrolstestutils/CMakeLists.txt
new file mode 100644
index 0000000000..69d41df2f9
--- /dev/null
+++ b/src/quickcontrolstestutils/CMakeLists.txt
@@ -0,0 +1,25 @@
+qt_internal_add_module(QuickControlsTestUtilsPrivate
+ CONFIG_MODULE_NAME quickcontrolstestutilsprivate
+ STATIC
+ INTERNAL_MODULE
+ SOURCES
+ controlstestutils.cpp
+ controlstestutils_p.h
+ dialogstestutils_p.h
+ dialogstestutils.cpp
+ qtest_quickcontrols_p.h
+ DEFINES
+ QT_BUILD_SHARED_QUICK_CONTROLS_TEST_UTILS_LIB
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Test
+ Qt::Qml
+ Qt::QmlPrivate
+ Qt::Quick
+ Qt::QuickControls2
+ Qt::QuickDialogs2QuickImplPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2
+ Qt::QuickTemplates2Private
+ Qt::QuickTestUtilsPrivate
+)
diff --git a/src/quickcontrolstestutils/controlstestutils.cpp b/src/quickcontrolstestutils/controlstestutils.cpp
new file mode 100644
index 0000000000..ec3748fed4
--- /dev/null
+++ b/src/quickcontrolstestutils/controlstestutils.cpp
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "controlstestutils_p.h"
+
+#include <QtTest/qsignalspy.h>
+#include <QtQuickControls2/qquickstyle.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+
+QQuickControlsTestUtils::QQuickControlsApplicationHelper::QQuickControlsApplicationHelper(QQmlDataTest *testCase,
+ const QString &testFilePath, const QVariantMap &initialProperties, const QStringList &qmlImportPaths)
+ : QQuickApplicationHelper(testCase, testFilePath, initialProperties, qmlImportPaths)
+{
+ if (ready)
+ appWindow = qobject_cast<QQuickApplicationWindow*>(cleanup.data());
+}
+
+bool QQuickControlsTestUtils::QQuickStyleHelper::updateStyle(const QString &style)
+{
+ // If it's not the first time a style has been set and the new style is not different, do nothing.
+ if (!currentStyle.isEmpty() && style == currentStyle)
+ return false;
+
+ engine.reset();
+ currentStyle = style;
+ qmlClearTypeRegistrations();
+ engine.reset(new QQmlEngine);
+ QQuickStyle::setStyle(style);
+
+ QQmlComponent component(engine.data());
+ component.setData(QString::fromUtf8("import QtQuick\nimport QtQuick.Controls\n Control { }").toUtf8(), QUrl());
+
+ return true;
+}
+
+void QQuickControlsTestUtils::forEachControl(QQmlEngine *engine, const QString &qqc2ImportPath,
+ const QString &sourcePath, const QString &targetPath, const QStringList &skipList,
+ QQuickControlsTestUtils::ForEachCallback callback)
+{
+ // We cannot use QQmlComponent to load QML files directly from the source tree.
+ // For styles that use internal QML types (eg. material/Ripple.qml), the source
+ // dir would be added as an "implicit" import path overriding the actual import
+ // path (qtbase/qml/QtQuick/Controls.2/Material). => The QML engine fails to load
+ // the style C++ plugin from the implicit import path (the source dir).
+ //
+ // Therefore we only use the source tree for finding out the set of QML files that
+ // a particular style implements, and then we locate the respective QML files in
+ // the engine's import path. This way we can use QQmlComponent to load each QML file
+ // for benchmarking.
+
+ const QFileInfoList entries = QDir(qqc2ImportPath + QLatin1Char('/') + sourcePath).entryInfoList(
+ QStringList(QStringLiteral("*.qml")), QDir::Files);
+ for (const QFileInfo &entry : entries) {
+ QString name = entry.baseName();
+ if (!skipList.contains(name)) {
+ const auto importPathList = engine->importPathList();
+ for (const QString &importPath : importPathList) {
+ QString name = entry.dir().dirName() + QLatin1Char('/') + entry.fileName();
+ QString filePath = importPath + QLatin1Char('/') + targetPath + QLatin1Char('/') + entry.fileName();
+ if (filePath.startsWith(QLatin1Char(':')))
+ filePath.prepend(QStringLiteral("qrc"));
+ if (QFile::exists(filePath)) {
+ callback(name, QUrl::fromLocalFile(filePath));
+ break;
+ } else {
+ QUrl url(filePath);
+ filePath = QQmlFile::urlToLocalFileOrQrc(filePath);
+ if (!filePath.isEmpty() && QFile::exists(filePath)) {
+ callback(name, url);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void QQuickControlsTestUtils::addTestRowForEachControl(QQmlEngine *engine, const QString &qqc2ImportPath,
+ const QString &sourcePath, const QString &targetPath, const QStringList &skipList)
+{
+ forEachControl(engine, qqc2ImportPath, sourcePath, targetPath, skipList, [&](const QString &relativePath, const QUrl &absoluteUrl) {
+ QTest::newRow(qPrintable(relativePath)) << absoluteUrl;
+ });
+}
+
+bool QQuickControlsTestUtils::verifyButtonClickable(QQuickAbstractButton *button)
+{
+ if (!button->window()) {
+ qWarning() << "button" << button << "doesn't have an associated window";
+ return false;
+ }
+
+ if (!button->isEnabled()) {
+ qWarning() << "button" << button << "is not enabled";
+ return false;
+ }
+
+ if (!button->isVisible()) {
+ qWarning() << "button" << button << "is not visible";
+ return false;
+ }
+
+ if (button->width() <= 0.0) {
+ qWarning() << "button" << button << "must have a width greater than 0";
+ return false;
+ }
+
+ if (button->height() <= 0.0) {
+ qWarning() << "button" << button << "must have a height greater than 0";
+ return false;
+ }
+
+ return true;
+}
+
+bool QQuickControlsTestUtils::clickButton(QQuickAbstractButton *button)
+{
+ if (!verifyButtonClickable(button))
+ return false;
+
+ QSignalSpy spy(button, &QQuickAbstractButton::clicked);
+ if (!spy.isValid()) {
+ qWarning() << "button" << button << "must have a valid clicked signal";
+ return false;
+ }
+
+ const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
+ QTest::mouseClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
+ if (spy.count() != 1) {
+ qWarning() << "clicked signal of button" << button << "was not emitted after clicking";
+ return false;
+ }
+
+ return true;
+}
+
+bool QQuickControlsTestUtils::doubleClickButton(QQuickAbstractButton *button)
+{
+ if (!verifyButtonClickable(button))
+ return false;
+
+ QSignalSpy spy(button, &QQuickAbstractButton::clicked);
+ if (!spy.isValid()) {
+ qWarning() << "button" << button << "must have a valid doubleClicked signal";
+ return false;
+ }
+
+ const QPoint buttonCenter = button->mapToScene(QPointF(button->width() / 2, button->height() / 2)).toPoint();
+ QTest::mouseDClick(button->window(), Qt::LeftButton, Qt::NoModifier, buttonCenter);
+ if (spy.count() != 1) {
+ qWarning() << "doubleClicked signal of button" << button << "was not emitted after double-clicking";
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/quickcontrolstestutils/controlstestutils_p.h b/src/quickcontrolstestutils/controlstestutils_p.h
new file mode 100644
index 0000000000..4d4f0432b0
--- /dev/null
+++ b/src/quickcontrolstestutils/controlstestutils_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CONTROLSTESTUTILS_P_H
+#define CONTROLSTESTUTILS_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 <QtQuickTestUtils/private/visualtestutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlEngine;
+class QQuickApplicationWindow;
+class QQuickAbstractButton;
+
+namespace QQuickControlsTestUtils
+{
+ class QQuickControlsApplicationHelper : public QQuickVisualTestUtils::QQuickApplicationHelper
+ {
+ public:
+ QQuickControlsApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath,
+ const QVariantMap &initialProperties = {},
+ const QStringList &qmlImportPaths = {});
+
+ QQuickApplicationWindow *appWindow = nullptr;
+ };
+
+ struct QQuickStyleHelper
+ {
+ [[nodiscard]] bool updateStyle(const QString &style);
+
+ QString currentStyle;
+ QScopedPointer<QQmlEngine> engine;
+ };
+
+ typedef std::function<void(const QString &/*relativePath*/, const QUrl &/*absoluteUrl*/)> ForEachCallback;
+
+ void forEachControl(QQmlEngine *engine, const QString &qqc2ImportPath, const QString &sourcePath,
+ const QString &targetPath, const QStringList &skipList, ForEachCallback callback);
+ void addTestRowForEachControl(QQmlEngine *engine, const QString &qqc2ImportPath, const QString &sourcePath,
+ const QString &targetPath, const QStringList &skipList = QStringList());
+
+ [[nodiscard]] bool verifyButtonClickable(QQuickAbstractButton *button);
+ [[nodiscard]] bool clickButton(QQuickAbstractButton *button);
+ [[nodiscard]] bool doubleClickButton(QQuickAbstractButton *button);
+}
+
+QT_END_NAMESPACE
+
+#endif // CONTROLSTESTUTILS_P_H
diff --git a/src/quickcontrolstestutils/dialogstestutils.cpp b/src/quickcontrolstestutils/dialogstestutils.cpp
new file mode 100644
index 0000000000..044926e7c8
--- /dev/null
+++ b/src/quickcontrolstestutils/dialogstestutils.cpp
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "dialogstestutils_p.h"
+
+#include <QtTest/qsignalspy.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuickTest/quicktest.h>
+#include <QtQuickControls2/qquickstyle.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfiledialogdelegate_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfolderbreadcrumbbar_p.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickfolderbreadcrumbbar_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+bool QQuickDialogTestUtils::verifyFileDialogDelegates(QQuickListView *fileDialogListView,
+ const QStringList &expectedFiles, QString &failureMessage)
+{
+ if (QQuickTest::qIsPolishScheduled(fileDialogListView)) {
+ if (!QQuickTest::qWaitForItemPolished(fileDialogListView)) {
+ failureMessage = QLatin1String("Failed to polish fileDialogListView");
+ return false;
+ }
+ }
+
+ QStringList actualFiles;
+ for (int i = 0; i < fileDialogListView->count(); ++i) {
+ auto delegate = qobject_cast<QQuickFileDialogDelegate*>(
+ QQuickVisualTestUtils::findViewDelegateItem(fileDialogListView, i));
+ if (!delegate) {
+ failureMessage = QString::fromLatin1("Delegate at index %1 is null").arg(i);
+ return false;
+ }
+
+ // Need to call absoluteFilePath on Windows; see comment in dialogtestutil.h.
+ actualFiles.append(QFileInfo(delegate->file().toLocalFile()).absoluteFilePath());
+ }
+
+ if (actualFiles != expectedFiles) {
+ failureMessage = QString::fromLatin1("Mismatch in actual vs expected "
+ "delegates in fileDialogListView:\n expected: %1\n actual: %2")
+ .arg(QDebug::toString(expectedFiles), QDebug::toString(actualFiles));
+ return false;
+ }
+
+ return true;
+}
+
+bool QQuickDialogTestUtils::verifyBreadcrumbDelegates(QQuickFolderBreadcrumbBar *breadcrumbBar,
+ const QUrl &expectedFolder, QString &failureMessage)
+{
+ if (!breadcrumbBar) {
+ failureMessage = QLatin1String("breadcrumbBar is null");
+ return false;
+ }
+
+ auto breadcrumbBarListView = qobject_cast<QQuickListView*>(breadcrumbBar->contentItem());
+ if (!breadcrumbBarListView) {
+ failureMessage = QLatin1String("breadcrumbBar's ListView is null");
+ return false;
+ }
+
+ if (QQuickTest::qIsPolishScheduled(breadcrumbBarListView)) {
+ if (!QQuickTest::qWaitForItemPolished(breadcrumbBarListView)) {
+ failureMessage = QLatin1String("Failed to polish breadcrumbBarListView");
+ return false;
+ }
+ }
+
+ QStringList actualCrumbs;
+ for (int i = 0; i < breadcrumbBarListView->count(); ++i) {
+ auto delegate = qobject_cast<QQuickAbstractButton*>(
+ QQuickVisualTestUtils::findViewDelegateItem(breadcrumbBarListView, i));
+ if (!delegate) {
+ // It's a separator or some other non-crumb item.
+ continue;
+ }
+
+ actualCrumbs.append(delegate->text());
+ }
+
+ QStringList expectedCrumbs = QQuickFolderBreadcrumbBarPrivate::crumbPathsForFolder(expectedFolder);
+ for (int i = 0; i < expectedCrumbs.size(); ++i) {
+ QString &crumbPath = expectedCrumbs[i];
+ crumbPath = QQuickFolderBreadcrumbBarPrivate::folderBaseName(crumbPath);
+ }
+
+ if (actualCrumbs != expectedCrumbs) {
+ failureMessage = QString::fromLatin1("Mismatch in actual vs expected "
+ "delegates in breadcrumbBarListView:\n expected: %1\n actual: %2")
+ .arg(QDebug::toString(expectedCrumbs), QDebug::toString(actualCrumbs));
+ return false;
+ }
+
+ return true;
+}
+
+QQuickAbstractButton *QQuickDialogTestUtils::findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText)
+{
+ for (int i = 0; i < box->count(); ++i) {
+ auto button = qobject_cast<QQuickAbstractButton*>(box->itemAt(i));
+ if (button && button->text().toUpper() == buttonText.toUpper())
+ return button;
+ }
+ return nullptr;
+}
+
+void QQuickDialogTestUtils::enterText(QWindow *window, const QString &textToEnter)
+{
+ for (int i = 0; i < textToEnter.size(); ++i) {
+ const QChar key = textToEnter.at(i);
+ QTest::keyClick(window, key.toLatin1());
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrolstestutils/dialogstestutils_p.h b/src/quickcontrolstestutils/dialogstestutils_p.h
new file mode 100644
index 0000000000..2d5ff0c573
--- /dev/null
+++ b/src/quickcontrolstestutils/dialogstestutils_p.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIALOGSTESTUTILS_H
+#define DIALOGSTESTUTILS_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 <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+
+#include <QtQuickTestUtils/private/qmlutils_p.h>
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+// We need these for Windows, because FolderListModel returns a lowercase drive letter; e.g.:
+// "file:///c:/blah.txt", whereas other API returns "file:///C:/blah.txt".
+#define COMPARE_URL(url1, url2) \
+ QCOMPARE(QFileInfo(url1.toLocalFile()).absoluteFilePath(), QFileInfo(url2.toLocalFile()).absoluteFilePath());
+
+// Store a copy of the arguments in case { ... } list initializer syntax is used as an argument,
+// which could result in two different lists being created and passed to std::transform()
+// (and would also require it to be enclosed in parentheses everywhere it's used).
+#define COMPARE_URLS(actualUrls, expectedUrls) \
+{ \
+ const QList<QUrl> actualUrlsCopy = actualUrls; \
+ QList<QString> actualPaths; \
+ std::transform(actualUrlsCopy.begin(), actualUrlsCopy.end(), std::back_insert_iterator(actualPaths), \
+ [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
+ const QList<QUrl> expectedUrlsCopy = expectedUrls; \
+ QList<QString> expectedPaths; \
+ std::transform(expectedUrlsCopy.begin(), expectedUrlsCopy.end(), std::back_insert_iterator(expectedPaths), \
+ [](const QUrl &url) { return QFileInfo(url.toLocalFile()).absoluteFilePath(); }); \
+ QCOMPARE(actualPaths, expectedPaths); \
+}
+
+#define OPEN_QUICK_DIALOG() \
+QVERIFY2(dialogHelper.isWindowInitialized(), dialogHelper.failureMessage()); \
+QVERIFY(dialogHelper.waitForWindowActive()); \
+QVERIFY(dialogHelper.openDialog()); \
+QTRY_VERIFY(dialogHelper.isQuickDialogOpen());
+
+#define CLOSE_QUICK_DIALOG() \
+ do { \
+ dialogHelper.dialog->close(); \
+ QVERIFY(!dialogHelper.dialog->isVisible()); \
+ QTRY_VERIFY(!dialogHelper.quickDialog->isVisible()); \
+ } while (false)
+
+QT_BEGIN_NAMESPACE
+class QWindow;
+
+class QQuickListView;
+
+class QQuickAbstractButton;
+
+class QQuickDialogButtonBox;
+class QQuickFolderBreadcrumbBar;
+
+namespace QQuickDialogTestUtils
+{
+
+// Saves duplicating a bunch of code in every test.
+template<typename DialogType, typename QuickDialogType>
+class DialogTestHelper
+{
+public:
+ DialogTestHelper(QQmlDataTest *testCase, const QString &testFilePath,
+ const QStringList &qmlImportPaths = {}, const QVariantMap &initialProperties = {}) :
+ appHelper(testCase, testFilePath, initialProperties, qmlImportPaths)
+ {
+ if (!appHelper.ready)
+ return;
+
+ dialog = appHelper.window->property("dialog").value<DialogType*>();
+ if (!dialog) {
+ appHelper.errorMessage = "\"dialog\" property is not valid";
+ return;
+ }
+
+ appHelper.window->show();
+ appHelper.window->requestActivate();
+ }
+
+ Q_REQUIRED_RESULT bool isWindowInitialized() const
+ {
+ return appHelper.ready;
+ }
+
+ Q_REQUIRED_RESULT bool waitForWindowActive()
+ {
+ return QTest::qWaitForWindowActive(appHelper.window);
+ }
+
+ bool openDialog()
+ {
+ dialog->open();
+ if (!dialog->isVisible()) {
+ appHelper.errorMessage = "Dialog is not visible";
+ return false;
+ }
+
+ // We might want to call this function more than once,
+ // and we only need to get these members the first time.
+ if (!quickDialog) {
+ quickDialog = appHelper.window->findChild<QuickDialogType*>();
+ if (!quickDialog) {
+ appHelper.errorMessage = "Can't find Qt Quick-based dialog";
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool isQuickDialogOpen() const
+ {
+ return quickDialog->isOpened();
+ }
+
+ QQuickWindow *window() const
+ {
+ return appHelper.window;
+ }
+
+ const char *failureMessage() const
+ {
+ return appHelper.errorMessage.constData();
+ }
+
+ QQuickVisualTestUtils::QQuickApplicationHelper appHelper;
+ DialogType *dialog = nullptr;
+ QuickDialogType *quickDialog = nullptr;
+};
+
+bool verifyFileDialogDelegates(QQuickListView *fileDialogListView, const QStringList &expectedFiles, QString &failureMessage);
+
+bool verifyBreadcrumbDelegates(QQuickFolderBreadcrumbBar *breadcrumbBar, const QUrl &expectedFolder, QString &failureMessage);
+
+QQuickAbstractButton *findDialogButton(QQuickDialogButtonBox *box, const QString &buttonText);
+
+void enterText(QWindow *window, const QString &textToEnter);
+}
+
+QT_END_NAMESPACE
+
+#endif // DIALOGSTESTUTILS_H
diff --git a/src/quickcontrolstestutils/qtest_quickcontrols_p.h b/src/quickcontrolstestutils/qtest_quickcontrols_p.h
new file mode 100644
index 0000000000..1c1ae27808
--- /dev/null
+++ b/src/quickcontrolstestutils/qtest_quickcontrols_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTEST_QUICKCONTROLS_P_H
+#define QTEST_QUICKCONTROLS_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 <QtTest/qtest.h>
+#include <QtTest/private/qtestresult_p.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/qquickstyle.h>
+#include <QtQuickControls2/private/qquickstyle_p.h>
+
+inline QStringList testStyles()
+{
+ // It's not enough to check if the name is empty, because since Qt 6
+ // we set an appropriate style for the platform if no style was specified.
+ // Also, we need the name check to come first, as isUsingDefaultStyle() does not do any resolving,
+ // and so its return value wouldn't be correct otherwise.
+ if (QQuickStyle::name().isEmpty() || QQuickStylePrivate::isUsingDefaultStyle())
+ return QQuickStylePrivate::builtInStyles();
+ return QStringList(QQuickStyle::name());
+}
+
+inline int runTests(QObject *testObject, int argc, char *argv[])
+{
+ int res = 0;
+ QTest::qInit(testObject, argc, argv);
+ const QByteArray testObjectName = QTestResult::currentTestObjectName();
+ // setCurrentTestObject() takes a C string, which means we must ensure
+ // that the string we pass in lives long enough (i.e until the next call
+ // to setCurrentTestObject()), so store the name outside of the loop.
+ QByteArray testName;
+ const QStringList styles = testStyles();
+ for (const QString &style : styles) {
+ qmlClearTypeRegistrations();
+ QQuickStyle::setStyle(style);
+ testName = testObjectName + "::" + style.toLocal8Bit();
+ QTestResult::setCurrentTestObject(testName);
+ res += QTest::qRun();
+ }
+ QTestResult::setCurrentTestObject(testObjectName);
+ QTest::qCleanup();
+ return res;
+}
+
+#define QTEST_QUICKCONTROLS_MAIN(TestCase) \
+int main(int argc, char *argv[]) \
+{ \
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1"); \
+ QGuiApplication app(argc, argv); \
+ TestCase tc; \
+ QTEST_SET_MAIN_SOURCE_PATH \
+ return runTests(&tc, argc, argv); \
+}
+
+#endif // QTEST_QUICKCONTROLS_P_H
diff --git a/src/quickdialogs2/CMakeLists.txt b/src/quickdialogs2/CMakeLists.txt
new file mode 100644
index 0000000000..88ae96331c
--- /dev/null
+++ b/src/quickdialogs2/CMakeLists.txt
@@ -0,0 +1,3 @@
+add_subdirectory(quickdialogs2utils)
+add_subdirectory(quickdialogs2quickimpl)
+add_subdirectory(quickdialogs2)
diff --git a/src/quickdialogs2/quickdialogs2/CMakeLists.txt b/src/quickdialogs2/quickdialogs2/CMakeLists.txt
new file mode 100644
index 0000000000..f6cf1d8325
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/CMakeLists.txt
@@ -0,0 +1,44 @@
+#####################################################################
+## QuickDialogs2 Module:
+#####################################################################
+
+qt_internal_add_qml_module(QuickDialogs2
+ URI "QtQuick.Dialogs"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickDialogsPlugin
+ PLUGIN_TARGET qtquickdialogsplugin
+ DEPENDENCIES
+ QtQuick/auto
+ SOURCES
+ qquickabstractdialog.cpp
+ qquickabstractdialog_p.h
+ qquickfiledialog.cpp
+ qquickfiledialog_p.h
+ qquickfontdialog.cpp
+ qquickfontdialog_p.h
+ qtquickdialogs2foreign_p.h
+ qtquickdialogs2global_p.h
+ DEFINES
+ QT_BUILD_QUICKDIALOGS2_LIB
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickDialogs2Utils
+ Qt::QuickDialogs2UtilsPrivate
+ Qt::QuickDialogs2QuickImpl
+ Qt::QuickDialogs2QuickImplPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+qt_internal_add_docs(QuickDialogs2
+ doc/qtquickdialogs.qdocconf
+)
diff --git a/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-filedialog-gtk.png b/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-filedialog-gtk.png
new file mode 100644
index 0000000000..9360d747a2
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-filedialog-gtk.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-fontdialog-gtk.png b/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-fontdialog-gtk.png
new file mode 100644
index 0000000000..0c6217bdb4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/images/qtquickdialogs-fontdialog-gtk.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2/doc/qtquickdialogs.qdocconf b/src/quickdialogs2/quickdialogs2/doc/qtquickdialogs.qdocconf
new file mode 100644
index 0000000000..b41c30ca1d
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/qtquickdialogs.qdocconf
@@ -0,0 +1,40 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+include($QT_INSTALL_DOCS/config/exampleurl-qtquickcontrols2.qdocconf)
+
+project = QtQuickDialogs
+description = Qt Quick Dialogs Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtQuickDialogs
+
+qhp.QtQuickDialogs.file = qtquickdialogs.qhp
+qhp.QtQuickDialogs.namespace = org.qt-project.qtquickdialogs.$QT_VERSION_TAG
+qhp.QtQuickDialogs.virtualFolder = qtquickdialogs
+qhp.QtQuickDialogs.indexTitle = Qt Quick Dialogs
+qhp.QtQuickDialogs.indexRoot =
+
+qhp.QtQuickDialogs.filterAttributes = qtquickdialogs $QT_VERSION qtrefdoc
+qhp.QtQuickDialogs.customFilters.Qt.name = QtQuickDialogs $QT_VERSION
+qhp.QtQuickDialogs.customFilters.Qt.filterAttributes = qtquickdialogs $QT_VERSION
+
+qhp.QtQuickDialogs.subprojects = qmltypes
+qhp.QtQuickDialogs.subprojects.qmltypes.title = QML Types
+qhp.QtQuickDialogs.subprojects.qmltypes.indexTitle = Qt Quick Dialogs QML Types
+qhp.QtQuickDialogs.subprojects.qmltypes.selectors = qmlclass
+qhp.QtQuickDialogs.subprojects.qmltypes.sortPages = true
+
+depends = qtcore qtgui qtdoc qtqml qtquick qtquickcontrols qtlabsplatform
+
+# This module has no documented C++ types, clear the module header
+moduleheader =
+
+headerdirs += ..
+sourcedirs += .. \
+ src
+
+imagedirs += images
+
+navigation.landingpage = "Qt Quick Dialogs"
+navigation.qmltypespage = "Qt Quick Dialogs QML Types"
+
+tagfile = qtquickdialogs.tags
diff --git a/src/quickdialogs2/quickdialogs2/doc/src/includes/fallback.qdocinc b/src/quickdialogs2/quickdialogs2/doc/src/includes/fallback.qdocinc
new file mode 100644
index 0000000000..f3a4a1805b
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/src/includes/fallback.qdocinc
@@ -0,0 +1 @@
+Qt Quick Dialogs uses a Qt Quick implementation as a fallback on platforms that do not have a native implementation available.
diff --git a/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-index.qdoc b/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-index.qdoc
new file mode 100644
index 0000000000..92a25c3fd4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-index.qdoc
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquickdialogs-index.html
+ \title Qt Quick Dialogs
+
+ \brief Provides QML types for creating and interacting with system dialogs.
+
+ The Qt Quick Dialogs module allows to create and interact with system dialogs
+ from QML. The module was introduced in Qt 6.2.
+
+ \section1 Using the Module
+
+ The \l{Qt Quick Dialogs QML Types}{QML types} can be imported into your
+ application using the following import statement in your \c {.qml} file:
+
+ \qml
+ import QtQuick.Dialogs
+ \endqml
+
+ \section1 License and Attributions
+
+ Qt Quick Dialogs is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under the
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
+ \section1 Reference
+
+ \list
+ \li \l{Qt Quick Dialogs QML Types}{QML Types}
+ \endlist
+
+ \section1 Related Modules
+
+ \list
+ \li \l{Qt Quick}
+ \li \l{Qt Quick Controls}
+ \li \l{Qt Quick Templates 2}
+ \li \l{Qt Labs Platform}
+ \endlist
+*/
diff --git a/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-qmltypes.qdoc b/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-qmltypes.qdoc
new file mode 100644
index 0000000000..748df4ab85
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/doc/src/qtquickdialogs-qmltypes.qdoc
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule QtQuick.Dialogs
+ \title Qt Quick Dialogs QML Types
+ \ingroup qmlmodules
+ \brief Provides QML types for creating and interacting with system dialogs.
+
+ The Qt Quick Dialogs module allows to create and interact with system dialogs
+ from QML. The module was introduced in Qt 6.2.
+
+ The QML types can be imported into your
+ application using the following import statement in your \c {.qml} file:
+
+ \qml
+ import QtQuick.Dialogs
+ \endqml
+
+ \section1 QML Types
+
+*/
diff --git a/src/quickdialogs2/quickdialogs2/qquickabstractdialog.cpp b/src/quickdialogs2/quickdialogs2/qquickabstractdialog.cpp
new file mode 100644
index 0000000000..69a478290a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickabstractdialog.cpp
@@ -0,0 +1,458 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickabstractdialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickDialogs2QuickImpl/private/qquickdialogimplfactory_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcDialogs, "qt.quick.dialogs")
+
+/*!
+ \internal
+
+ A dialog that can be backed by different implementations.
+
+ Each dialog has a handle to QPlatformDialogHelper, which is created in create().
+ The helper acts as an intermediary between the QML-facing dialog object
+ and the native/widget/quick implementation:
+
+ +------------+ +------------------------------------+ +-------------------------------------+
+ | | | | | |
+ | FileDialog |----->| Native/Widget/Quick QPlatformFile- |----->| Native OS dialog/QQuickFileDialog/ |
+ | | | DialogHelper subclass | | QQuickFileDialogImpl |
+ | | | | | |
+ +------------+ +------------------------------------+ +-------------------------------------+
+*/
+
+/*!
+ \qmltype Dialog
+ \inherits QtObject
+//! \instantiates QQuickAbstractDialog
+ \inqmlmodule QtQuick.Dialogs
+ \since 6.2
+ \brief The base class of native dialogs.
+
+ The Dialog type provides common QML API for native platform dialogs.
+ For the non-native dialog, see \l [QML QtQuickControls]{Dialog}.
+
+ To show a native dialog, construct an instance of one of the concrete
+ Dialog implementations, set the desired properties, and call \l open().
+ Dialog emits \l accepted() or \l rejected() when the user is done with
+ the dialog.
+*/
+
+/*!
+ \qmlsignal void QtQuick.Dialogs::Dialog::accepted()
+
+ This signal is emitted when the dialog has been accepted either
+ interactively or by calling \l accept().
+
+ \sa rejected()
+*/
+
+/*!
+ \qmlsignal void QtQuick.Dialogs::Dialog::rejected()
+
+ This signal is emitted when the dialog has been rejected either
+ interactively or by calling \l reject().
+
+ This signal is also emitted when closing the dialog with \l close().
+
+ \sa accepted()
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
+
+QQuickAbstractDialog::QQuickAbstractDialog(QPlatformTheme::DialogType type, QObject *parent)
+ : QObject(parent),
+ m_type(type)
+{
+}
+
+QQuickAbstractDialog::~QQuickAbstractDialog()
+{
+ destroy();
+}
+
+QPlatformDialogHelper *QQuickAbstractDialog::handle() const
+{
+ return m_handle.get();
+}
+
+/*!
+ \qmldefault
+ \qmlproperty list<Object> QtQuick.Dialogs::Dialog::data
+
+ This default property holds the list of all objects declared as children of
+ the dialog.
+*/
+QQmlListProperty<QObject> QQuickAbstractDialog::data()
+{
+ return QQmlListProperty<QObject>(this, &m_data);
+}
+
+/*!
+ \qmlproperty Window QtQuick.Dialogs::Dialog::parentWindow
+
+ This property holds the parent window of the dialog.
+
+ Unless explicitly set, the window is automatically resolved by iterating
+ the QML parent objects until a \l Window or an \l Item that has a window
+ is found.
+*/
+QWindow *QQuickAbstractDialog::parentWindow() const
+{
+ return m_parentWindow;
+}
+
+void QQuickAbstractDialog::setParentWindow(QWindow *window)
+{
+ qCDebug(lcDialogs) << "set parent window to" << window;
+ if (m_parentWindow == window)
+ return;
+
+ m_parentWindow = window;
+ emit parentWindowChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick.Dialogs::Dialog::title
+
+ This property holds the title of the dialog.
+*/
+QString QQuickAbstractDialog::title() const
+{
+ return m_title;
+}
+
+void QQuickAbstractDialog::setTitle(const QString &title)
+{
+ if (m_title == title)
+ return;
+
+ m_title = title;
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty Qt::WindowFlags QtQuick.Dialogs::Dialog::flags
+
+ This property holds the window flags of the dialog. The default value is \c Qt.Dialog.
+*/
+Qt::WindowFlags QQuickAbstractDialog::flags() const
+{
+ return m_flags;
+}
+
+void QQuickAbstractDialog::setFlags(Qt::WindowFlags flags)
+{
+ if (m_flags == flags)
+ return;
+
+ m_flags = flags;
+ emit flagsChanged();
+}
+
+/*!
+ \qmlproperty Qt::WindowModality QtQuick.Dialogs::Dialog::modality
+
+ This property holds the modality of the dialog. The default value is \c Qt.WindowModal.
+
+ Available values:
+ \value Qt.NonModal The dialog is not modal and does not block input to other windows.
+ \value Qt.WindowModal The dialog is modal to a single window hierarchy and blocks input to its parent window, all grandparent windows, and all siblings of its parent and grandparent windows.
+ \value Qt.ApplicationModal The dialog is modal to the application and blocks input to all windows.
+*/
+Qt::WindowModality QQuickAbstractDialog::modality() const
+{
+ return m_modality;
+}
+
+void QQuickAbstractDialog::setModality(Qt::WindowModality modality)
+{
+ if (m_modality == modality)
+ return;
+
+ m_modality = modality;
+ emit modalityChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Dialogs::Dialog::visible
+
+ This property holds the visibility of the dialog. The default value is \c false.
+
+ \sa open(), close()
+*/
+bool QQuickAbstractDialog::isVisible() const
+{
+ return m_handle && m_visible;
+}
+
+void QQuickAbstractDialog::setVisible(bool visible)
+{
+ qCDebug(lcDialogs) << "setVisible called with" << visible;
+
+ if (visible) {
+ // Don't try to open before component completion, as we won't have a window yet,
+ // and open() sets m_visible to false if it fails.
+ if (!m_complete)
+ m_visibleRequested = true;
+ else
+ open();
+ } else {
+ close();
+ }
+}
+
+/*!
+ \qmlproperty StandardCode QtQuick.Dialogs::Dialog::result
+
+ This property holds the result code.
+
+ Standard result codes:
+ \value Dialog.Accepted
+ \value Dialog.Rejected
+
+ \note MessageDialog sets the result to the value of the clicked standard
+ button instead of using the standard result codes.
+*/
+QQuickAbstractDialog::StandardCode QQuickAbstractDialog::result() const
+{
+ return m_result;
+}
+
+void QQuickAbstractDialog::setResult(StandardCode result)
+{
+ if (m_result == result)
+ return;
+
+ m_result = result;
+ emit resultChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Dialogs::Dialog::open()
+
+ Opens the dialog.
+
+ \sa visible, close()
+*/
+void QQuickAbstractDialog::open()
+{
+ qCDebug(lcDialogs) << "open called";
+ if (m_visible || !create())
+ return;
+
+ onShow(m_handle.get());
+ m_visible = m_handle->show(m_flags, m_modality, m_parentWindow);
+ if (m_visible) {
+ m_result = Rejected; // in case an accepted dialog gets re-opened, then closed
+ emit visibleChanged();
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick.Dialogs::Dialog::close()
+
+ Closes the dialog and emits either the \l accepted() or \l rejected()
+ signal.
+
+ \sa visible, open()
+*/
+void QQuickAbstractDialog::close()
+{
+ if (!m_handle || !m_visible)
+ return;
+
+ onHide(m_handle.get());
+ m_handle->hide();
+ m_visible = false;
+ emit visibleChanged();
+
+ if (m_result == Accepted)
+ emit accepted();
+ else // if (m_result == Rejected)
+ emit rejected();
+}
+
+/*!
+ \qmlmethod void QtQuick.Dialogs::Dialog::accept()
+
+ Closes the dialog and emits the \l accepted() signal.
+
+ \sa reject()
+*/
+void QQuickAbstractDialog::accept()
+{
+ done(Accepted);
+}
+
+/*!
+ \qmlmethod void QtQuick.Dialogs::Dialog::reject()
+
+ Closes the dialog and emits the \l rejected() signal.
+
+ \sa accept()
+*/
+void QQuickAbstractDialog::reject()
+{
+ done(Rejected);
+}
+
+/*!
+ \qmlmethod void QtQuick.Dialogs::Dialog::done(StandardCode result)
+
+ Closes the dialog and sets the \a result.
+
+ \sa accept(), reject(), result
+*/
+void QQuickAbstractDialog::done(StandardCode result)
+{
+ setResult(result);
+ close();
+}
+
+void QQuickAbstractDialog::classBegin()
+{
+}
+
+void QQuickAbstractDialog::componentComplete()
+{
+ qCDebug(lcDialogs) << "componentComplete";
+ m_complete = true;
+
+ if (!m_parentWindow) {
+ qCDebug(lcDialogs) << "- no parent window; searching for one";
+ setParentWindow(findParentWindow());
+ }
+
+ if (m_visibleRequested) {
+ qCDebug(lcDialogs) << "visible was bound to true before component completion; opening dialog";
+ open();
+ m_visibleRequested = false;
+ }
+}
+
+static const char *qmlTypeName(const QObject *object)
+{
+ return object->metaObject()->className() + qstrlen("QQuickPlatform");
+}
+
+bool QQuickAbstractDialog::create()
+{
+ qCDebug(lcDialogs) << qmlTypeName(this) << "attempting to create dialog backend of type"
+ << m_type << "with parent window" << m_parentWindow;
+ if (m_handle)
+ return m_handle.get();
+
+ qCDebug(lcDialogs) << "- attempting to create a native dialog";
+ if (useNativeDialog())
+ m_handle.reset(QGuiApplicationPrivate::platformTheme()->createPlatformDialogHelper(m_type));
+
+ if (!m_handle) {
+ qCDebug(lcDialogs) << "- attempting to create a quick dialog";
+ m_handle.reset(QQuickDialogImplFactory::createPlatformDialogHelper(m_type, this));
+ }
+
+ qCDebug(lcDialogs) << qmlTypeName(this) << "created ->" << m_handle.get();
+ if (m_handle) {
+ onCreate(m_handle.get());
+ connect(m_handle.get(), &QPlatformDialogHelper::accept, this, &QQuickAbstractDialog::accept);
+ connect(m_handle.get(), &QPlatformDialogHelper::reject, this, &QQuickAbstractDialog::reject);
+ }
+ return m_handle.get();
+}
+
+void QQuickAbstractDialog::destroy()
+{
+ m_handle.reset();
+}
+
+bool QQuickAbstractDialog::useNativeDialog() const
+{
+ if (QCoreApplication::testAttribute(Qt::AA_DontUseNativeDialogs)) {
+ qCDebug(lcDialogs) << " - Qt::AA_DontUseNativeDialogs was set; not using native dialog";
+ return false;
+ }
+
+ if (!QGuiApplicationPrivate::platformTheme()->usePlatformNativeDialog(m_type)) {
+ qCDebug(lcDialogs) << " - the platform theme told us a native dialog isn't available; not using native dialog";
+ return false;
+ }
+
+ return true;
+}
+
+void QQuickAbstractDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+void QQuickAbstractDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+void QQuickAbstractDialog::onHide(QPlatformDialogHelper *dialog)
+{
+ Q_UNUSED(dialog);
+}
+
+QWindow *QQuickAbstractDialog::findParentWindow() const
+{
+ QObject *obj = parent();
+ while (obj) {
+ QWindow *window = qobject_cast<QWindow *>(obj);
+ if (window)
+ return window;
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window())
+ return item->window();
+ obj = obj->parent();
+ }
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickabstractdialog_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2/qquickabstractdialog_p.h b/src/quickdialogs2/quickdialogs2/qquickabstractdialog_p.h
new file mode 100644
index 0000000000..07e9ffbf5a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickabstractdialog_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKABSTRACTDIALOG_P_H
+#define QQUICKABSTRACTDIALOG_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 <memory>
+
+#include <QtCore/qobject.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqml.h>
+
+#include "qtquickdialogs2global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWindow;
+class QPlatformDialogHelper;
+
+class Q_QUICKDIALOGS2_PRIVATE_EXPORT QQuickAbstractDialog : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(QQmlListProperty<QObject> data READ data FINAL)
+ Q_PROPERTY(QWindow *parentWindow READ parentWindow WRITE setParentWindow NOTIFY parentWindowChanged FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(Qt::WindowFlags flags READ flags WRITE setFlags NOTIFY flagsChanged FINAL)
+ Q_PROPERTY(Qt::WindowModality modality READ modality WRITE setModality NOTIFY modalityChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(StandardCode result READ result WRITE setResult NOTIFY resultChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "data")
+ Q_MOC_INCLUDE(<QtGui/qwindow.h>)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ explicit QQuickAbstractDialog(QPlatformTheme::DialogType type, QObject *parent = nullptr);
+ ~QQuickAbstractDialog();
+
+ QPlatformDialogHelper *handle() const;
+
+ QQmlListProperty<QObject> data();
+
+ QWindow *parentWindow() const;
+ void setParentWindow(QWindow *window);
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ Qt::WindowFlags flags() const;
+ void setFlags(Qt::WindowFlags flags);
+
+ Qt::WindowModality modality() const;
+ void setModality(Qt::WindowModality modality);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ enum StandardCode { Rejected, Accepted };
+ Q_ENUM(StandardCode)
+
+ StandardCode result() const;
+ void setResult(StandardCode result);
+
+public Q_SLOTS:
+ void open();
+ void close();
+ virtual void accept();
+ virtual void reject();
+ virtual void done(StandardCode result);
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+ void parentWindowChanged();
+ void titleChanged();
+ void flagsChanged();
+ void modalityChanged();
+ void visibleChanged();
+ void resultChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ bool create();
+ void destroy();
+
+ virtual bool useNativeDialog() const;
+ virtual void onCreate(QPlatformDialogHelper *dialog);
+ virtual void onShow(QPlatformDialogHelper *dialog);
+ virtual void onHide(QPlatformDialogHelper *dialog);
+
+ QWindow *findParentWindow() const;
+
+private:
+ bool m_visibleRequested = false;
+ bool m_visible = false;
+ bool m_complete = false;
+ StandardCode m_result = Rejected;
+ QWindow *m_parentWindow = nullptr;
+ QString m_title;
+ Qt::WindowFlags m_flags = Qt::Dialog;
+ Qt::WindowModality m_modality = Qt::WindowModal;
+ QPlatformTheme::DialogType m_type;
+ QList<QObject *> m_data;
+ std::unique_ptr<QPlatformDialogHelper> m_handle;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickAbstractDialog)
+
+#endif // QQUICKABSTRACTDIALOG_P_H
diff --git a/src/quickdialogs2/quickdialogs2/qquickfiledialog.cpp b/src/quickdialogs2/quickdialogs2/qquickfiledialog.cpp
new file mode 100644
index 0000000000..b14492a6ce
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickfiledialog.cpp
@@ -0,0 +1,622 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfiledialog_p.h"
+
+#include <QtCore/qlist.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlfile.h>
+
+#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcFileDialog, "qt.quick.dialogs.filedialog")
+
+/*!
+ \qmltype FileDialog
+ \inherits Dialog
+//! \instantiates QQuickFileDialog
+ \inqmlmodule QtQuick.Dialogs
+ \since 6.2
+ \brief A file dialog.
+
+ The FileDialog type provides a QML API for file dialogs.
+
+ \image qtquickdialogs-filedialog-gtk.png
+
+ To show a file dialog, construct an instance of FileDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentFile
+ or \l currentFiles properties can be used to determine the currently
+ selected file(s) in the dialog. The \l selectedFile and \l selectedFiles
+ properties are updated only after the final selection has been made by
+ accepting the dialog.
+
+ \code
+ MenuItem {
+ text: "Open..."
+ onTriggered: fileDialog.open()
+ }
+
+ FileDialog {
+ id: fileDialog
+ currentFile: document.source
+ folder: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
+ }
+
+ MyDocument {
+ id: document
+ source: fileDialog.file
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform file dialog is currently available on the following platforms:
+
+ \list
+ \li iOS
+ \li Android
+ \li Linux (when running with the GTK+ platform theme)
+ \li macOS
+ \li Windows
+ \endlist
+
+ \include includes/fallback.qdocinc
+
+ //! \sa FolderDialog, StandardPaths
+*/
+
+Q_DECLARE_LOGGING_CATEGORY(lcDialogs)
+
+QQuickFileDialog::QQuickFileDialog(QObject *parent)
+ : QQuickAbstractDialog(QPlatformTheme::FileDialog, parent),
+ m_fileMode(OpenFile),
+ m_options(QFileDialogOptions::create()),
+ m_selectedNameFilter(nullptr)
+{
+ m_options->setFileMode(QFileDialogOptions::ExistingFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Dialogs::FileDialog::fileMode
+
+ This property holds the mode of the dialog.
+
+ Available values:
+ \value FileDialog.OpenFile The dialog is used to select an existing file (default).
+ \value FileDialog.OpenFiles The dialog is used to select multiple existing files.
+ \value FileDialog.SaveFile The dialog is used to select any file. The file does not have to exist.
+*/
+QQuickFileDialog::FileMode QQuickFileDialog::fileMode() const
+{
+ return m_fileMode;
+}
+
+void QQuickFileDialog::setFileMode(FileMode mode)
+{
+ qCDebug(lcFileDialog) << "setFileMode called with" << mode;
+ if (mode == m_fileMode)
+ return;
+
+ switch (mode) {
+ case OpenFile:
+ m_options->setFileMode(QFileDialogOptions::ExistingFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+ break;
+ case OpenFiles:
+ m_options->setFileMode(QFileDialogOptions::ExistingFiles);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptOpen);
+ break;
+ case SaveFile:
+ m_options->setFileMode(QFileDialogOptions::AnyFile);
+ m_options->setAcceptMode(QFileDialogOptions::AcceptSave);
+ break;
+ default:
+ break;
+ }
+
+ m_fileMode = mode;
+ emit fileModeChanged();
+}
+
+/*!
+ \qmlproperty url QtQuick.Dialogs::FileDialog::selectedFile
+ \readonly
+
+ This property holds the final accepted file.
+
+ If there are multiple selected files, this property refers to the first
+ file.
+
+ Unlike the \l currentFile property, the \c selectedFile property is not
+ updated while the user is selecting files in the dialog, but only after the
+ final selection has been made. That is, when the user has clicked
+ \uicontrol OK to accept a file. Alternatively, the
+ \l {Dialog::}{accepted()} signal can be handled to get the final selection.
+
+ \sa selectedFiles, currentFile, {Dialog::}{accepted()}, currentFolder
+*/
+QUrl QQuickFileDialog::selectedFile() const
+{
+ return addDefaultSuffix(m_selectedFiles.value(0));
+}
+
+/*!
+ \qmlproperty list<url> QtQuick.Dialogs::FileDialog::selectedFiles
+
+ This property holds the final accepted files.
+
+ Unlike the \l currentFiles property, the \c selectedFiles property is not
+ updated while the user is selecting files in the dialog, but only after the
+ final selection has been made. That is, when the user has clicked
+ \uicontrol OK to accept files. Alternatively, the \l {Dialog::}{accepted()}
+ signal can be handled to get the final selection.
+
+ \sa currentFiles, {Dialog::}{accepted()}, currentFolder
+*/
+QList<QUrl> QQuickFileDialog::selectedFiles() const
+{
+ return addDefaultSuffixes(m_selectedFiles);
+}
+
+void QQuickFileDialog::setSelectedFiles(const QList<QUrl> &selectedFiles)
+{
+ if (m_selectedFiles == selectedFiles)
+ return;
+
+ bool firstChanged = m_selectedFiles.value(0) != selectedFiles.value(0);
+ m_selectedFiles = selectedFiles;
+ if (firstChanged)
+ emit selectedFileChanged();
+ emit selectedFilesChanged();
+}
+
+/*!
+ \qmlproperty url QtQuick.Dialogs::FileDialog::currentFile
+
+ This property holds the currently selected file in the dialog.
+
+ Unlike the \l selectedFile property, the \c currentFile property is updated
+ while the user is selecting files in the dialog, even before the final
+ selection has been made.
+
+ \sa selectedFile, currentFiles, currentFolder
+*/
+QUrl QQuickFileDialog::currentFile() const
+{
+ return currentFiles().value(0);
+}
+
+void QQuickFileDialog::setCurrentFile(const QUrl &file)
+{
+ setCurrentFiles(QList<QUrl>() << file);
+}
+
+/*!
+ \qmlproperty list<url> QtQuick.Dialogs::FileDialog::currentFiles
+
+ This property holds the currently selected files in the dialog.
+
+ Unlike the \l selectedFiles property, the \c currentFiles property is
+ updated while the user is selecting files in the dialog, even before the
+ final selection has been made.
+
+ \sa selectedFiles, currentFile, currentFolder
+*/
+QList<QUrl> QQuickFileDialog::currentFiles() const
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ return fileDialog->selectedFiles();
+ return m_options->initiallySelectedFiles();
+}
+
+void QQuickFileDialog::setCurrentFiles(const QList<QUrl> &currentFiles)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
+ for (const QUrl &file : currentFiles)
+ fileDialog->selectFile(file);
+ }
+ m_options->setInitiallySelectedFiles(currentFiles);
+}
+
+/*!
+ \qmlproperty url QtQuick.Dialogs::FileDialog::currentFolder
+
+ This property holds the folder where files are selected. It can be set to
+ control the initial directory that is shown when the dialog is opened.
+
+\omit
+ For selecting a folder, use FolderDialog instead.
+
+ \sa FolderDialog
+\endomit
+*/
+QUrl QQuickFileDialog::currentFolder() const
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ return fileDialog->directory();
+
+ // If we're not using a native file dialog and the folder is invalid,
+ // return the current directory.
+ if (!m_options->initialDirectory().isValid())
+ return QUrl::fromLocalFile(QDir::currentPath());
+
+ return m_options->initialDirectory();
+}
+
+void QQuickFileDialog::setCurrentFolder(const QUrl &currentFolder)
+{
+ qCDebug(lcFileDialog) << "setCurrentFolder called with" << currentFolder;
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle()))
+ fileDialog->setDirectory(currentFolder);
+ m_options->setInitialDirectory(currentFolder);
+}
+
+/*!
+ \qmlproperty flags QtQuick.Dialogs::FileDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value FileDialog.DontResolveSymlinks Don't resolve symlinks in the file dialog. By default symlinks are resolved.
+ \value FileDialog.DontConfirmOverwrite Don't ask for confirmation if an existing file is selected. By default confirmation is requested.
+ \value FileDialog.ReadOnly Indicates that the dialog doesn't allow creating directories.
+ \value FileDialog.HideNameFilterDetails Indicates if the file name filter details are hidden or not.
+*/
+QFileDialogOptions::FileDialogOptions QQuickFileDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickFileDialog::setOptions(QFileDialogOptions::FileDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+void QQuickFileDialog::resetOptions()
+{
+ setOptions({});
+}
+
+/*!
+ \qmlproperty list<string> QtQuick.Dialogs::FileDialog::nameFilters
+
+ This property holds the filters that restrict the types of files that
+ can be selected.
+
+ \code
+ FileDialog {
+ nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)"]
+ }
+ \endcode
+
+ Different platforms may restrict the files that can be selected in
+ different ways. For example, macOS will disable file entries that do not
+ match the filters, whereas Windows will hide them.
+
+ \note \b{*.*} is not a portable filter, because the historical assumption
+ that the file extension determines the file type is not consistent on every
+ operating system. It is possible to have a file with no dot in its name (for
+ example, \c Makefile). In a native Windows file dialog, \b{*.*} will match
+ such files, while in other types of file dialogs it may not. So it is better
+ to use \b{*} if you mean to select any file.
+
+ \sa selectedNameFilter
+*/
+QStringList QQuickFileDialog::nameFilters() const
+{
+ return m_options->nameFilters();
+}
+
+void QQuickFileDialog::setNameFilters(const QStringList &filters)
+{
+ qCDebug(lcFileDialog).nospace() << "setNameFilters called with " << filters
+ << " (old filters were: " << m_options->nameFilters() << ")";
+ if (filters == m_options->nameFilters())
+ return;
+
+ m_options->setNameFilters(filters);
+ if (m_selectedNameFilter) {
+ int index = m_selectedNameFilter->index();
+ if (index < 0 || index >= filters.count())
+ index = 0;
+ m_selectedNameFilter->update(filters.value(index));
+ }
+ emit nameFiltersChanged();
+}
+
+void QQuickFileDialog::resetNameFilters()
+{
+ setNameFilters(QStringList());
+}
+
+/*!
+ \qmlproperty int QtQuick.Dialogs::FileDialog::selectedNameFilter.index
+ \qmlproperty string QtQuick.Dialogs::FileDialog::selectedNameFilter.name
+ \qmlproperty list<string> QtQuick.Dialogs::FileDialog::selectedNameFilter.extensions
+ \qmlproperty list<string> QtQuick.Dialogs::FileDialog::selectedNameFilter.globs
+
+ These properties hold the currently selected name filter.
+
+ \table
+ \header
+ \li Name
+ \li Description
+ \row
+ \li \b index : int
+ \li This property determines which \l {nameFilters}{name filter} is selected.
+ The specified filter is selected when the dialog is opened. The value is
+ updated when the user selects another filter.
+ \row
+ \li [read-only] \b name : string
+ \li This property holds the name of the selected filter. In the
+ example below, the name of the first filter is \c {"Text files"}
+ and the second is \c {"HTML files"}.
+ \row
+ \li [read-only] \b extensions : list<string>
+ \li This property holds the list of extensions of the selected filter.
+ In the example below, the list of extensions of the first filter is
+ \c {["txt"]} and the second is \c {["html", "htm"]}.
+ \row
+ \li [read-only] \b globs : list<string>
+ \li This property holds the list of globs of the selected filter.
+ In the example below, the list of globs of the first filter is
+ \c {["*.txt"]} and the second is \c {["*.html", "*.htm"]}.
+
+ This property is useful in conjunction with \l {FolderListModel}'s
+ \l {FolderListModel::}{nameFilters} property, for example.
+ \endtable
+
+ \code
+ FileDialog {
+ id: fileDialog
+ selectedNameFilter.index: 1
+ nameFilters: ["Text files (*.txt)", "HTML files (*.html *.htm)"]
+ }
+
+ MyDocument {
+ id: document
+ fileType: fileDialog.selectedNameFilter.extensions[0]
+ }
+ \endcode
+
+ \sa nameFilters
+*/
+QQuickFileNameFilter *QQuickFileDialog::selectedNameFilter() const
+{
+ if (!m_selectedNameFilter) {
+ QQuickFileDialog *that = const_cast<QQuickFileDialog *>(this);
+ m_selectedNameFilter = new QQuickFileNameFilter(that);
+ m_selectedNameFilter->setOptions(m_options);
+ }
+ return m_selectedNameFilter;
+}
+
+/*!
+ \qmlproperty string QtQuick.Dialogs::FileDialog::defaultSuffix
+
+ This property holds a suffix that is added to selected files that have
+ no suffix specified. The suffix is typically used to indicate the file
+ type (e.g. "txt" indicates a text file).
+
+ If the first character is a dot ('.'), it is removed.
+*/
+QString QQuickFileDialog::defaultSuffix() const
+{
+ return m_options->defaultSuffix();
+}
+
+void QQuickFileDialog::setDefaultSuffix(const QString &suffix)
+{
+ if (suffix == m_options->defaultSuffix())
+ return;
+
+ m_options->setDefaultSuffix(suffix);
+ emit defaultSuffixChanged();
+}
+
+void QQuickFileDialog::resetDefaultSuffix()
+{
+ setDefaultSuffix(QString());
+}
+
+/*!
+ \qmlproperty string QtQuick.Dialogs::FileDialog::acceptLabel
+
+ This property holds the label text shown on the button that accepts the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Open or \uicontrol Save depending on which
+ \l fileMode the dialog is used in.
+
+ The default value is an empty string.
+
+ \sa rejectLabel
+*/
+QString QQuickFileDialog::acceptLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Accept);
+}
+
+void QQuickFileDialog::setAcceptLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Accept))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Accept, label);
+ emit acceptLabelChanged();
+}
+
+void QQuickFileDialog::resetAcceptLabel()
+{
+ setAcceptLabel(QString());
+}
+
+/*!
+ \qmlproperty string QtQuick.Dialogs::FileDialog::rejectLabel
+
+ This property holds the label text shown on the button that rejects the dialog.
+
+ When set to an empty string, the default label of the underlying platform is used.
+ The default label is typically \uicontrol Cancel.
+
+ The default value is an empty string.
+
+ \sa acceptLabel
+*/
+QString QQuickFileDialog::rejectLabel() const
+{
+ return m_options->labelText(QFileDialogOptions::Reject);
+}
+
+void QQuickFileDialog::setRejectLabel(const QString &label)
+{
+ if (label == m_options->labelText(QFileDialogOptions::Reject))
+ return;
+
+ m_options->setLabelText(QFileDialogOptions::Reject, label);
+ emit rejectLabelChanged();
+}
+
+void QQuickFileDialog::resetRejectLabel()
+{
+ setRejectLabel(QString());
+}
+
+bool QQuickFileDialog::useNativeDialog() const
+{
+ if (!QQuickAbstractDialog::useNativeDialog())
+ return false;
+
+ if (m_options->testOption(QFileDialogOptions::DontUseNativeDialog)) {
+ qCDebug(lcDialogs) << " - the FileDialog was told not to use a native dialog; not using native dialog";
+ return false;
+ }
+
+ return true;
+}
+
+void QQuickFileDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickFileDialog::currentFileChanged);
+ connect(fileDialog, &QPlatformFileDialogHelper::currentChanged, this, &QQuickFileDialog::currentFilesChanged);
+ connect(fileDialog, &QPlatformFileDialogHelper::directoryEntered, this, &QQuickFileDialog::currentFolderChanged);
+ fileDialog->setOptions(m_options);
+ }
+}
+
+void QQuickFileDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ // Ensure that a name filter is always selected.
+ int index = selectedNameFilter()->index();
+ if (index == -1)
+ index = 0;
+ const QString filter = m_options->nameFilters().value(index);
+ m_options->setInitiallySelectedNameFilter(filter);
+
+ fileDialog->setOptions(m_options); // setOptions only assigns a member and isn't virtual
+
+ connect(fileDialog, &QPlatformFileDialogHelper::filterSelected, m_selectedNameFilter, &QQuickFileNameFilter::update);
+ fileDialog->selectNameFilter(filter);
+
+ const QUrl initialDir = m_options->initialDirectory();
+ // If it's not valid, or it's a file and not a directory, we shouldn't set it.
+ if (m_firstShow && initialDir.isValid() && QDir(QQmlFile::urlToLocalFileOrQrc(initialDir)).exists())
+ fileDialog->setDirectory(m_options->initialDirectory());
+ }
+ if (m_firstShow)
+ m_firstShow = false;
+}
+
+void QQuickFileDialog::onHide(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(dialog)) {
+ if (m_selectedNameFilter)
+ disconnect(fileDialog, &QPlatformFileDialogHelper::filterSelected, m_selectedNameFilter, &QQuickFileNameFilter::update);
+ }
+}
+
+void QQuickFileDialog::accept()
+{
+ if (QPlatformFileDialogHelper *fileDialog = qobject_cast<QPlatformFileDialogHelper *>(handle())) {
+ // Take the currently selected files and make them the final set of files.
+ setSelectedFiles(fileDialog->selectedFiles());
+ }
+ QQuickAbstractDialog::accept();
+}
+
+QUrl QQuickFileDialog::addDefaultSuffix(const QUrl &file) const
+{
+ QUrl url = file;
+ const QString path = url.path();
+ const QString suffix = m_options->defaultSuffix();
+ // Urls with "content" scheme do not require suffixes. Such schemes are
+ // used on Android.
+ const bool isContentScheme = url.scheme() == u"content"_qs;
+ if (!isContentScheme && !suffix.isEmpty() && !path.endsWith(QLatin1Char('/'))
+ && path.lastIndexOf(QLatin1Char('.')) == -1) {
+ url.setPath(path + QLatin1Char('.') + suffix);
+ }
+ return url;
+}
+
+QList<QUrl> QQuickFileDialog::addDefaultSuffixes(const QList<QUrl> &files) const
+{
+ QList<QUrl> urls;
+ urls.reserve(files.size());
+ for (const QUrl &file : files)
+ urls += addDefaultSuffix(file);
+ return urls;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfiledialog_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2/qquickfiledialog_p.h b/src/quickdialogs2/quickdialogs2/qquickfiledialog_p.h
new file mode 100644
index 0000000000..0dccbe727c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickfiledialog_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFILEDIALOG_P_H
+#define QQUICKFILEDIALOG_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 <QtQml/qqml.h>
+
+#include "qquickabstractdialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFileNameFilter;
+
+class Q_QUICKDIALOGS2_PRIVATE_EXPORT QQuickFileDialog : public QQuickAbstractDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(FileMode fileMode READ fileMode WRITE setFileMode NOTIFY fileModeChanged FINAL)
+ Q_PROPERTY(QUrl selectedFile READ selectedFile NOTIFY selectedFileChanged FINAL)
+ Q_PROPERTY(QList<QUrl> selectedFiles READ selectedFiles NOTIFY selectedFilesChanged FINAL)
+ Q_PROPERTY(QUrl currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged FINAL)
+ Q_PROPERTY(QList<QUrl> currentFiles READ currentFiles WRITE setCurrentFiles NOTIFY currentFilesChanged FINAL)
+ Q_PROPERTY(QUrl currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged FINAL)
+ Q_PROPERTY(QFileDialogOptions::FileDialogOptions options READ options WRITE setOptions RESET resetOptions NOTIFY optionsChanged FINAL)
+ Q_PROPERTY(QStringList nameFilters READ nameFilters WRITE setNameFilters RESET resetNameFilters NOTIFY nameFiltersChanged FINAL)
+ Q_PROPERTY(QQuickFileNameFilter *selectedNameFilter READ selectedNameFilter CONSTANT)
+ Q_PROPERTY(QString defaultSuffix READ defaultSuffix WRITE setDefaultSuffix RESET resetDefaultSuffix NOTIFY defaultSuffixChanged FINAL)
+ Q_PROPERTY(QString acceptLabel READ acceptLabel WRITE setAcceptLabel RESET resetAcceptLabel NOTIFY acceptLabelChanged FINAL)
+ Q_PROPERTY(QString rejectLabel READ rejectLabel WRITE setRejectLabel RESET resetRejectLabel NOTIFY rejectLabelChanged FINAL)
+ Q_FLAGS(QFileDialogOptions::FileDialogOptions)
+ QML_NAMED_ELEMENT(FileDialog)
+ QML_ADDED_IN_VERSION(6, 2)
+ Q_MOC_INCLUDE(<QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>)
+
+public:
+ explicit QQuickFileDialog(QObject *parent = nullptr);
+
+ enum FileMode {
+ OpenFile,
+ OpenFiles,
+ SaveFile
+ };
+ Q_ENUM(FileMode)
+
+ FileMode fileMode() const;
+ void setFileMode(FileMode fileMode);
+
+ QUrl selectedFile() const;
+
+ QList<QUrl> selectedFiles() const;
+
+ QUrl currentFile() const;
+ void setCurrentFile(const QUrl &file);
+
+ QList<QUrl> currentFiles() const;
+ void setCurrentFiles(const QList<QUrl> &currentFiles);
+
+ QUrl currentFolder() const;
+ void setCurrentFolder(const QUrl &currentFolder);
+
+ QFileDialogOptions::FileDialogOptions options() const;
+ void setOptions(QFileDialogOptions::FileDialogOptions options);
+ void resetOptions();
+
+ QStringList nameFilters() const;
+ void setNameFilters(const QStringList &filters);
+ void resetNameFilters();
+
+ QQuickFileNameFilter *selectedNameFilter() const;
+
+ QString defaultSuffix() const;
+ void setDefaultSuffix(const QString &suffix);
+ void resetDefaultSuffix();
+
+ QString acceptLabel() const;
+ void setAcceptLabel(const QString &label);
+ void resetAcceptLabel();
+
+ QString rejectLabel() const;
+ void setRejectLabel(const QString &label);
+ void resetRejectLabel();
+
+Q_SIGNALS:
+ void fileModeChanged();
+ void selectedFileChanged();
+ void selectedFilesChanged();
+ void currentFileChanged();
+ void currentFilesChanged();
+ void currentFolderChanged();
+ void optionsChanged();
+ void nameFiltersChanged();
+ void defaultSuffixChanged();
+ void acceptLabelChanged();
+ void rejectLabelChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void onHide(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QUrl addDefaultSuffix(const QUrl &file) const;
+ QList<QUrl> addDefaultSuffixes(const QList<QUrl> &files) const;
+
+ void setSelectedFiles(const QList<QUrl> &selectedFiles);
+
+ FileMode m_fileMode;
+ QList<QUrl> m_selectedFiles;
+ bool m_firstShow = true;
+ QSharedPointer<QFileDialogOptions> m_options;
+ mutable QQuickFileNameFilter *m_selectedNameFilter;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFileDialog)
+
+#endif // QQUICKFILEDIALOG_P_H
diff --git a/src/quickdialogs2/quickdialogs2/qquickfontdialog.cpp b/src/quickdialogs2/quickdialogs2/qquickfontdialog.cpp
new file mode 100644
index 0000000000..9472259dae
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickfontdialog.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFONTDIALOG_CPP
+#define QQUICKFONTDIALOG_CPP
+
+#include "qquickfontdialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype FontDialog
+ \inherits Dialog
+//! \instantiates QQuickFontDialog
+ \inqmlmodule QtQuick.Dialogs
+ \since 6.2
+ \brief A font dialog.
+
+ The FontDialog type provides a QML API for font dialogs.
+
+ \image qtquickdialogs-fontdialog-gtk.png
+
+ To show a font dialog, construct an instance of FontDialog, set the
+ desired properties, and call \l {Dialog::}{open()}. The \l currentFont
+ property can be used to determine the currently selected font in the
+ dialog. The \l selectedFont property is updated only after the final selection
+ has been made by accepting the dialog.
+
+ \code
+ MenuItem {
+ text: "Font"
+ onTriggered: fontDialog.open()
+ }
+
+ FontDialog {
+ id: fontDialog
+ currentFont.family: document.font
+ }
+
+ MyDocument {
+ id: document
+ font: fontDialog.selectedFont
+ }
+ \endcode
+
+ \section2 Availability
+
+ A native platform font dialog is currently available on the following platforms:
+
+ \list
+ \li macOS
+ \li Linux (when running with the GTK+ platform theme)
+ \endlist
+
+ \include includes/fallback.qdocinc
+*/
+
+Q_LOGGING_CATEGORY(lcFontDialog, "qt.quick.dialogs.fontdialog")
+
+QQuickFontDialog::QQuickFontDialog(QObject *parent)
+ : QQuickAbstractDialog(QPlatformTheme::FontDialog, parent),
+ m_options(QFontDialogOptions::create())
+{
+}
+
+/*!
+ \qmlproperty font QtQuick.Dialogs::FontDialog::currentFont
+
+ This property holds the currently selected font in the dialog.
+
+ Unlike the \l selectedFont property, the \c currentFont property is updated
+ while the user is selecting fonts in the dialog, even before the final
+ selection has been made.
+
+ \sa selectedFont
+*/
+
+QFont QQuickFontDialog::currentFont() const
+{
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(handle()))
+ return fontDialog->currentFont();
+ return QFont();
+}
+
+void QQuickFontDialog::setCurrentFont(const QFont &font)
+{
+ if (QPlatformFontDialogHelper *fontDialog =
+ qobject_cast<QPlatformFontDialogHelper *>(handle()))
+ fontDialog->setCurrentFont(font);
+}
+
+/*!
+ \qmlproperty font QtQuick.Dialogs::FontDialog::selectedFont
+
+ This property holds the final accepted font.
+
+ Unlike the \l currentFont property, the \c selectedFont property is not updated
+ while the user is selecting fonts in the dialog, but only after the final
+ selection has been made. That is, when the user has clicked \uicontrol Open
+ to accept a font. Alternatively, the \l {Dialog::}{accepted()} signal
+ can be handled to get the final selection.
+
+ \sa currentFont, {Dialog::}{accepted()}
+*/
+
+QFont QQuickFontDialog::selectedFont() const
+{
+ return m_selectedFont;
+}
+
+void QQuickFontDialog::setSelectedFont(const QFont &font)
+{
+ if (m_selectedFont == font)
+ return;
+
+ m_selectedFont = font;
+ emit selectedFontChanged();
+}
+
+/*!
+ \qmlproperty flags QtQuick.Dialogs::FontDialog::options
+
+ This property holds the various options that affect the look and feel of the dialog.
+
+ By default, all options are disabled.
+
+ Options should be set before showing the dialog. Setting them while the dialog is
+ visible is not guaranteed to have an immediate effect on the dialog (depending on
+ the option and on the platform).
+
+ Available options:
+ \value FontDialog.ScalableFonts Show scalable fonts.
+ \value FontDialog.NonScalableFonts Show non-scalable fonts.
+ \value FontDialog.MonospacedFonts Show monospaced fonts.
+ \value FontDialog.ProportionalFonts Show proportional fonts.
+ \value FontDialog.NoButtons Don't display \uicontrol Open and \uicontrol Cancel buttons (useful
+ for "live dialogs").
+*/
+
+QFontDialogOptions::FontDialogOptions QQuickFontDialog::options() const
+{
+ return m_options->options();
+}
+
+void QQuickFontDialog::setOptions(QFontDialogOptions::FontDialogOptions options)
+{
+ if (options == m_options->options())
+ return;
+
+ m_options->setOptions(options);
+ emit optionsChanged();
+}
+
+void QQuickFontDialog::resetOptions()
+{
+ setOptions({});
+}
+
+bool QQuickFontDialog::useNativeDialog() const
+{
+ return QQuickAbstractDialog::useNativeDialog()
+ && !(m_options->testOption(QFontDialogOptions::DontUseNativeDialog));
+}
+
+void QQuickFontDialog::onCreate(QPlatformDialogHelper *dialog)
+{
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(dialog)) {
+ connect(fontDialog, &QPlatformFontDialogHelper::currentFontChanged, this,
+ &QQuickFontDialog::currentFontChanged);
+ connect(fontDialog, &QPlatformFontDialogHelper::fontSelected, this,
+ &QQuickFontDialog::setSelectedFont);
+ fontDialog->setOptions(m_options);
+ }
+}
+
+void QQuickFontDialog::onShow(QPlatformDialogHelper *dialog)
+{
+ m_options->setWindowTitle(title());
+ if (QPlatformFontDialogHelper *fontDialog = qobject_cast<QPlatformFontDialogHelper *>(dialog))
+ fontDialog->setOptions(m_options); // setOptions only assigns a member and isn't virtual
+}
+
+void QQuickFontDialog::accept()
+{
+ if (auto fontDialog = qobject_cast<QPlatformFontDialogHelper *>(handle()))
+ setSelectedFont(fontDialog->currentFont());
+ QQuickAbstractDialog::accept();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfontdialog_p.cpp"
+
+#endif // QQUICKFONTDIALOG_CPP
diff --git a/src/quickdialogs2/quickdialogs2/qquickfontdialog_p.h b/src/quickdialogs2/quickdialogs2/qquickfontdialog_p.h
new file mode 100644
index 0000000000..c12cbd6298
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qquickfontdialog_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFONTDIALOG_P_H
+#define QQUICKFONTDIALOG_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 "qquickabstractdialog_p.h"
+
+#include <QtGui/qfont.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKDIALOGS2_PRIVATE_EXPORT QQuickFontDialog : public QQuickAbstractDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont selectedFont READ selectedFont WRITE setSelectedFont NOTIFY selectedFontChanged)
+ Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged FINAL)
+ Q_PROPERTY(QFontDialogOptions::FontDialogOptions options READ options WRITE setOptions
+ RESET resetOptions NOTIFY optionsChanged)
+ Q_FLAGS(QFontDialogOptions::FontDialogOptions)
+ QML_NAMED_ELEMENT(FontDialog)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ explicit QQuickFontDialog(QObject *parent = nullptr);
+
+ void setCurrentFont(const QFont &font);
+ QFont currentFont() const;
+
+ void setSelectedFont(const QFont &font);
+ QFont selectedFont() const;
+
+ QFontDialogOptions::FontDialogOptions options() const;
+ void setOptions(QFontDialogOptions::FontDialogOptions options);
+ void resetOptions();
+
+Q_SIGNALS:
+ void selectedFontChanged();
+ void currentFontChanged();
+ void optionsChanged();
+
+protected:
+ bool useNativeDialog() const override;
+ void onCreate(QPlatformDialogHelper *dialog) override;
+ void onShow(QPlatformDialogHelper *dialog) override;
+ void accept() override;
+
+private:
+ QFont m_selectedFont;
+ QSharedPointer<QFontDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFontDialog)
+
+#endif // QQUICKFONTDIALOG_P_H
diff --git a/src/quickdialogs2/quickdialogs2/qtquickdialogs2foreign_p.h b/src/quickdialogs2/quickdialogs2/qtquickdialogs2foreign_p.h
new file mode 100644
index 0000000000..8af454a6f8
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qtquickdialogs2foreign_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKDIALOGS2FOREIGN_P_H
+#define QTQUICKDIALOGS2FOREIGN_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/qpa/qplatformdialoghelper.h>
+#include <QtQml/qqml.h>
+#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QPlatformDialogHelperForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QPlatformDialogHelper)
+ QML_ADDED_IN_VERSION(6, 2)
+};
+
+struct QQuickFileNameFilterQuickDialogs2Foreign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickFileNameFilter)
+ QML_ADDED_IN_VERSION(6, 2)
+};
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKDIALOGS2FOREIGN_P_H
diff --git a/src/quickdialogs2/quickdialogs2/qtquickdialogs2global_p.h b/src/quickdialogs2/quickdialogs2/qtquickdialogs2global_p.h
new file mode 100644
index 0000000000..cae55a95a3
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2/qtquickdialogs2global_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKDIALOGS2GLOBAL_P_H
+#define QTQUICKDIALOGS2GLOBAL_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>
+#include <QtQml/private/qqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKDIALOGS2_LIB)
+# define Q_QUICKDIALOGS2_PRIVATE_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKDIALOGS2_PRIVATE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKDIALOGS2_PRIVATE_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKDIALOGS2GLOBAL_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/CMakeLists.txt b/src/quickdialogs2/quickdialogs2quickimpl/CMakeLists.txt
new file mode 100644
index 0000000000..caec15b097
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/CMakeLists.txt
@@ -0,0 +1,146 @@
+#####################################################################
+## QuickDialogs2QuickImpl Module:
+#####################################################################
+
+set(qml_files
+ "qml/FileDialog.qml"
+ "qml/FileDialogDelegate.qml"
+ "qml/FileDialogDelegateLabel.qml"
+ "qml/FolderBreadcrumbBar.qml"
+ "qml/FontDialog.qml"
+ "qml/FontDialogContent.qml"
+ "qml/+Fusion/FileDialog.qml"
+ "qml/+Fusion/FileDialogDelegate.qml"
+ "qml/+Fusion/FolderBreadcrumbBar.qml"
+ "qml/+Fusion/FontDialog.qml"
+ "qml/+Imagine/FileDialog.qml"
+ "qml/+Imagine/FileDialogDelegate.qml"
+ "qml/+Imagine/FolderBreadcrumbBar.qml"
+ "qml/+Imagine/FontDialog.qml"
+ "qml/+Material/FileDialog.qml"
+ "qml/+Material/FileDialogDelegate.qml"
+ "qml/+Material/FolderBreadcrumbBar.qml"
+ "qml/+Material/FontDialog.qml"
+ "qml/+Universal/FileDialog.qml"
+ "qml/+Universal/FileDialogDelegate.qml"
+ "qml/+Universal/FolderBreadcrumbBar.qml"
+ "qml/+Universal/FontDialog.qml"
+)
+
+qt_internal_add_qml_module(QuickDialogs2QuickImpl
+ URI "QtQuick.Dialogs.quickimpl"
+ VERSION "${PROJECT_VERSION}"
+ CLASS_NAME QtQuickDialogs2QuickImplPlugin
+ PLUGIN_TARGET qtquickdialogs2quickimplplugin
+ DEPENDENCIES
+ QtQuick/auto
+ QtQuick.Templates/auto
+ SOURCES
+ qquickdialogimplfactory.cpp
+ qquickdialogimplfactory_p.h
+ qquickfiledialogdelegate.cpp
+ qquickfiledialogdelegate_p.h
+ qquickfiledialogimpl.cpp
+ qquickfiledialogimpl_p.h
+ qquickfiledialogimpl_p_p.h
+ qquickfolderbreadcrumbbar.cpp
+ qquickfolderbreadcrumbbar_p.h
+ qquickfolderbreadcrumbbar_p_p.h
+ qquickplatformfiledialog.cpp
+ qquickplatformfiledialog_p.h
+ qquickplatformfontdialog_p.h
+ qquickplatformfontdialog.cpp
+ qtquickdialogs2quickimplforeign_p.h
+ qtquickdialogs2quickimplglobal_p.h
+ qquickfontdialogimpl_p.h
+ qquickfontdialogimpl_p_p.h
+ qquickfontdialogimpl.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_BUILD_QUICKDIALOGS2QUICKIMPL_LIB
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ Qt::QuickTemplates2
+ Qt::QuickTemplates2Private
+ Qt::QuickDialogs2Utils
+ Qt::QuickDialogs2UtilsPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+# Resources:
+set(qtquickdialogs2quickimpl_resource_files
+ "images/crumb-separator-icon-round.png"
+ "images/crumb-separator-icon-round@2x.png"
+ "images/crumb-separator-icon-round@3x.png"
+ "images/crumb-separator-icon-round@4x.png"
+ "images/crumb-separator-icon-square.png"
+ "images/crumb-separator-icon-square@2x.png"
+ "images/crumb-separator-icon-square@3x.png"
+ "images/crumb-separator-icon-square@4x.png"
+ "images/file-icon-round.png"
+ "images/file-icon-round@2x.png"
+ "images/file-icon-round@3x.png"
+ "images/file-icon-round@4x.png"
+ "images/file-icon-square.png"
+ "images/file-icon-square@2x.png"
+ "images/file-icon-square@3x.png"
+ "images/file-icon-square@4x.png"
+ "images/folder-icon-round.png"
+ "images/folder-icon-round@2x.png"
+ "images/folder-icon-round@3x.png"
+ "images/folder-icon-round@4x.png"
+ "images/folder-icon-square.png"
+ "images/folder-icon-square@2x.png"
+ "images/folder-icon-square@3x.png"
+ "images/folder-icon-square@4x.png"
+ "images/imagine/filedialogdelegate-background@2x.9.png"
+ "images/imagine/filedialogdelegate-background@3x.9.png"
+ "images/imagine/filedialogdelegate-background@4x.9.png"
+ "images/imagine/filedialogdelegate-background.9.png"
+ "images/imagine/filedialogdelegate-background-disabled@2x.9.png"
+ "images/imagine/filedialogdelegate-background-disabled@3x.9.png"
+ "images/imagine/filedialogdelegate-background-disabled@4x.9.png"
+ "images/imagine/filedialogdelegate-background-disabled.9.png"
+ "images/imagine/filedialogdelegate-background-pressed@2x.9.png"
+ "images/imagine/filedialogdelegate-background-pressed@3x.9.png"
+ "images/imagine/filedialogdelegate-background-pressed@4x.9.png"
+ "images/imagine/filedialogdelegate-background-pressed.9.png"
+ "images/imagine/filedialogdelegate-background-focused@2x.9.png"
+ "images/imagine/filedialogdelegate-background-focused@3x.9.png"
+ "images/imagine/filedialogdelegate-background-focused@4x.9.png"
+ "images/imagine/filedialogdelegate-background-focused.9.png"
+ "images/imagine/filedialogdelegate-background-highlighted@2x.9.png"
+ "images/imagine/filedialogdelegate-background-highlighted@3x.9.png"
+ "images/imagine/filedialogdelegate-background-highlighted@4x.9.png"
+ "images/imagine/filedialogdelegate-background-highlighted.9.png"
+ "images/up-icon-round.png"
+ "images/up-icon-round@2x.png"
+ "images/up-icon-round@3x.png"
+ "images/up-icon-round@4x.png"
+ "images/up-icon-square.png"
+ "images/up-icon-square@2x.png"
+ "images/up-icon-square@3x.png"
+ "images/up-icon-square@4x.png"
+ "images/up-icon-thick-square.png"
+ "images/up-icon-thick-square@2x.png"
+ "images/up-icon-thick-square@3x.png"
+ "images/up-icon-thick-square@4x.png"
+)
+
+qt_internal_add_resource(QuickDialogs2QuickImpl "QuickDialogs2QuickImpl"
+ PREFIX
+ "/qt-project.org/imports/QtQuick/Dialogs/quickimpl"
+ FILES
+ ${qtquickdialogs2quickimpl_resource_files}
+)
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.png
new file mode 100644
index 0000000000..aaa5a3e431
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.svg
new file mode 100644
index 0000000000..013cedefa3
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round.svg
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="8"
+ height="8"
+ viewBox="0 0 8 8"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="crumb-separator-icon-round.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8">
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect3421"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1367"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1365"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="16.000001"
+ inkscape:cx="6.7812496"
+ inkscape:cy="15.031249"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0"
+ height="14px">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="crumb-separator-icon-round"
+ transform="translate(2.046,3.0914383)">
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect2017"
+ width="8"
+ height="8"
+ x="-2.046"
+ y="-3.0914383" />
+ </g>
+ <path
+ id="rect858"
+ style="fill:#757575;stroke-width:2.43737;stroke-linejoin:round"
+ d="M 3.0219754,1.01117 6.416287,3.5317721 a 0.74259596,0.74259596 90 0 1 0,1.1923778 L 3.0219754,7.2447519 A 0.5029757,0.5029757 26.701285 0 1 2.2191312,6.8409408 l 0,-5.4259596 A 0.5029757,0.5029757 153.29872 0 1 3.0219754,1.01117 Z"
+ sodipodi:nodetypes="cccc"
+ inkscape:path-effect="#path-effect3421"
+ inkscape:original-d="m 2.2191312,0.41498117 5,3.71297983 -5,3.7129798 z" />
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect1449"
+ width="8"
+ height="8"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@2x.png
new file mode 100644
index 0000000000..3f66fe172b
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@3x.png
new file mode 100644
index 0000000000..24d9f6a64e
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@4x.png
new file mode 100644
index 0000000000..1dc83ef09f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-round@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.png
new file mode 100644
index 0000000000..1f7ac63e7f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.svg
new file mode 100644
index 0000000000..9663673470
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square.svg
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="8"
+ height="8"
+ viewBox="0 0 8 8"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="crumb-separator-icon-square.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8">
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect3421"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1367"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1365"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="90.509672"
+ inkscape:cx="4.43599"
+ inkscape:cy="3.3311357"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0"
+ height="14px">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="crumb-separator-icon-square"
+ transform="translate(2.046,3.0914383)">
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect2017"
+ width="8"
+ height="8"
+ x="-2.046"
+ y="-3.0914383" />
+ <path
+ style="fill:#757575;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m -0.046,-2.0914383 4,3 -4,3 z"
+ id="path1065"
+ sodipodi:nodetypes="cccc" />
+ </g>
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect1449"
+ width="8"
+ height="8"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@2x.png
new file mode 100644
index 0000000000..524872c1e9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@3x.png
new file mode 100644
index 0000000000..33bce847c8
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@4x.png
new file mode 100644
index 0000000000..185c3eb7ae
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/crumb-separator-icon-square@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.png
new file mode 100644
index 0000000000..c2a4928daf
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.svg
new file mode 100644
index 0000000000..7ac6a23b5c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round.svg
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="14"
+ height="18"
+ viewBox="0 0 14 18"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="file-icon-round.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1.5003822,2.5063148 1.5000273,15.5 A 0.99997269,0.99997269 45.000782 0 0 2.5,16.5 h 9 a 1,1 135 0 0 1,-1 V 6.3440001 A 2.3479106,2.3479106 66.930332 0 0 11.778973,4.6510931 L 9.221027,2.192907 A 2.4805476,2.4805476 21.904486 0 0 7.5000004,1.5009022 l -4.9995913,0.00451 A 1.0009299,1.0009299 134.97494 0 0 1.5003822,2.5063148 Z"
+ id="path917"
+ sodipodi:nodetypes="cccccc"
+ inkscape:path-effect="#path-effect1367"
+ inkscape:original-d="M 1.5004095,1.5063148 1.5,16.5 h 11 V 5.3440001 L 8.5,1.5 Z" />
+ <path
+ id="path921"
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 12.35,6.5 H 8.5 a 1,1 45 0 1 -1,-1 V 1.55"
+ inkscape:path-effect="#path-effect1365"
+ inkscape:original-d="M 12.35,6.5 H 7.5 V 1.55"
+ sodipodi:nodetypes="ccc" />
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8">
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1367"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1365"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,0,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="32.000001"
+ inkscape:cx="7.8906248"
+ inkscape:cy="9.7343747"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="file-icon-round"
+ transform="translate(2.046,3.0914383)" />
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect2270"
+ width="14"
+ height="18"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@2x.png
new file mode 100644
index 0000000000..86af70d1cf
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@3x.png
new file mode 100644
index 0000000000..06fea29ed0
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@4x.png
new file mode 100644
index 0000000000..09f8787314
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-round@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.png
new file mode 100644
index 0000000000..9e8f3ddd8f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.svg
new file mode 100644
index 0000000000..107afa385e
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="14"
+ height="18"
+ viewBox="0 0 14 18"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="file-icon-square.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1.5004095,1.5063148 1.5,16.5 h 11 V 5.3440001 L 8.5,1.5 Z"
+ id="path917"
+ sodipodi:nodetypes="cccccc" />
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 8.5,1.55 V 5.5"
+ id="path919"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 12.45,5.5 H 8.5"
+ id="path921"
+ sodipodi:nodetypes="cc" />
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="22.627417"
+ inkscape:cx="0.022097087"
+ inkscape:cy="8.1538251"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="file-icon-square"
+ transform="translate(2.046,3.0914383)" />
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect1895"
+ width="14"
+ height="18"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@2x.png
new file mode 100644
index 0000000000..8d33067744
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@3x.png
new file mode 100644
index 0000000000..2987d2caed
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@4x.png
new file mode 100644
index 0000000000..69d76176e9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/file-icon-square@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.png
new file mode 100644
index 0000000000..60bc6c72c1
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.svg
new file mode 100644
index 0000000000..ba6b627644
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round.svg
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="18"
+ height="14"
+ viewBox="0 0 18 14"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="folder-icon-round.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1.5003723,2.5063148 1.5000372,11.5 A 0.99996275,0.99996275 45.001067 0 0 2.5,12.5 h 13 a 1,1 135 0 0 1,-1 v -7 a 1,1 45 0 0 -1,-1 h -5 A 2.4142136,2.4142136 22.5 0 1 8.7928932,2.7928932 L 8.2071068,2.2071068 A 2.4106245,2.4106245 22.469847 0 0 6.5000006,1.5010525 l -3.9995917,0.00421 A 1.0010904,1.0010904 134.97091 0 0 1.5003723,2.5063148 Z"
+ id="path917"
+ sodipodi:nodetypes="ccccccc"
+ inkscape:path-effect="#path-effect1132"
+ inkscape:original-d="M 1.5004095,1.5063148 1.5,12.5 h 15 v -9 h -7 l -2,-2 z" />
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8">
+ <inkscape:path-effect
+ effect="fillet_chamfer"
+ id="path-effect1132"
+ is_visible="true"
+ lpeversion="1"
+ satellites_param="F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1 @ F,0,0,1,0,1,0,1"
+ unit="px"
+ method="auto"
+ mode="F"
+ radius="1"
+ chamfer_steps="1"
+ flexible="false"
+ use_knot_distance="true"
+ apply_no_radius="true"
+ apply_with_radius="true"
+ only_selected="false"
+ hide_knots="false" />
+ </defs>
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="-11.28125"
+ inkscape:cy="7.40625"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="folder-icon-round"
+ transform="translate(2.046,3.0914383)" />
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect2548"
+ width="18"
+ height="14"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@2x.png
new file mode 100644
index 0000000000..e28734374f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@3x.png
new file mode 100644
index 0000000000..5ee70a955e
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@4x.png
new file mode 100644
index 0000000000..47d28a4b75
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-round@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.png
new file mode 100644
index 0000000000..b84a90aecb
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.svg
new file mode 100644
index 0000000000..0002b5ac8e
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square.svg
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="18"
+ height="14"
+ viewBox="0 0 18 14"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="folder-icon-square.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <path
+ style="fill:none;stroke:#757575;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 1.5004095,1.5063148 1.5,12.5 h 15 v -9 h -7 l -2,-2 z"
+ id="path917"
+ sodipodi:nodetypes="ccccccc" />
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="-1.59375"
+ inkscape:cy="12.65625"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid856" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="folder-icon-square"
+ transform="translate(2.046,3.0914383)">
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect1423"
+ width="18"
+ height="14"
+ x="-2.046"
+ y="-3.0914383" />
+ </g>
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@2x.png
new file mode 100644
index 0000000000..9bf320bbf0
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@3x.png
new file mode 100644
index 0000000000..9f12edb6ee
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@4x.png
new file mode 100644
index 0000000000..9ec5b389bd
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/folder-icon-square@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled.9.png
new file mode 100644
index 0000000000..ce48ee7422
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@2x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@2x.9.png
new file mode 100644
index 0000000000..c7abb65c3f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@2x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@3x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@3x.9.png
new file mode 100644
index 0000000000..46b84d7da4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@3x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@4x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@4x.9.png
new file mode 100644
index 0000000000..f4dfd338f9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-disabled@4x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused.9.png
new file mode 100644
index 0000000000..39fa866442
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@2x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@2x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@3x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@3x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@4x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-focused@4x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted.9.png
new file mode 100644
index 0000000000..6f565e8be2
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@2x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@2x.9.png
new file mode 100644
index 0000000000..9fd0a434bb
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@2x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@3x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@3x.9.png
new file mode 100644
index 0000000000..62b7435b84
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@3x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@4x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@4x.9.png
new file mode 100644
index 0000000000..96444b8905
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-highlighted@4x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed.9.png
new file mode 100644
index 0000000000..39fa866442
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@2x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@2x.9.png
new file mode 100644
index 0000000000..6b61562c14
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@2x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@3x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@3x.9.png
new file mode 100644
index 0000000000..e46c0bf1d9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@3x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@4x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@4x.9.png
new file mode 100644
index 0000000000..010444e8e1
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background-pressed@4x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.9.png
new file mode 100644
index 0000000000..cef1bafab3
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.svg
new file mode 100644
index 0000000000..acecfcc9ac
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background.svg
@@ -0,0 +1,358 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="210mm"
+ height="297mm"
+ viewBox="0 0 210 297"
+ version="1.1"
+ id="svg5"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="filedialogdelegate-background.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata122">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ id="namedview7"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ objecttolerance="10.0"
+ gridtolerance="10.0"
+ guidetolerance="10.0"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ inkscape:pagecheckerboard="0"
+ inkscape:document-units="px"
+ showgrid="false"
+ inkscape:zoom="3.2715084"
+ inkscape:cx="24.912056"
+ inkscape:cy="54.867657"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="g1413"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:document-rotation="0">
+ <sodipodi:guide
+ position="6.0854167,296.96676"
+ orientation="-1,0"
+ id="guide2310"
+ inkscape:label=""
+ inkscape:locked="true"
+ inkscape:color="rgb(0,0,255)" />
+ <sodipodi:guide
+ position="3.363578,293.03125"
+ orientation="0,1"
+ id="guide2322"
+ inkscape:label=""
+ inkscape:locked="true"
+ inkscape:color="rgb(0,0,255)" />
+ <sodipodi:guide
+ position="12.170833,297.68429"
+ orientation="-1,0"
+ id="guide2760"
+ inkscape:label=""
+ inkscape:locked="true"
+ inkscape:color="rgb(0,0,255)" />
+ <sodipodi:guide
+ position="18.25625,297.91758"
+ orientation="-1,0"
+ id="guide949"
+ inkscape:label=""
+ inkscape:locked="true"
+ inkscape:color="rgb(0,0,255)" />
+ <sodipodi:guide
+ position="24.341667,299.40187"
+ orientation="-1,0"
+ id="guide941"
+ inkscape:label=""
+ inkscape:locked="true"
+ inkscape:color="rgb(0,0,255)" />
+ <sodipodi:guide
+ position="30.427083,299.08734"
+ orientation="-1,0"
+ id="guide1165"
+ inkscape:label=""
+ inkscape:locked="false"
+ inkscape:color="rgb(0,0,255)" />
+ </sodipodi:namedview>
+ <defs
+ id="defs2" />
+ <g
+ inkscape:label="[9] filedialogdelegate-background-highlighted"
+ inkscape:groupmode="layer"
+ id="g1413"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <rect
+ style="fill:none;stroke-width:0.946642;stroke-linejoin:round"
+ id="rect1401"
+ width="6.0854168"
+ height="3.96875"
+ x="30.427084"
+ y="-6.9388939e-18" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:7.98967;stroke-linejoin:round"
+ id="rect1403"
+ width="0.26458332"
+ height="3.4395833"
+ x="30.427084"
+ y="0.26458332" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10.1547;stroke-linejoin:round"
+ id="rect1405"
+ width="0.26458332"
+ height="5.5562401"
+ x="-0.26415125"
+ y="30.691679"
+ transform="matrix(3.6708238e-5,-1,1,1.4067378e-5,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect1407"
+ width="0.26458332"
+ height="0.26458287"
+ x="-3.9588995"
+ y="33.337505"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect1409"
+ width="0.26458332"
+ height="0.26458287"
+ x="-2.1059568"
+ y="36.247913"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#4fc1e9;fill-opacity:1;fill-rule:evenodd;stroke-width:0.263352"
+ id="rect1411"
+ width="5.5562501"
+ height="3.4395833"
+ x="30.691668"
+ y="0.26458332" />
+ </g>
+ <g
+ inkscape:label="[9] filedialogdelegate-background-focused"
+ inkscape:groupmode="layer"
+ id="g939"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <rect
+ style="fill:none;stroke-width:0.946642;stroke-linejoin:round"
+ id="rect927"
+ width="6.0854168"
+ height="3.96875"
+ x="18.25625"
+ y="-6.9388939e-18" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:7.98967;stroke-linejoin:round"
+ id="rect929"
+ width="0.26458332"
+ height="3.4395833"
+ x="18.25625"
+ y="0.26458332" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10.1547;stroke-linejoin:round"
+ id="rect931"
+ width="0.26458332"
+ height="5.5562401"
+ x="-0.26432261"
+ y="18.520845"
+ transform="matrix(3.6708238e-5,-1,1,1.4067378e-5,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect933"
+ width="0.26458332"
+ height="0.26458287"
+ x="-3.9624968"
+ y="21.166674"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect935"
+ width="0.26458332"
+ height="0.26458287"
+ x="-2.1095541"
+ y="24.077082"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#e6e9ed;fill-opacity:1;fill-rule:evenodd;stroke-width:0.263352"
+ id="rect937"
+ width="5.5562501"
+ height="3.4395833"
+ x="18.520834"
+ y="0.26458332" />
+ </g>
+ <g
+ inkscape:label="[9] filedialogdelegate-background-pressed"
+ inkscape:groupmode="layer"
+ id="g867"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <rect
+ style="fill:none;stroke-width:0.946642;stroke-linejoin:round"
+ id="rect855"
+ width="6.0854168"
+ height="3.96875"
+ x="12.170834"
+ y="-6.9388939e-18" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:7.98967;stroke-linejoin:round"
+ id="rect857"
+ width="0.26458332"
+ height="3.4395833"
+ x="12.170834"
+ y="0.26458332" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10.1547;stroke-linejoin:round"
+ id="rect859"
+ width="0.26458332"
+ height="5.5562401"
+ x="-0.26440823"
+ y="12.435429"
+ transform="matrix(3.6708238e-5,-1,1,1.4067378e-5,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect861"
+ width="0.26458332"
+ height="0.26458287"
+ x="-3.9642947"
+ y="15.081257"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect863"
+ width="0.26458332"
+ height="0.26458287"
+ x="-2.111352"
+ y="17.991665"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#e6e9ed;fill-opacity:1;fill-rule:evenodd;stroke-width:0.263352"
+ id="rect865"
+ width="5.5562501"
+ height="3.4395833"
+ x="12.435416"
+ y="0.26458332" />
+ </g>
+ <g
+ inkscape:label="[9] filedialogdelegate-background-disabled"
+ inkscape:groupmode="layer"
+ id="g2435"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <rect
+ style="fill:none;stroke-width:0.946642;stroke-linejoin:round"
+ id="rect2425"
+ width="6.0854168"
+ height="3.96875"
+ x="6.0854168"
+ y="-6.9388939e-18" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:7.98967;stroke-linejoin:round"
+ id="rect2427"
+ width="0.26458332"
+ height="3.4395833"
+ x="6.0854168"
+ y="0.26458332" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10.1547;stroke-linejoin:round"
+ id="rect2429"
+ width="0.26458332"
+ height="5.5562401"
+ x="-0.264494"
+ y="6.3500099"
+ transform="matrix(3.6708238e-5,-1,1,1.4067378e-5,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect2431"
+ width="0.26458332"
+ height="0.26458287"
+ x="-3.9660921"
+ y="8.995841"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect2433"
+ width="0.26458332"
+ height="0.26458287"
+ x="-2.1131494"
+ y="11.906255"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#f5f7fa;fill-opacity:1;fill-rule:evenodd;stroke-width:0.263352"
+ id="rect124"
+ width="5.5562501"
+ height="3.4395833"
+ x="6.3499999"
+ y="0.26458332" />
+ </g>
+ <g
+ inkscape:label="[9] filedialogdelegate-background"
+ inkscape:groupmode="layer"
+ id="layer1"
+ style="display:inline"
+ sodipodi:insensitive="true">
+ <rect
+ style="fill:none;stroke-width:0.946642;stroke-linejoin:round"
+ id="rect846"
+ width="6.0854168"
+ height="3.96875"
+ x="0"
+ y="-6.9388939e-18" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:7.98967;stroke-linejoin:round"
+ id="rect1054"
+ width="0.26458332"
+ height="3.4395833"
+ x="0"
+ y="0.26458332" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:10.1547;stroke-linejoin:round"
+ id="rect1212"
+ width="0.26458332"
+ height="5.5562401"
+ x="-0.26457959"
+ y="0.26459303"
+ transform="matrix(3.6708238e-5,-1,1,1.4067378e-5,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect1505"
+ width="0.26458332"
+ height="0.26458287"
+ x="-3.9678898"
+ y="2.9104238"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2.21594;stroke-linejoin:round"
+ id="rect1587"
+ width="0.26458332"
+ height="0.26458287"
+ x="-2.1149471"
+ y="5.8208375"
+ transform="matrix(1.7480114e-6,-1,0.99999996,2.9541491e-4,0,0)" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.0578;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect3108"
+ width="5.5562501"
+ height="3.4395833"
+ x="0.26458332"
+ y="0.26458332" />
+ </g>
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@2x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@2x.9.png
new file mode 100644
index 0000000000..5a136a0ca9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@2x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@3x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@3x.9.png
new file mode 100644
index 0000000000..f47a366b7b
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@3x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@4x.9.png b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@4x.9.png
new file mode 100644
index 0000000000..9ecb680f20
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/imagine/filedialogdelegate-background@4x.9.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.png
new file mode 100644
index 0000000000..a4b7bc0383
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.svg
new file mode 100644
index 0000000000..fd05395798
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round.svg
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="up-icon-round.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="16"
+ inkscape:cx="-1.96875"
+ inkscape:cy="10.65625"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid1497" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="up-icon-round" />
+ <g
+ id="g1413"
+ transform="translate(0.3592822,-0.0034197)">
+ <path
+ style="fill:none;fill-opacity:1;stroke:#757575;stroke-width:2.23721;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 7.6407178,2.1165354 3e-7,11.7737686"
+ id="path20"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-opacity:1;stroke:#757575;stroke-width:2.23721;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 7.6407178,2.1165354 2.6616436,7.0956099"
+ id="path950"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;fill-opacity:1;stroke:#757575;stroke-width:2.23721;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 7.6407178,2.1165354 12.619792,7.0956096"
+ id="path952"
+ sodipodi:nodetypes="cc" />
+ </g>
+ <rect
+ style="fill:none;stroke-width:5.33333;stroke-linejoin:round"
+ id="rect2897"
+ width="16"
+ height="16"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@2x.png
new file mode 100644
index 0000000000..25ee970a17
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@3x.png
new file mode 100644
index 0000000000..486f2f46a9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@4x.png
new file mode 100644
index 0000000000..585402531c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-round@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.png
new file mode 100644
index 0000000000..f7d4151a5a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.svg
new file mode 100644
index 0000000000..93fc45bae4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square.svg
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="up-icon-square.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="11.313709"
+ inkscape:cx="-6.3197669"
+ inkscape:cy="28.416854"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid1497" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="up-icon-square" />
+ <path
+ style="fill:#757575;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 8.000315,1 -6,6 L 3,8 8,3 13,8 14,7 Z"
+ id="path928"
+ sodipodi:nodetypes="ccccccc" />
+ <rect
+ style="fill:none;stroke-width:5.33333;stroke-linejoin:round"
+ id="rect2897"
+ width="16"
+ height="16"
+ x="0"
+ y="0" />
+ <rect
+ style="fill:#757575;fill-opacity:1;stroke:none;stroke-width:5.23075;stroke-linejoin:round"
+ id="rect4947"
+ width="1.5"
+ height="11"
+ x="7.2501574"
+ y="3" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@2x.png
new file mode 100644
index 0000000000..2e2a3d94eb
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@3x.png
new file mode 100644
index 0000000000..8965148c90
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@4x.png
new file mode 100644
index 0000000000..0a56bbcc0a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-square@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.png
new file mode 100644
index 0000000000..3f9f87624a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.svg b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.svg
new file mode 100644
index 0000000000..dd20777be7
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ width="16"
+ height="16"
+ viewBox="0 0 16 16"
+ version="1.1"
+ id="svg2"
+ inkscape:version="1.1-alpha (b0f32e08fc, 2021-03-07)"
+ sodipodi:docname="up-icon-thick-square.svg"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <metadata
+ id="metadata10">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs8" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview6"
+ showgrid="true"
+ inkscape:zoom="22.627417"
+ inkscape:cx="2.3201941"
+ inkscape:cy="10.00998"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1"
+ inkscape:document-rotation="0"
+ inkscape:pagecheckerboard="0">
+ <inkscape:grid
+ type="xygrid"
+ id="grid1497" />
+ </sodipodi:namedview>
+ <g
+ inkscape:groupmode="layer"
+ id="layer1"
+ inkscape:label="up-icon-thick-square" />
+ <path
+ style="fill:#757575;fill-opacity:1;stroke:none;stroke-width:1.34164px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 2,8 6,-6 6,6 h -3 v 7 H 5 V 8 Z"
+ id="path1103"
+ sodipodi:nodetypes="cccccccc" />
+ <rect
+ style="fill:none;stroke-width:4;stroke-linejoin:round"
+ id="rect1748"
+ width="16"
+ height="16"
+ x="0"
+ y="0" />
+</svg>
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@2x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@2x.png
new file mode 100644
index 0000000000..b4efe13228
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@2x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@3x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@3x.png
new file mode 100644
index 0000000000..2e8302b1f0
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@3x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@4x.png b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@4x.png
new file mode 100644
index 0000000000..5cf05ab305
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/images/up-icon-thick-square@4x.png
Binary files differ
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialog.qml
new file mode 100644
index 0000000000..cf2a0a32c5
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialog.qml
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt.labs.folderlistmodel
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+import "." as DialogsImpl
+
+FileDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 6
+ horizontalPadding: 12
+
+ standardButtons: T.Dialog.Open | T.Dialog.Cancel
+
+ /*
+ We use attached properties because we want to handle logic in C++, and:
+ - We can't assume the footer only contains a DialogButtonBox (which would allow us
+ to connect up to it in QQuickFileDialogImpl); it also needs to hold a ComboBox
+ and therefore the root footer item will be e.g. a layout item instead.
+ - We don't want to create our own "FileDialogButtonBox" (in order to be able to handle the logic
+ in C++) because we'd need to copy (and hence duplicate code in) DialogButtonBox.qml.
+ */
+ FileDialogImpl.buttonBox: buttonBox
+ FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
+ FileDialogImpl.fileDialogListView: fileDialogListView
+ FileDialogImpl.breadcrumbBar: breadcrumbBar
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.palette.window
+ border.color: control.palette.mid
+ radius: 2
+
+ Rectangle {
+ z: -1
+ x: 1
+ y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.2
+ radius: 2
+ }
+ }
+
+ header: ColumnLayout {
+ spacing: 0
+
+ Label {
+ objectName: "dialogTitleBarLabel"
+ text: control.title
+ horizontalAlignment: Label.AlignHCenter
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 6
+
+ Layout.fillWidth: true
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+ Layout.topMargin: control.title.length > 0 ? 0 : 12
+ Layout.preferredHeight: control.title.length > 0 ? implicitHeight : 0
+ }
+
+ DialogsImpl.FolderBreadcrumbBar {
+ id: breadcrumbBar
+ fileDialog: control
+
+ Layout.fillWidth: true
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+
+ KeyNavigation.tab: fileDialogListView
+ }
+ }
+
+ contentItem: Frame {
+ padding: 0
+ verticalPadding: 1
+
+ ListView {
+ id: fileDialogListView
+ objectName: "fileDialogListView"
+ anchors.fill: parent
+ clip: true
+ focus: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: FolderListModel {
+ folder: control.currentFolder
+ nameFilters: control.selectedNameFilter.globs
+ showDirsFirst: true
+ sortCaseSensitive: false
+ }
+ delegate: DialogsImpl.FileDialogDelegate {
+ objectName: "fileDialogDelegate" + index
+ x: 1
+ width: ListView.view.width - 2
+ highlighted: ListView.isCurrentItem
+ fileDialog: control
+ fileDetailRowWidth: nameFiltersComboBox.width
+
+ KeyNavigation.backtab: breadcrumbBar
+ KeyNavigation.tab: nameFiltersComboBox
+ }
+ }
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 12
+
+ ComboBox {
+ // OK to use IDs here, since users shouldn't be overriding this stuff.
+ id: nameFiltersComboBox
+ model: control.nameFilters
+
+ Layout.leftMargin: 12
+ Layout.fillWidth: true
+ Layout.bottomMargin: 12
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 6
+ horizontalPadding: 0
+ verticalPadding: 0
+ background: null
+
+ Layout.rightMargin: 12
+ Layout.bottomMargin: 12
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialogDelegate.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialogDelegate.qml
new file mode 100644
index 0000000000..3c2b7b9c3c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FileDialogDelegate.qml
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl as ControlsImpl
+import QtQuick.Controls.Fusion
+import QtQuick.Controls.Fusion.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FileDialogDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 6
+ spacing: 6
+
+ file: fileUrl
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: highlighted ? palette.highlightedText : palette.text
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/"
+ + (fileIsDir ? "folder" : "file") + "-icon-round.png"
+
+ // We don't use index here, but in C++. Since we're using required
+ // properties, the index context property will not be injected, so we can't
+ // use its QQmlContext to access it.
+ required property int index
+ required property string fileName
+ required property url fileUrl
+ required property int fileSize
+ required property date fileModified
+ required property bool fileIsDir
+
+ required property int fileDetailRowWidth
+
+ contentItem: FileDialogDelegateLabel {
+ delegate: control
+ fileDetailRowTextColor: control.highlighted ? Fusion.highlightedText(control.palette) : control.palette.text
+ fileDetailRowWidth: control.fileDetailRowWidth
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 20
+ color: control.down ? Fusion.buttonColor(control.palette, false, true, true)
+ : control.highlighted ? Fusion.highlight(control.palette) : control.palette.base
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FolderBreadcrumbBar.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FolderBreadcrumbBar.qml
new file mode 100644
index 0000000000..df8a466881
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FolderBreadcrumbBar.qml
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FolderBreadcrumbBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (upButton ? upButton.implicitWidth + upButtonSpacing : 0)
+ + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ upButtonSpacing: 6
+
+ contentItem: ListView {
+ currentIndex: control.currentIndex
+ model: control.contentModel
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapToItem
+ highlightMoveDuration: 0
+ interactive: false
+ clip: true
+
+ Rectangle {
+ anchors.fill: parent
+ color: control.palette.light
+ border.color: control.palette.mid
+ radius: 2
+ z: -1
+ }
+ }
+ buttonDelegate: Button {
+ id: buttonDelegateRoot
+ text: folderName
+ flat: true
+
+ // The default of 100 is a bit too wide for short directory names.
+ Binding {
+ target: buttonDelegateRoot.background
+ property: "implicitWidth"
+ value: 24
+ }
+
+ required property int index
+ required property string folderName
+ }
+ separatorDelegate: IconImage {
+ id: iconImage
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/crumb-separator-icon-round.png"
+ sourceSize: Qt.size(8, 8)
+ width: 8 + 6
+ height: control.contentItem.height
+ color: control.palette.dark
+ y: (control.height - height) / 2
+ }
+ upButton: Button {
+ x: control.leftPadding
+ y: control.topPadding
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/up-icon-round.png"
+ icon.width: 16
+ icon.height: 16
+ width: height
+ height: Math.max(implicitHeight, control.contentItem.height)
+ focusPolicy: Qt.TabFocus
+ }
+ textField: TextField {
+ text: control.fileDialog.selectedFile
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FontDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FontDialog.qml
new file mode 100644
index 0000000000..dd75338f21
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Fusion/FontDialog.qml
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Fusion
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+FontDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(control.implicitBackgroundWidth + control.leftInset + control.rightInset,
+ control.contentWidth + control.leftPadding + control.rightPadding,
+ control.implicitHeaderWidth,
+ control.implicitFooterWidth)
+ implicitHeight: Math.max(control.implicitBackgroundHeight + control.topInset + control.bottomInset,
+ control.contentHeight + control.topPadding + control.bottomPadding
+ + (control.implicitHeaderHeight > 0 ? control.implicitHeaderHeight + control.spacing : 0)
+ + (control.implicitFooterHeight > 0 ? control.implicitFooterHeight + control.spacing : 0))
+
+ leftPadding: 20
+ rightPadding: 20
+ // Ensure that the background's border is visible.
+ leftInset: -1
+ rightInset: -1
+ topInset: -1
+ bottomInset: -1
+
+ standardButtons: T.Dialog.Ok | T.Dialog.Cancel
+
+ FontDialogImpl.buttonBox: buttonBox
+ FontDialogImpl.familyListView: content.familyListView
+ FontDialogImpl.styleListView: content.styleListView
+ FontDialogImpl.sizeListView: content.sizeListView
+ FontDialogImpl.sampleEdit: content.sampleEdit
+ FontDialogImpl.writingSystemComboBox: writingSystemComboBox
+ FontDialogImpl.underlineCheckBox: content.underline
+ FontDialogImpl.strikeoutCheckBox: content.strikeout
+ FontDialogImpl.familyEdit: content.familyEdit
+ FontDialogImpl.styleEdit: content.styleEdit
+ FontDialogImpl.sizeEdit: content.sizeEdit
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.palette.window
+ border.color: control.palette.mid
+ radius: 2
+
+ Rectangle {
+ z: -1
+ x: 1
+ y: 1
+ width: parent.width
+ height: parent.height
+ color: control.palette.shadow
+ opacity: 0.2
+ radius: 2
+ }
+ }
+
+ Overlay.modal: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ Overlay.modeless: Rectangle {
+ color: Fusion.topShadow
+ }
+
+ header: Label {
+ text: control.title
+ horizontalAlignment: Label.AlignHCenter
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 6
+ }
+
+ contentItem: FontDialogContent {
+ id: content
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 12
+
+ Label {
+ text: qsTr("Writing System")
+
+ Layout.leftMargin: 12
+ Layout.topMargin: 6
+ Layout.bottomMargin: 6
+ }
+ ComboBox{
+ id: writingSystemComboBox
+
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+ Layout.bottomMargin: 6
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 6
+ horizontalPadding: 0
+ verticalPadding: 0
+ background: null
+
+ Layout.rightMargin: 12
+ Layout.topMargin: 6
+ Layout.bottomMargin: 6
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialog.qml
new file mode 100644
index 0000000000..9509664df6
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialog.qml
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt.labs.folderlistmodel
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+
+import "." as DialogsImpl
+
+FileDialogImpl {
+ id: control
+
+ // Can't set implicitWidth of the NinePatchImage background, so we do it here.
+ implicitWidth: Math.max(600,
+ implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(400,
+ implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ standardButtons: T.Dialog.Open | T.Dialog.Cancel
+
+ FileDialogImpl.buttonBox: buttonBox
+ FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
+ FileDialogImpl.fileDialogListView: fileDialogListView
+ FileDialogImpl.breadcrumbBar: breadcrumbBar
+
+ background: NinePatchImage {
+ source: Imagine.url + "dialog-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+
+ header: ColumnLayout {
+ spacing: 12
+
+ Label {
+ text: control.title
+ elide: Label.ElideRight
+ font.bold: true
+
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+ Layout.topMargin: 12
+ Layout.fillWidth: true
+ Layout.preferredHeight: control.title.length > 0 ? implicitHeight : 0
+
+ background: NinePatchImage {
+ width: parent.width
+ height: parent.height
+
+ source: Imagine.url + "dialog-title"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+ }
+
+ DialogsImpl.FolderBreadcrumbBar {
+ id: breadcrumbBar
+ fileDialog: control
+
+ Layout.leftMargin: 16
+ Layout.rightMargin: 16
+ Layout.fillWidth: true
+ Layout.maximumWidth: parent.width - 28
+ }
+ }
+
+ contentItem: ListView {
+ id: fileDialogListView
+ objectName: "fileDialogListView"
+ clip: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: FolderListModel {
+ folder: control.currentFolder
+ nameFilters: control.selectedNameFilter.globs
+ showDirsFirst: true
+ sortCaseSensitive: false
+ }
+ delegate: DialogsImpl.FileDialogDelegate {
+ objectName: "fileDialogDelegate" + index
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ fileDialog: control
+ fileDetailRowWidth: nameFiltersComboBox.width
+ }
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 20
+
+ ComboBox {
+ id: nameFiltersComboBox
+ model: control.nameFilters
+
+ Layout.leftMargin: 16
+ Layout.bottomMargin: 16
+ Layout.fillWidth: true
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+
+ Layout.bottomMargin: 16
+ Layout.rightMargin: 16
+ }
+ }
+
+ T.Overlay.modal: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ T.Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialogDelegate.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialogDelegate.qml
new file mode 100644
index 0000000000..832f851cca
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FileDialogDelegate.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick.Controls
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+import QtQuick.Controls.impl as ControlsImpl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FileDialogDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ file: fileUrl
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: highlighted ? palette.highlightedText : palette.text
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/"
+ + (fileIsDir ? "folder" : "file") + "-icon-round.png"
+
+ required property int index
+ required property string fileName
+ required property url fileUrl
+ required property int fileSize
+ required property date fileModified
+ required property bool fileIsDir
+
+ required property int fileDetailRowWidth
+
+ contentItem: FileDialogDelegateLabel {
+ delegate: control
+ fileDetailRowTextColor: control.icon.color
+ fileDetailRowWidth: control.fileDetailRowWidth
+ }
+
+ background: NinePatchImage {
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/imagine/filedialogdelegate-background"
+ NinePatchImageSelector on source {
+ states: [
+ { "disabled": !control.enabled },
+ { "pressed": control.down },
+ { "focused": control.visualFocus },
+ { "highlighted": control.highlighted },
+ { "mirrored": control.mirrored },
+ { "hovered": control.enabled && control.hovered }
+ ]
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FolderBreadcrumbBar.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FolderBreadcrumbBar.qml
new file mode 100644
index 0000000000..30e0586740
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FolderBreadcrumbBar.qml
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FolderBreadcrumbBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (upButton ? upButton.implicitWidth + upButtonSpacing : 0)
+ + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ upButtonSpacing: 20
+ padding: 1
+
+ background: Rectangle {}
+ contentItem: ListView {
+ currentIndex: control.currentIndex
+ model: control.contentModel
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapToItem
+ highlightMoveDuration: 0
+ interactive: false
+ clip: true
+ }
+ buttonDelegate: Button {
+ id: buttonDelegateRoot
+ text: folderName
+ flat: true
+
+ required property int index
+ required property string folderName
+ }
+ separatorDelegate: IconImage {
+ id: iconImage
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/crumb-separator-icon-round.png"
+ sourceSize: Qt.size(8, 8)
+ width: 8
+ height: control.contentItem.height
+ y: (control.height - height) / 2
+ }
+ upButton: ToolButton {
+ x: control.leftPadding
+ y: control.topPadding
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/up-icon-thick-square.png"
+ icon.width: 16
+ icon.height: 16
+ focusPolicy: Qt.TabFocus
+ }
+ textField: TextField {
+ text: control.fileDialog.selectedFile
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FontDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FontDialog.qml
new file mode 100644
index 0000000000..47bd53dafc
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Imagine/FontDialog.qml
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Imagine
+import QtQuick.Controls.Imagine.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+FontDialogImpl {
+ id: control
+
+ // Can't set implicitWidth of the NinePatchImage background, so we do it here.
+ implicitWidth: Math.max(600,
+ implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(400,
+ implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ topPadding: background ? background.topPadding : 0
+ leftPadding: background ? background.leftPadding : 0
+ rightPadding: background ? background.rightPadding : 0
+ bottomPadding: background ? background.bottomPadding : 0
+
+ topInset: background ? -background.topInset || 0 : 0
+ leftInset: background ? -background.leftInset || 0 : 0
+ rightInset: background ? -background.rightInset || 0 : 0
+ bottomInset: background ? -background.bottomInset || 0 : 0
+
+ standardButtons: T.Dialog.Ok | T.Dialog.Cancel
+
+ FontDialogImpl.buttonBox: buttonBox
+ FontDialogImpl.familyListView: content.familyListView
+ FontDialogImpl.styleListView: content.styleListView
+ FontDialogImpl.sizeListView: content.sizeListView
+ FontDialogImpl.sampleEdit: content.sampleEdit
+ FontDialogImpl.writingSystemComboBox: writingSystemComboBox
+ FontDialogImpl.underlineCheckBox: content.underline
+ FontDialogImpl.strikeoutCheckBox: content.strikeout
+ FontDialogImpl.familyEdit: content.familyEdit
+ FontDialogImpl.styleEdit: content.styleEdit
+ FontDialogImpl.sizeEdit: content.sizeEdit
+
+ background: NinePatchImage {
+ source: Imagine.url + "dialog-background"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+
+ Overlay.modal: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": true}
+ ]
+ }
+ }
+
+ Overlay.modeless: NinePatchImage {
+ source: Imagine.url + "dialog-overlay"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": false}
+ ]
+ }
+ }
+
+ header: Label {
+ text: control.title
+ elide: Label.ElideRight
+ font.bold: true
+
+ leftPadding: 16
+ rightPadding: 16
+ topPadding: 12
+ height: control.title.length > 0 ? implicitHeight : 0
+
+ background: NinePatchImage {
+ width: parent.width
+ height: parent.height
+
+ source: Imagine.url + "dialog-title"
+ NinePatchImageSelector on source {
+ states: [
+ {"modal": control.modal},
+ {"dim": control.dim}
+ ]
+ }
+ }
+ }
+
+ contentItem: FontDialogContent {
+ id: content
+ rowSpacing: 16
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 20
+
+ Label {
+ text: qsTr("Writing System")
+ Layout.leftMargin: 20
+ Layout.bottomMargin: 16
+ }
+ ComboBox{
+ id: writingSystemComboBox
+
+ Layout.fillWidth: true
+ Layout.bottomMargin: 16
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+ Layout.rightMargin: 20
+ Layout.bottomMargin: 16
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialog.qml
new file mode 100644
index 0000000000..de4a9d6f44
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialog.qml
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt.labs.folderlistmodel
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+import "." as DialogsImpl
+
+FileDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ leftPadding: 24
+ rightPadding: 24
+
+ standardButtons: T.Dialog.Open | T.Dialog.Cancel
+
+ Material.elevation: 24
+
+ FileDialogImpl.buttonBox: buttonBox
+ FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
+ FileDialogImpl.fileDialogListView: fileDialogListView
+ FileDialogImpl.breadcrumbBar: breadcrumbBar
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ radius: 2
+ color: control.Material.dialogColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+
+ header: ColumnLayout {
+ spacing: 12
+
+ Label {
+ text: control.title
+ visible: control.title.length > 0
+ elide: Label.ElideRight
+ font.bold: true
+ font.pixelSize: 16
+
+ Layout.leftMargin: 24
+ Layout.rightMargin: 24
+ Layout.topMargin: 24
+ Layout.fillWidth: true
+ }
+
+ DialogsImpl.FolderBreadcrumbBar {
+ id: breadcrumbBar
+ fileDialog: control
+
+ Layout.leftMargin: 24
+ Layout.rightMargin: 24
+ Layout.fillWidth: true
+ Layout.maximumWidth: parent.width - 48
+ }
+ }
+
+ contentItem: ListView {
+ id: fileDialogListView
+ objectName: "fileDialogListView"
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: FolderListModel {
+ folder: control.currentFolder
+ nameFilters: control.selectedNameFilter.globs
+ showDirsFirst: true
+ sortCaseSensitive: false
+ }
+ delegate: DialogsImpl.FileDialogDelegate {
+ objectName: "fileDialogDelegate" + index
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ fileDialog: control
+ fileDetailRowWidth: nameFiltersComboBox.width
+ }
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 20
+
+ ComboBox {
+ id: nameFiltersComboBox
+ model: control.nameFilters
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+ horizontalPadding: 0
+ verticalPadding: 20
+
+ Layout.rightMargin: 20
+ }
+ }
+
+ Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialogDelegate.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialogDelegate.qml
new file mode 100644
index 0000000000..eb4bae9bfc
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FileDialogDelegate.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FileDialogDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 16
+ verticalPadding: 8
+ spacing: 16
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: enabled ? Material.foreground : Material.hintTextColor
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/"
+ + (fileIsDir ? "folder" : "file") + "-icon-square.png"
+
+ file: fileUrl
+
+ required property int index
+ required property string fileName
+ required property url fileUrl
+ required property int fileSize
+ required property date fileModified
+ required property bool fileIsDir
+
+ required property int fileDetailRowWidth
+
+ contentItem: FileDialogDelegateLabel {
+ delegate: control
+ fileDetailRowTextColor: control.Material.hintTextColor
+ fileDetailRowWidth: control.fileDetailRowWidth
+ }
+
+ background: Rectangle {
+ implicitHeight: control.Material.delegateHeight
+
+ color: control.highlighted ? Color.transparent(control.Material.accentColor, 0.08) : "transparent"
+
+ Ripple {
+ width: parent.width
+ height: parent.height
+
+ clip: visible
+ pressed: control.pressed
+ anchor: control
+ active: control.down || control.visualFocus || control.hovered
+ color: control.highlighted ? control.Material.highlightedRippleColor : control.Material.rippleColor
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FolderBreadcrumbBar.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FolderBreadcrumbBar.qml
new file mode 100644
index 0000000000..5ac638a07d
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FolderBreadcrumbBar.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FolderBreadcrumbBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (upButton ? upButton.implicitWidth + upButtonSpacing : 0)
+ + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ upButtonSpacing: 20
+ padding: 1
+
+ background: Rectangle {}
+ contentItem: ListView {
+ currentIndex: control.currentIndex
+ model: control.contentModel
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapToItem
+ highlightMoveDuration: 0
+ interactive: false
+ clip: true
+ }
+ buttonDelegate: Button {
+ id: buttonDelegateRoot
+ text: folderName
+ flat: true
+ font.capitalization: Font.MixedCase
+
+ // The default of 100 is a bit too wide for short directory names.
+ Binding {
+ target: buttonDelegateRoot.background
+ property: "implicitWidth"
+ value: control.Material.buttonHeight
+ }
+
+ required property int index
+ required property string folderName
+ }
+ separatorDelegate: IconImage {
+ id: iconImage
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/crumb-separator-icon-square.png"
+ sourceSize: Qt.size(8, 8)
+ // The image is 8x8, and add 2 px padding on each side.
+ width: 8 + 4
+ height: control.contentItem.height
+ color: control.Material.hintTextColor
+ y: (control.height - height) / 2
+ }
+ upButton: ToolButton {
+ x: control.leftPadding
+ y: control.topPadding
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/up-icon-thick-square.png"
+ icon.width: 16
+ icon.height: 16
+ width: height
+ focusPolicy: Qt.TabFocus
+ }
+ textField: TextField {
+ text: control.fileDialog.selectedFile
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FontDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FontDialog.qml
new file mode 100644
index 0000000000..5113468012
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Material/FontDialog.qml
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+FontDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ leftPadding: 24
+ rightPadding: 24
+
+ standardButtons: T.Dialog.Ok | T.Dialog.Cancel
+
+ Material.elevation: 24
+
+ FontDialogImpl.buttonBox: buttonBox
+ FontDialogImpl.familyListView: content.familyListView
+ FontDialogImpl.styleListView: content.styleListView
+ FontDialogImpl.sizeListView: content.sizeListView
+ FontDialogImpl.sampleEdit: content.sampleEdit
+ FontDialogImpl.writingSystemComboBox: writingSystemComboBox
+ FontDialogImpl.underlineCheckBox: content.underline
+ FontDialogImpl.strikeoutCheckBox: content.strikeout
+ FontDialogImpl.familyEdit: content.familyEdit
+ FontDialogImpl.styleEdit: content.styleEdit
+ FontDialogImpl.sizeEdit: content.sizeEdit
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ radius: 2
+ color: control.Material.dialogColor
+
+ layer.enabled: control.Material.elevation > 0
+ layer.effect: ElevationEffect {
+ elevation: control.Material.elevation
+ }
+ }
+
+ Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+
+ header: Label {
+ text: control.title
+ visible: control.title.length > 0
+ elide: Label.ElideRight
+ font.bold: true
+ font.pixelSize: 16
+
+ leftPadding: 24
+ rightPadding: 24
+ topPadding: 24
+ bottomPadding: 24
+ }
+
+ contentItem: FontDialogContent {
+ id: content
+ familyEdit.bottomPadding: 8
+ styleEdit.bottomPadding: 8
+ sizeEdit.bottomPadding: 8
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 20
+
+ Label {
+ text: qsTr("Writing System")
+
+ Layout.leftMargin: 20
+ }
+ ComboBox{
+ id: writingSystemComboBox
+
+ Layout.fillWidth: true
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+ horizontalPadding: 0
+ verticalPadding: 20
+
+ Layout.rightMargin: 20
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialog.qml
new file mode 100644
index 0000000000..7bcb4629d0
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialog.qml
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt.labs.folderlistmodel
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.Universal
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+import "." as DialogsImpl
+
+FileDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 24
+ verticalPadding: 18
+
+ standardButtons: T.Dialog.Open | T.Dialog.Cancel
+
+ FileDialogImpl.buttonBox: buttonBox
+ FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
+ FileDialogImpl.fileDialogListView: fileDialogListView
+ FileDialogImpl.breadcrumbBar: breadcrumbBar
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+
+ header: ColumnLayout {
+ spacing: 12
+
+ Label {
+ text: control.title
+ elide: Label.ElideRight
+ // TODO: QPlatformTheme::TitleBarFont
+ font.pixelSize: 20
+
+ Layout.leftMargin: 24
+ Layout.rightMargin: 24
+ Layout.topMargin: 18
+ Layout.fillWidth: true
+ Layout.preferredHeight: control.title.length > 0 ? implicitHeight : 0
+
+ background: Rectangle {
+ x: 1; y: 1 // // FlyoutBorderThemeThickness
+ color: control.Universal.chromeMediumLowColor
+ width: parent.width - 2
+ height: parent.height - 1
+ }
+ }
+
+ DialogsImpl.FolderBreadcrumbBar {
+ id: breadcrumbBar
+ fileDialog: control
+
+ Layout.leftMargin: 24
+ Layout.rightMargin: 24
+ Layout.fillWidth: true
+ Layout.maximumWidth: parent.width - 48
+ }
+ }
+
+ contentItem: ListView {
+ id: fileDialogListView
+ objectName: "fileDialogListView"
+ clip: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: FolderListModel {
+ folder: control.currentFolder
+ nameFilters: control.selectedNameFilter.globs
+ showDirsFirst: true
+ sortCaseSensitive: false
+ }
+ delegate: DialogsImpl.FileDialogDelegate {
+ objectName: "fileDialogDelegate" + index
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ fileDialog: control
+ fileDetailRowWidth: nameFiltersComboBox.width
+ }
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 24
+
+ ComboBox {
+ id: nameFiltersComboBox
+ model: control.nameFilters
+
+ Layout.leftMargin: 24
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+ Layout.bottomMargin: 24
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+ horizontalPadding: 0
+
+ Layout.rightMargin: 24
+ }
+ }
+
+ T.Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ T.Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialogDelegate.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialogDelegate.qml
new file mode 100644
index 0000000000..d4322dc5fa
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FileDialogDelegate.qml
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FileDialogDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: 12
+
+ padding: 12
+ topPadding: padding - 1
+ bottomPadding: padding + 1
+
+ icon.width: 20
+ icon.height: 20
+ icon.color: Color.transparent(Universal.foreground, enabled ? 1.0 : 0.2)
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/"
+ + (fileIsDir ? "folder" : "file") + "-icon-square.png"
+
+ file: fileUrl
+
+ required property int index
+ required property string fileName
+ required property url fileUrl
+ required property int fileSize
+ required property date fileModified
+ required property bool fileIsDir
+
+ required property int fileDetailRowWidth
+
+ contentItem: FileDialogDelegateLabel {
+ delegate: control
+ fileDetailRowTextColor: control.icon.color
+ fileDetailRowWidth: control.fileDetailRowWidth
+ }
+
+ background: Rectangle {
+ visible: control.down || control.highlighted || control.visualFocus || control.hovered
+ color: control.down ? control.Universal.listMediumColor :
+ control.hovered ? control.Universal.listLowColor : control.Universal.altMediumLowColor
+
+ Rectangle {
+ width: parent.width
+ height: parent.height
+ visible: control.visualFocus || control.highlighted
+ color: control.Universal.accent
+ opacity: control.Universal.theme === Universal.Light ? 0.4 : 0.6
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FolderBreadcrumbBar.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FolderBreadcrumbBar.qml
new file mode 100644
index 0000000000..1554b40a6f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FolderBreadcrumbBar.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FolderBreadcrumbBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (upButton ? upButton.implicitWidth + upButtonSpacing : 0)
+ + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ upButtonSpacing: 20
+ padding: 1
+
+ background: Rectangle {}
+ contentItem: ListView {
+ currentIndex: control.currentIndex
+ model: control.contentModel
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapToItem
+ highlightMoveDuration: 0
+ interactive: false
+ clip: true
+ }
+ buttonDelegate: ToolButton {
+ id: buttonDelegateRoot
+ text: folderName
+
+ // The default is a bit too wide for short directory names.
+ Binding {
+ target: buttonDelegateRoot.background
+ property: "implicitWidth"
+ value: 48
+ }
+
+ required property int index
+ required property string folderName
+ }
+ separatorDelegate: IconImage {
+ id: iconImage
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/crumb-separator-icon-square.png"
+ sourceSize: Qt.size(8, 8)
+ // The image is 8x8, and add 2 px padding on each side.
+ width: 8 + 4
+ height: control.contentItem.height
+ color: Color.transparent(control.Universal.foreground, enabled ? 1.0 : 0.2)
+ y: (control.height - height) / 2
+ }
+ upButton: ToolButton {
+ x: control.leftPadding
+ y: control.topPadding
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/up-icon-square.png"
+ icon.width: 16
+ icon.height: 16
+ width: height
+ focusPolicy: Qt.TabFocus
+ }
+ textField: TextField {
+ text: control.fileDialog.selectedFile
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FontDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FontDialog.qml
new file mode 100644
index 0000000000..1bd3092e6b
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/+Universal/FontDialog.qml
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Controls.Universal
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+FontDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ padding: 24
+ verticalPadding: 18
+
+ standardButtons: T.Dialog.Ok | T.Dialog.Cancel
+
+ FontDialogImpl.buttonBox: buttonBox
+ FontDialogImpl.familyListView: content.familyListView
+ FontDialogImpl.styleListView: content.styleListView
+ FontDialogImpl.sizeListView: content.sizeListView
+ FontDialogImpl.sampleEdit: content.sampleEdit
+ FontDialogImpl.writingSystemComboBox: writingSystemComboBox
+ FontDialogImpl.underlineCheckBox: content.underline
+ FontDialogImpl.strikeoutCheckBox: content.strikeout
+ FontDialogImpl.familyEdit: content.familyEdit
+ FontDialogImpl.styleEdit: content.styleEdit
+ FontDialogImpl.sizeEdit: content.sizeEdit
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.Universal.chromeMediumLowColor
+ border.color: control.Universal.chromeHighColor
+ border.width: 1 // FlyoutBorderThemeThickness
+ }
+
+ Overlay.modal: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ Overlay.modeless: Rectangle {
+ color: control.Universal.baseLowColor
+ }
+
+ header: Label {
+ text: control.title
+ elide: Label.ElideRight
+ // TODO: QPlatformTheme::TitleBarFont
+ font.pixelSize: 20
+
+ leftPadding: 24
+ rightPadding: 24
+ topPadding: 18
+ height: control.title.length > 0 ? implicitHeight : 0
+
+ background: Rectangle {
+ x: 1; y: 1 // // FlyoutBorderThemeThickness
+ color: control.Universal.chromeMediumLowColor
+ width: parent.width - 2
+ height: parent.height - 1
+ }
+ }
+
+ contentItem: FontDialogContent {
+ id: content
+ rowSpacing: 12
+ }
+
+ footer: RowLayout {
+ id: rowLayout
+ spacing: 24
+
+ Label {
+ text: qsTr("Writing System")
+
+ Layout.leftMargin: 24
+ Layout.topMargin: 6
+ Layout.bottomMargin: 24
+ }
+ ComboBox{
+ id: writingSystemComboBox
+
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+ Layout.bottomMargin: 24
+
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ spacing: 12
+ horizontalPadding: 0
+
+ Layout.rightMargin: 24
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialog.qml
new file mode 100644
index 0000000000..5659190477
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialog.qml
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import Qt.labs.folderlistmodel
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+import "." as DialogsImpl
+
+FileDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitHeaderWidth,
+ implicitFooterWidth)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding
+ + (implicitHeaderHeight > 0 ? implicitHeaderHeight + spacing : 0)
+ + (implicitFooterHeight > 0 ? implicitFooterHeight + spacing : 0))
+
+ leftPadding: 20
+ rightPadding: 20
+ // Ensure that the background's border is visible.
+ leftInset: -1
+ rightInset: -1
+ topInset: -1
+ bottomInset: -1
+
+ standardButtons: T.Dialog.Open | T.Dialog.Cancel
+
+ /*
+ We use attached properties because we want to handle logic in C++, and:
+ - We can't assume the footer only contains a DialogButtonBox (which would allow us
+ to connect up to it in QQuickFileDialogImpl); it also needs to hold a ComboBox
+ and therefore the root footer item will be e.g. a layout item instead.
+ - We don't want to create our own "FileDialogButtonBox" (in order to be able to handle the logic
+ in C++) because we'd need to copy (and hence duplicate code in) DialogButtonBox.qml.
+ */
+ FileDialogImpl.buttonBox: buttonBox
+ FileDialogImpl.nameFiltersComboBox: nameFiltersComboBox
+ FileDialogImpl.fileDialogListView: fileDialogListView
+ FileDialogImpl.breadcrumbBar: breadcrumbBar
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.palette.window
+ border.color: control.palette.dark
+ }
+
+ header: Pane {
+ palette.window: control.palette.light
+ padding: 20
+
+ contentItem: Column {
+ spacing: 12
+
+ Label {
+ objectName: "dialogTitleBarLabel"
+ width: parent.width
+ text: control.title
+ visible: control.title.length > 0
+ horizontalAlignment: Label.AlignHCenter
+ elide: Label.ElideRight
+ font.bold: true
+ }
+
+ DialogsImpl.FolderBreadcrumbBar {
+ id: breadcrumbBar
+ width: parent.width
+ fileDialog: control
+
+ KeyNavigation.tab: fileDialogListView
+ }
+ }
+ }
+
+ contentItem: ListView {
+ id: fileDialogListView
+ objectName: "fileDialogListView"
+ clip: true
+ focus: true
+ boundsBehavior: Flickable.StopAtBounds
+
+ ScrollBar.vertical: ScrollBar {}
+
+ model: FolderListModel {
+ folder: control.currentFolder
+ nameFilters: control.selectedNameFilter.globs
+ showDirsFirst: true
+ sortCaseSensitive: false
+ }
+ delegate: DialogsImpl.FileDialogDelegate {
+ objectName: "fileDialogDelegate" + index
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ fileDialog: control
+ fileDetailRowWidth: nameFiltersComboBox.width
+
+ KeyNavigation.backtab: breadcrumbBar
+ KeyNavigation.tab: nameFiltersComboBox
+ }
+ }
+
+ footer: Rectangle {
+ color: control.palette.light
+ implicitWidth: rowLayout.implicitWidth
+ implicitHeight: rowLayout.implicitHeight
+
+ RowLayout {
+ id: rowLayout
+ width: parent.width
+ height: parent.height
+ spacing: 20
+
+ ComboBox {
+ // OK to use IDs here, since users shouldn't be overriding this stuff.
+ id: nameFiltersComboBox
+ model: control.nameFilters
+
+ Layout.leftMargin: 20
+ Layout.fillWidth: true
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ palette.window: control.palette.light
+ spacing: 12
+ horizontalPadding: 0
+ verticalPadding: 20
+
+ Layout.rightMargin: 20
+ }
+ }
+ }
+
+ Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegate.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegate.qml
new file mode 100644
index 0000000000..03250faa7e
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegate.qml
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl as ControlsImpl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FileDialogDelegate {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ padding: 12
+ spacing: 8
+ topPadding: 0
+ bottomPadding: 0
+
+ file: fileUrl
+
+ icon.width: 16
+ icon.height: 16
+ icon.color: highlighted ? palette.highlightedText : palette.text
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/"
+ + (fileIsDir ? "folder" : "file") + "-icon-round.png"
+
+ // We don't use index here, but in C++. Since we're using required
+ // properties, the index context property will not be injected, so we can't
+ // use its QQmlContext to access it.
+ required property int index
+ required property string fileName
+ required property url fileUrl
+ required property int fileSize
+ required property date fileModified
+ required property bool fileIsDir
+
+ required property int fileDetailRowWidth
+
+ contentItem: FileDialogDelegateLabel {
+ delegate: control
+ fileDetailRowTextColor: control.icon.color
+ fileDetailRowWidth: control.fileDetailRowWidth
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: control.down || control.highlighted || control.visualFocus
+ color: Color.blend(control.down ? control.palette.midlight : control.palette.light,
+ control.palette.highlight, control.highlighted ? 0.15 : 0.0)
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegateLabel.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegateLabel.qml
new file mode 100644
index 0000000000..9768cd51f0
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FileDialogDelegateLabel.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+/*
+ Most of the elements in here are the same between styles, so we
+ have a reusable component for it and provide some properties to enable style-specific tweaks.
+*/
+Item {
+ id: root
+ implicitWidth: column.implicitWidth
+ implicitHeight: column.implicitHeight
+
+ required property DialogsQuickImpl.FileDialogDelegate delegate
+ required property int fileDetailRowWidth
+
+ property color fileDetailRowTextColor
+
+ Column {
+ id: column
+ y: (parent.height - height) / 2
+
+ Row {
+ spacing: root.delegate.spacing
+
+ IconImage {
+ id: iconImage
+ source: root.delegate.icon.source
+ sourceSize: Qt.size(root.delegate.icon.width, root.delegate.icon.height)
+ width: root.delegate.icon.width
+ height: root.delegate.icon.height
+ color: root.delegate.icon.color
+ y: (parent.height - height) / 2
+ }
+ Label {
+ text: root.delegate.fileName
+ color: root.delegate.icon.color
+ y: (parent.height - height) / 2
+ }
+ }
+
+ Item {
+ id: fileDetailRow
+ x: iconImage.width + root.delegate.spacing
+ width: fileDetailRowWidth - x - root.delegate.leftPadding
+ implicitHeight: childrenRect.height
+
+ Label {
+ text: locale.formattedDataSize(root.delegate.fileSize)
+ font.pixelSize: root.delegate.font.pixelSize * 0.75
+ color: root.fileDetailRowTextColor
+ }
+ Label {
+ text: Qt.formatDateTime(root.delegate.fileModified)
+ font.pixelSize: root.delegate.font.pixelSize * 0.75
+ color: root.fileDetailRowTextColor
+ x: parent.width - width
+ }
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FolderBreadcrumbBar.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FolderBreadcrumbBar.qml
new file mode 100644
index 0000000000..a1697c8fe2
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FolderBreadcrumbBar.qml
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs.quickimpl as DialogsQuickImpl
+
+DialogsQuickImpl.FolderBreadcrumbBar {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + (upButton ? upButton.implicitWidth + upButtonSpacing : 0)
+ + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ upButtonSpacing: 20
+ padding: 1
+
+ background: Rectangle {
+ border.color: control.palette.button
+ }
+ contentItem: ListView {
+ currentIndex: control.currentIndex
+ model: control.contentModel
+ orientation: ListView.Horizontal
+ snapMode: ListView.SnapToItem
+ highlightMoveDuration: 0
+ interactive: false
+ clip: true
+ }
+ buttonDelegate: Button {
+ id: buttonDelegateRoot
+ text: folderName
+ flat: true
+
+ // The default of 100 is a bit too wide for short directory names.
+ Binding {
+ target: buttonDelegateRoot.background
+ property: "implicitWidth"
+ value: 40
+ }
+
+ required property int index
+ required property string folderName
+ }
+ separatorDelegate: IconImage {
+ id: iconImage
+ source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/crumb-separator-icon-round.png"
+ sourceSize: Qt.size(8, 8)
+ width: 8
+ height: control.contentItem.height
+ color: control.palette.button
+ y: (control.height - height) / 2
+ }
+ upButton: ToolButton {
+ x: control.leftPadding
+ y: control.topPadding
+ icon.source: "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/images/up-icon-round.png"
+ icon.width: 16
+ icon.height: 16
+ width: height
+ focusPolicy: Qt.TabFocus
+ }
+ textField: TextField {
+ text: control.fileDialog.selectedFile
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialog.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialog.qml
new file mode 100644
index 0000000000..e2caea4043
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialog.qml
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+import QtQuick.Templates as T
+
+FontDialogImpl {
+ id: control
+
+ implicitWidth: Math.max(control.implicitBackgroundWidth + control.leftInset + control.rightInset,
+ control.contentWidth + control.leftPadding + control.rightPadding,
+ control.implicitHeaderWidth,
+ control.implicitFooterWidth)
+ implicitHeight: Math.max(control.implicitBackgroundHeight + control.topInset + control.bottomInset,
+ control.contentHeight + control.topPadding + control.bottomPadding
+ + (control.implicitHeaderHeight > 0 ? control.implicitHeaderHeight + control.spacing : 0)
+ + (control.implicitFooterHeight > 0 ? control.implicitFooterHeight + control.spacing : 0))
+
+ leftPadding: 20
+ rightPadding: 20
+ // Ensure that the background's border is visible.
+ leftInset: -1
+ rightInset: -1
+ topInset: -1
+ bottomInset: -1
+
+ spacing: 12
+
+ standardButtons: T.Dialog.Ok | T.Dialog.Cancel
+
+ FontDialogImpl.buttonBox: buttonBox
+ FontDialogImpl.familyListView: content.familyListView
+ FontDialogImpl.styleListView: content.styleListView
+ FontDialogImpl.sizeListView: content.sizeListView
+ FontDialogImpl.sampleEdit: content.sampleEdit
+ FontDialogImpl.writingSystemComboBox: writingSystemComboBox
+ FontDialogImpl.underlineCheckBox: content.underline
+ FontDialogImpl.strikeoutCheckBox: content.strikeout
+ FontDialogImpl.familyEdit: content.familyEdit
+ FontDialogImpl.styleEdit: content.styleEdit
+ FontDialogImpl.sizeEdit: content.sizeEdit
+
+ background: Rectangle {
+ implicitWidth: 600
+ implicitHeight: 400
+ color: control.palette.window
+ border.color: control.palette.dark
+ }
+
+ Overlay.modal: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.5)
+ }
+
+ Overlay.modeless: Rectangle {
+ color: Color.transparent(control.palette.shadow, 0.12)
+ }
+
+ header: Pane {
+ palette.window: control.palette.light
+ padding: 20
+
+ contentItem: Label {
+ width: parent.width
+ text: control.title
+ visible: control.title.length > 0
+ horizontalAlignment: Label.AlignHCenter
+ elide: Label.ElideRight
+ font.bold: true
+ }
+ }
+
+ contentItem: FontDialogContent {
+ id: content
+ }
+
+ footer: Rectangle {
+ color: control.palette.light
+ implicitWidth: rowLayout.implicitWidth
+ implicitHeight: rowLayout.implicitHeight
+
+ RowLayout {
+ id: rowLayout
+ width: parent.width
+ height: parent.height
+ spacing: 20
+
+ Label {
+ text: qsTr("Writing System")
+
+ Layout.leftMargin: 20
+ }
+ ComboBox{
+ id: writingSystemComboBox
+
+ Layout.fillWidth: true
+ }
+
+ DialogButtonBox {
+ id: buttonBox
+ standardButtons: control.standardButtons
+ palette.window: control.palette.light
+ spacing: 12
+ horizontalPadding: 0
+ verticalPadding: 20
+
+ Layout.rightMargin: 20
+ }
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialogContent.qml b/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialogContent.qml
new file mode 100644
index 0000000000..f0d5020adf
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qml/FontDialogContent.qml
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Dialogs
+import QtQuick.Dialogs.quickimpl
+import QtQuick.Layouts
+
+GridLayout {
+ property alias familyListView: fontFamilyListView
+ property alias styleListView: fontStyleListView
+ property alias sizeListView: fontSizeListView
+ property alias sampleEdit: fontSample
+ property alias underline: fontUnderline
+ property alias strikeout: fontStrikeout
+ property alias familyEdit: fontFamilyEdit
+ property alias styleEdit: fontStyleEdit
+ property alias sizeEdit: fontSizeEdit
+
+ columns: 3
+
+ ColumnLayout {
+ spacing: 0
+
+ Layout.preferredWidth: 50
+
+ Label {
+ text: qsTr("Family")
+ Layout.alignment: Qt.AlignLeft
+ }
+ TextField {
+ id: fontFamilyEdit
+ objectName: "familyEdit"
+ readOnly: true
+ Layout.fillWidth: true
+ focus: true
+ }
+ Frame {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ background: Rectangle {
+ color: "white"
+ }
+ ListView {
+ id: fontFamilyListView
+ objectName: "familyListView"
+ implicitHeight: 200
+ anchors.fill: parent
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {
+ policy: ScrollBar.AlwaysOn
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightMoveVelocity: -1
+ highlightMoveDuration: 1
+ highlightFollowsCurrentItem: true
+ keyNavigationEnabled: true
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ onClicked: () => fontFamilyListView.currentIndex = index
+ text: modelData
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 0
+
+ Layout.preferredWidth: 30
+
+ Label {
+ text: qsTr("Style")
+ Layout.alignment: Qt.AlignLeft
+ }
+ TextField {
+ id: fontStyleEdit
+ objectName: "styleEdit"
+ readOnly: true
+ Layout.fillWidth: true
+ }
+ Frame {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ background: Rectangle {
+ color: "white"
+ }
+ ListView {
+ id: fontStyleListView
+ objectName: "styleListView"
+ implicitHeight: 200
+ anchors.fill: parent
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {}
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightMoveVelocity: -1
+ highlightMoveDuration: 1
+ highlightFollowsCurrentItem: true
+ keyNavigationEnabled: true
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ onClicked: () => fontStyleListView.currentIndex = index
+ text: modelData
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 0
+
+ Layout.preferredWidth: 20
+
+ Label {
+ text: qsTr("Size")
+ Layout.alignment: Qt.AlignLeft
+ }
+ TextField {
+ id: fontSizeEdit
+ objectName: "sizeEdit"
+ Layout.fillWidth: true
+ validator: IntValidator {
+ bottom: 1
+ top: 512
+ }
+ }
+ Frame {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ background: Rectangle {
+ color: "white"
+ }
+ ListView {
+ id: fontSizeListView
+ objectName: "sizeListView"
+ implicitHeight: 200
+ anchors.fill: parent
+ clip: true
+
+ ScrollBar.vertical: ScrollBar {
+ policy: ScrollBar.AlwaysOn
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ highlightMoveVelocity: -1
+ highlightMoveDuration: 1
+ highlightFollowsCurrentItem: true
+ keyNavigationEnabled: true
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ highlighted: ListView.isCurrentItem
+ onClicked: () => fontSizeListView.currentIndex = index
+ text: modelData
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ Layout.preferredWidth: 80
+
+ GroupBox {
+ id: effectsGroupBox
+ title: qsTr("Effects")
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ label: Label {
+ anchors.left: effectsGroupBox.left
+ text: parent.title
+ }
+
+ RowLayout {
+ anchors.fill: parent
+ CheckBox {
+ id: fontUnderline
+ objectName: "underlineEffect"
+ text: qsTr("Underline")
+ }
+ CheckBox{
+ id: fontStrikeout
+ objectName: "strikeoutEffect"
+ text: qsTr("Strikeout")
+ }
+ }
+ }
+ }
+
+ GroupBox {
+ id: sample
+ padding: label.implicitHeight
+ title: qsTr("Sample")
+
+ Layout.fillWidth: true
+ Layout.preferredWidth: 80
+ Layout.fillHeight: true
+ Layout.columnSpan: 2
+ clip: true
+
+ background: Rectangle {
+ y: sample.topPadding - sample.bottomPadding
+ width: sample.width - sample.leftPadding + sample.rightPadding
+ height: sample.height - sample.topPadding + sample.bottomPadding
+ radius: 3
+ }
+
+ label: Label {
+ anchors.left: sample.left
+ text: sample.title
+ }
+
+ TextEdit {
+ id: fontSample
+ objectName: "sampleEdit"
+ anchors.centerIn: parent
+ readOnly: true
+ }
+ }
+}
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory.cpp
new file mode 100644
index 0000000000..da298432b4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdialogimplfactory_p.h"
+
+#include <QtCore/qloggingcategory.h>
+
+#include "qquickplatformfiledialog_p.h"
+#include "qquickplatformfontdialog_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ Creates concrete QML-based dialogs.
+*/
+
+Q_LOGGING_CATEGORY(lcQuickDialogImplFactory, "qt.quick.dialogs.quickdialogimplfactory")
+
+QPlatformDialogHelper *QQuickDialogImplFactory::createPlatformDialogHelper(
+ QPlatformTheme::DialogType type, QObject *parent)
+{
+ switch (type) {
+ case QPlatformTheme::FileDialog: {
+ auto dialog = new QQuickPlatformFileDialog(parent);
+ // If the QML file failed to load, we need to handle it gracefully.
+ if (!dialog->isValid()) {
+ delete dialog;
+ return nullptr;
+ }
+
+ return dialog;
+ }
+ case QPlatformTheme::FontDialog: {
+ auto dialog = new QQuickPlatformFontDialog(parent);
+
+ if (!dialog->isValid()) {
+ delete dialog;
+ return nullptr;
+ }
+ return dialog;
+ }
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory_p.h
new file mode 100644
index 0000000000..54aa921f30
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickdialogimplfactory_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKQMLDIALOGFACTORY_P_H
+#define QQUICKQMLDIALOGFACTORY_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 <QtGui/qpa/qplatformtheme.h>
+
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickDialogImplFactory
+{
+public:
+ static QPlatformDialogHelper *createPlatformDialogHelper(QPlatformTheme::DialogType type,
+ QObject *parent);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKQMLDIALOGFACTORY_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate.cpp
new file mode 100644
index 0000000000..b1d4477305
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfiledialogdelegate_p.h"
+
+#include <QtCore/qfileinfo.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/QQmlFile>
+#include <QtQml/qqmlexpression.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuickTemplates2/private/qquickitemdelegate_p_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFileDialogDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFileDialogDelegate)
+
+public:
+ void highlightFile();
+ void chooseFile();
+
+ bool acceptKeyClick(Qt::Key key) const override;
+
+ QQuickFileDialogImpl *fileDialog = nullptr;
+ QUrl file;
+};
+
+void QQuickFileDialogDelegatePrivate::highlightFile()
+{
+ Q_Q(QQuickFileDialogDelegate);
+ QQuickListViewAttached *attached = static_cast<QQuickListViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickListView>(q));
+ if (!attached)
+ return;
+
+ QQmlContext *delegateContext = qmlContext(q);
+ if (!delegateContext)
+ return;
+
+ bool converted = false;
+ const int index = q->property("index").toInt(&converted);
+ if (converted) {
+ attached->view()->setCurrentIndex(index);
+ fileDialog->setCurrentFile(file);
+ }
+}
+
+void QQuickFileDialogDelegatePrivate::chooseFile()
+{
+ const QFileInfo fileInfo(QQmlFile::urlToLocalFileOrQrc(file));
+ if (fileInfo.isDir()) {
+ // If it's a directory, navigate to it.
+ fileDialog->setCurrentFolder(file);
+ } else {
+ // Otherwise it's a file, so select it and close the dialog.
+ fileDialog->setSelectedFile(file);
+ fileDialog->accept();
+ }
+}
+
+bool QQuickFileDialogDelegatePrivate::acceptKeyClick(Qt::Key key) const
+{
+ return key == Qt::Key_Return || key == Qt::Key_Enter;
+}
+
+QQuickFileDialogDelegate::QQuickFileDialogDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickFileDialogDelegatePrivate), parent)
+{
+ Q_D(QQuickFileDialogDelegate);
+ // Clicking and tabbing should result in it getting focus,
+ // as e.g. Ubuntu and Windows both allow tabbing through file dialogs.
+ setFocusPolicy(Qt::StrongFocus);
+ setCheckable(true);
+ QObjectPrivate::connect(this, &QQuickFileDialogDelegate::clicked,
+ d, &QQuickFileDialogDelegatePrivate::highlightFile);
+ QObjectPrivate::connect(this, &QQuickFileDialogDelegate::doubleClicked,
+ d, &QQuickFileDialogDelegatePrivate::chooseFile);
+}
+
+QQuickFileDialogImpl *QQuickFileDialogDelegate::fileDialog() const
+{
+ Q_D(const QQuickFileDialogDelegate);
+ return d->fileDialog;
+}
+
+void QQuickFileDialogDelegate::setFileDialog(QQuickFileDialogImpl *fileDialog)
+{
+ Q_D(QQuickFileDialogDelegate);
+ if (fileDialog == d->fileDialog)
+ return;
+
+ d->fileDialog = fileDialog;
+ emit fileDialogChanged();
+}
+
+QUrl QQuickFileDialogDelegate::file() const
+{
+ Q_D(const QQuickFileDialogDelegate);
+ return d->file;
+}
+
+void QQuickFileDialogDelegate::setFile(const QUrl &file)
+{
+ Q_D(QQuickFileDialogDelegate);
+ if (file == d->file)
+ return;
+
+ d->file = file;
+ emit fileChanged();
+}
+
+void QQuickFileDialogDelegate::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickFileDialogDelegate);
+ // We need to respond to being triggered by enter being pressed,
+ // but we can't use event->isAccepted() to check, because events are pre-accepted.
+ auto connection = QObjectPrivate::connect(this, &QQuickFileDialogDelegate::clicked,
+ d, &QQuickFileDialogDelegatePrivate::chooseFile);
+
+ QQuickItemDelegate::keyReleaseEvent(event);
+
+ disconnect(connection);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfiledialogdelegate_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate_p.h
new file mode 100644
index 0000000000..093e27bdbd
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogdelegate_p.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFILEDIALOGDELEGATE_P_H
+#define QQUICKFILEDIALOGDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFileDialogImpl;
+class QQuickFileDialogDelegatePrivate;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogDelegate : public QQuickItemDelegate
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickFileDialogImpl *fileDialog READ fileDialog WRITE setFileDialog NOTIFY fileDialogChanged)
+ Q_PROPERTY(QUrl file READ file WRITE setFile NOTIFY fileChanged)
+ QML_NAMED_ELEMENT(FileDialogDelegate)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ explicit QQuickFileDialogDelegate(QQuickItem *parent = nullptr);
+
+ QQuickFileDialogImpl *fileDialog() const;
+ void setFileDialog(QQuickFileDialogImpl *fileDialog);
+
+ QUrl file() const;
+ void setFile(const QUrl &file);
+
+Q_SIGNALS:
+ void fileDialogChanged();
+ void fileChanged();
+
+protected:
+ void keyReleaseEvent(QKeyEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickFileDialogDelegate)
+ Q_DECLARE_PRIVATE(QQuickFileDialogDelegate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFileDialogDelegate)
+
+#endif // QQUICKFILEDIALOGDELEGATE_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl.cpp
new file mode 100644
index 0000000000..fd1ad44068
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfiledialogimpl_p.h"
+#include "qquickfiledialogimpl_p_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlfile.h>
+#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p_p.h>
+#include <QtQuickTemplates2/private/qquickpopupitem_p_p.h>
+#include "qquickfiledialogdelegate_p.h"
+#include "qquickfolderbreadcrumbbar_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcCurrentFolder, "qt.quick.dialogs.quickfiledialogimpl.currentFolder")
+Q_LOGGING_CATEGORY(lcOptions, "qt.quick.dialogs.quickfiledialogimpl.options")
+Q_LOGGING_CATEGORY(lcNameFilters, "qt.quick.dialogs.quickfiledialogimpl.namefilters")
+Q_LOGGING_CATEGORY(lcAttachedNameFilters, "qt.quick.dialogs.quickfiledialogimplattached.namefilters")
+
+QQuickFileDialogImplPrivate::QQuickFileDialogImplPrivate()
+{
+}
+
+void QQuickFileDialogImplPrivate::setNameFilters(const QStringList &filters)
+{
+ Q_Q(QQuickFileDialogImpl);
+ if (filters == nameFilters)
+ return;
+
+ nameFilters = filters;
+ emit q->nameFiltersChanged();
+}
+
+void QQuickFileDialogImplPrivate::updateEnabled()
+{
+ Q_Q(QQuickFileDialogImpl);
+ QQuickFileDialogImplAttached *attached = attachedOrWarn();
+ if (!attached)
+ return;
+
+ auto openButton = attached->buttonBox()->standardButton(QPlatformDialogHelper::Open);
+ if (!openButton) {
+ qmlWarning(q).nospace() << "Can't update Open button's enabled state because it wasn't found";
+ return;
+ }
+
+ openButton->setEnabled(!currentFile.isEmpty() && attached->breadcrumbBar()
+ && !attached->breadcrumbBar()->textField()->isVisible());
+}
+
+/*!
+ \internal
+
+ Ensures that a file is always selected after a change in \c folder.
+
+ \a oldFolderPath is the previous value of \c folder.
+*/
+void QQuickFileDialogImplPrivate::updateCurrentFile(const QString &oldFolderPath)
+{
+ Q_Q(QQuickFileDialogImpl);
+ QQuickFileDialogImplAttached *attached = attachedOrWarn();
+ if (!attached || !attached->fileDialogListView())
+ return;
+
+ QString newCurrentFilePath;
+ int newCurrentFileIndex = 0;
+ const QString newFolderPath = QQmlFile::urlToLocalFileOrQrc(currentFolder);
+ if (!oldFolderPath.isEmpty() && !newFolderPath.isEmpty()) {
+ // If the user went up a directory (or several), we should set
+ // currentFile to be the directory that we were in (or
+ // its closest ancestor that is a child of the new directory).
+ // E.g. if oldFolderPath is /foo/bar/baz/abc/xyz, and newFolderPath is /foo/bar,
+ // then we want to set currentFile to be /foo/bar/baz.
+ const int indexOfFolder = oldFolderPath.indexOf(newFolderPath);
+ if (indexOfFolder != -1) {
+ // [folder]
+ // [ oldFolderPath ]
+ // /foo/bar/baz/abc/xyz
+ // [rel...Paths]
+ QStringList relativePaths = oldFolderPath.mid(indexOfFolder + newFolderPath.size()).split(QLatin1Char('/'), Qt::SkipEmptyParts);
+ newCurrentFilePath = newFolderPath + QLatin1Char('/') + relativePaths.first();
+
+ // Now find the index of that directory so that we can set the ListView's currentIndex to it.
+ const QDir newFolderDir(newFolderPath);
+ // Just to be safe...
+ if (!newFolderDir.exists()) {
+ qmlWarning(q) << "Directory" << newCurrentFilePath << "doesn't exist; can't get a file entry list for it";
+ return;
+ }
+
+ const QFileInfoList dirs = newFolderDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::DirsFirst);
+ const QFileInfo newCurrentFileInfo(newCurrentFilePath);
+ // The directory can contain files, but since we put dirs first, that should never affect the indices.
+ newCurrentFileIndex = dirs.indexOf(newCurrentFileInfo);
+ }
+ }
+
+ if (newCurrentFilePath.isEmpty()) {
+ // When entering into a directory that isn't a parent of the old one, the first
+ // file delegate should be selected.
+ // TODO: is there a cheaper way to do this? QDirIterator doesn't support sorting,
+ // so we can't use that. QQuickFolderListModel uses threads to fetch its data,
+ // so should be considered asynchronous. We might be able to use it, but it would
+ // complicate the code even more...
+ QDir newFolderDir(newFolderPath);
+ if (newFolderDir.exists()) {
+ const QFileInfoList files = newFolderDir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, QDir::DirsFirst);
+ if (!files.isEmpty())
+ newCurrentFilePath = files.first().absoluteFilePath();
+ }
+ }
+
+ if (!newCurrentFilePath.isEmpty()) {
+ q->setCurrentFile(QUrl::fromLocalFile(newCurrentFilePath));
+ {
+ // Set the appropriate currentIndex for the selected file. We block signals from ListView
+ // because we don't want fileDialogListViewCurrentIndexChanged to be called, as the file
+ // it gets from the delegate will not be up-to-date (but most importantly because we already
+ // just set the selected file).
+ QSignalBlocker blocker(attached->fileDialogListView());
+ attached->fileDialogListView()->setCurrentIndex(newCurrentFileIndex);
+ attached->fileDialogListView()->positionViewAtIndex(newCurrentFileIndex, QQuickListView::Center);
+ }
+ if (QQuickItem *currentItem = attached->fileDialogListView()->currentItem())
+ currentItem->forceActiveFocus();
+ }
+}
+
+void QQuickFileDialogImplPrivate::handleAccept()
+{
+ // Let handleClick take care of calling accept().
+}
+
+void QQuickFileDialogImplPrivate::handleClick(QQuickAbstractButton *button)
+{
+ Q_Q(QQuickFileDialogImpl);
+ if (buttonRole(button) == QPlatformDialogHelper::AcceptRole && currentFile.isValid()) {
+ // The "Open" button was clicked, so we need to set the file to the current file, if any.
+ const QFileInfo fileInfo(currentFile.toLocalFile());
+ if (fileInfo.isDir()) {
+ // If it's a directory, navigate to it.
+ q->setCurrentFolder(currentFile);
+ // Don't call accept(), because selecting a folder != accepting the dialog.
+ } else {
+ // Otherwise it's a file, so select it and close the dialog.
+ q->setSelectedFile(currentFile);
+ q->accept();
+ QQuickDialogPrivate::handleClick(button);
+ emit q->fileSelected(currentFile);
+ }
+ }
+}
+
+QQuickFileDialogImpl::QQuickFileDialogImpl(QObject *parent)
+ : QQuickDialog(*(new QQuickFileDialogImplPrivate), parent)
+{
+}
+
+QQuickFileDialogImplAttached *QQuickFileDialogImpl::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickFileDialogImplAttached(object);
+}
+
+QUrl QQuickFileDialogImpl::currentFolder() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ return d->currentFolder;
+}
+
+void QQuickFileDialogImpl::setCurrentFolder(const QUrl &currentFolder)
+{
+ qCDebug(lcCurrentFolder) << "setCurrentFolder called with" << currentFolder;
+ Q_D(QQuickFileDialogImpl);
+ if (currentFolder == d->currentFolder)
+ return;
+
+ const QString oldFolderPath = QQmlFile::urlToLocalFileOrQrc(d->currentFolder);
+
+ d->currentFolder = currentFolder;
+ // Since the directory changed, the old file can no longer be selected.
+ setCurrentFile(QUrl());
+ d->updateCurrentFile(oldFolderPath);
+ emit currentFolderChanged(d->currentFolder);
+}
+
+QUrl QQuickFileDialogImpl::selectedFile() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ return d->selectedFile;
+}
+
+void QQuickFileDialogImpl::setSelectedFile(const QUrl &selectedFile)
+{
+ Q_D(QQuickFileDialogImpl);
+ if (selectedFile == d->selectedFile)
+ return;
+
+ d->selectedFile = selectedFile;
+ emit selectedFileChanged();
+}
+
+QUrl QQuickFileDialogImpl::currentFile() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ return d->currentFile;
+}
+
+void QQuickFileDialogImpl::setCurrentFile(const QUrl &currentFile)
+{
+ Q_D(QQuickFileDialogImpl);
+ if (currentFile == d->currentFile)
+ return;
+
+ d->currentFile = currentFile;
+ d->updateEnabled();
+ emit currentFileChanged(d->currentFile);
+}
+
+QSharedPointer<QFileDialogOptions> QQuickFileDialogImpl::options() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ return d->options;
+}
+
+void QQuickFileDialogImpl::setOptions(const QSharedPointer<QFileDialogOptions> &options)
+{
+ qCDebug(lcOptions).nospace() << "setOptions called with:"
+ << " acceptMode=" << options->acceptMode()
+ << " fileMode=" << options->fileMode()
+ << " initialDirectory=" << options->initialDirectory()
+ << " nameFilters=" << options->nameFilters()
+ << " initiallySelectedNameFilter=" << options->initiallySelectedNameFilter();
+
+ Q_D(QQuickFileDialogImpl);
+ d->options = options;
+
+ if (d->options) {
+ d->selectedNameFilter->setOptions(options);
+ d->setNameFilters(options->nameFilters());
+ }
+}
+
+/*!
+ \internal
+
+ The list of user-facing strings describing the available file filters.
+*/
+QStringList QQuickFileDialogImpl::nameFilters() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ return d->options ? d->options->nameFilters() : QStringList();
+}
+
+void QQuickFileDialogImpl::resetNameFilters()
+{
+ Q_D(QQuickFileDialogImpl);
+ d->setNameFilters(QStringList());
+}
+
+QQuickFileNameFilter *QQuickFileDialogImpl::selectedNameFilter() const
+{
+ Q_D(const QQuickFileDialogImpl);
+ if (!d->selectedNameFilter) {
+ QQuickFileDialogImpl *that = const_cast<QQuickFileDialogImpl *>(this);
+ d->selectedNameFilter = new QQuickFileNameFilter(that);
+ if (d->options)
+ d->selectedNameFilter->setOptions(d->options);
+ }
+ return d->selectedNameFilter;
+}
+
+/*!
+ \internal
+
+ These allow QQuickPlatformFileDialog::show() to set custom labels on the
+ dialog buttons without having to know about/go through QQuickFileDialogImplAttached
+ and QQuickDialogButtonBox.
+*/
+void QQuickFileDialogImpl::setAcceptLabel(const QString &label)
+{
+ Q_D(QQuickFileDialogImpl);
+ d->acceptLabel = label;
+ QQuickFileDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ auto acceptButton = attached->buttonBox()->standardButton(QPlatformDialogHelper::Open);
+ if (!acceptButton) {
+ qmlWarning(this).nospace() << "Can't set accept label to " << label
+ << "; failed to find Open button in DialogButtonBox of " << this;
+ return;
+ }
+
+ acceptButton->setText(!label.isEmpty()
+ ? label : QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::Open));
+}
+
+void QQuickFileDialogImpl::setRejectLabel(const QString &label)
+{
+ Q_D(QQuickFileDialogImpl);
+ d->rejectLabel = label;
+ QQuickFileDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ auto rejectButton = attached->buttonBox()->standardButton(QPlatformDialogHelper::Cancel);
+ if (!rejectButton) {
+ qmlWarning(this).nospace() << "Can't set reject label to " << label
+ << "; failed to find Open button in DialogButtonBox of " << this;
+ return;
+ }
+
+ rejectButton->setText(!label.isEmpty()
+ ? label : QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::Cancel));
+}
+
+void QQuickFileDialogImpl::selectNameFilter(const QString &filter)
+{
+ qCDebug(lcNameFilters) << "selectNameFilter called with" << filter;
+ Q_D(QQuickFileDialogImpl);
+ d->selectedNameFilter->update(filter);
+ emit filterSelected(filter);
+}
+
+void QQuickFileDialogImpl::componentComplete()
+{
+ Q_D(QQuickFileDialogImpl);
+ QQuickDialog::componentComplete();
+
+ // Find the right-most button and set its key navigation so that
+ // tab moves focus to the breadcrumb bar's up button. I tried
+ // doing this via KeyNavigation on the DialogButtonBox in QML,
+ // but it didn't work (probably because it's not the right item).
+ QQuickFileDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ const int buttonCount = attached->buttonBox()->count();
+ if (buttonCount == 0)
+ return;
+
+ QQuickAbstractButton *rightMostButton = qobject_cast<QQuickAbstractButton *>(
+ attached->buttonBox()->itemAt(buttonCount - 1));
+ if (!rightMostButton) {
+ qmlWarning(this) << "Can't find right-most button in DialogButtonBox";
+ return;
+ }
+
+ auto keyNavigationAttached = QQuickKeyNavigationAttached::qmlAttachedProperties(rightMostButton);
+ if (!keyNavigationAttached) {
+ qmlWarning(this) << "Can't create attached KeyNavigation object on" << QDebug::toString(rightMostButton);
+ return;
+ }
+
+ keyNavigationAttached->setTab(attached->breadcrumbBar()->upButton());
+}
+
+void QQuickFileDialogImpl::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ Q_D(QQuickFileDialogImpl);
+ QQuickDialog::itemChange(change, data);
+
+ if (change != QQuickItem::ItemVisibleHasChanged || !isComponentComplete() || !data.boolValue)
+ return;
+
+ QQuickFileDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ attached->fileDialogListView()->forceActiveFocus();
+ d->updateEnabled();
+}
+
+QQuickFileDialogImplAttached *QQuickFileDialogImplPrivate::attachedOrWarn()
+{
+ Q_Q(QQuickFileDialogImpl);
+ QQuickFileDialogImplAttached *attached = static_cast<QQuickFileDialogImplAttached*>(
+ qmlAttachedPropertiesObject<QQuickFileDialogImpl>(q));
+ if (!attached)
+ qmlWarning(q) << "Expected FileDialogImpl attached object to be present on" << this;
+ return attached;
+}
+
+void QQuickFileDialogImplAttachedPrivate::nameFiltersComboBoxItemActivated(int index)
+{
+ qCDebug(lcAttachedNameFilters) << "nameFiltersComboBoxItemActivated called with" << index;
+ auto fileDialogImpl = qobject_cast<QQuickFileDialogImpl*>(parent);
+ if (!fileDialogImpl)
+ return;
+
+ fileDialogImpl->selectNameFilter(nameFiltersComboBox->textAt(index));
+}
+
+void QQuickFileDialogImplAttachedPrivate::fileDialogListViewCurrentIndexChanged()
+{
+ auto fileDialogImpl = qobject_cast<QQuickFileDialogImpl*>(parent);
+ if (!fileDialogImpl)
+ return;
+
+ auto fileDialogDelegate = qobject_cast<QQuickFileDialogDelegate*>(fileDialogListView->currentItem());
+ if (!fileDialogDelegate)
+ return;
+
+ fileDialogImpl->setCurrentFile(fileDialogDelegate->file());
+}
+
+QQuickFileDialogImplAttached::QQuickFileDialogImplAttached(QObject *parent)
+ : QObject(*(new QQuickFileDialogImplAttachedPrivate), parent)
+{
+ if (!qobject_cast<QQuickFileDialogImpl*>(parent)) {
+ qmlWarning(this) << "FileDialogImpl attached properties should only be "
+ << "accessed through the root FileDialogImpl instance";
+ }
+}
+
+QQuickDialogButtonBox *QQuickFileDialogImplAttached::buttonBox() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->buttonBox;
+}
+
+void QQuickFileDialogImplAttached::setButtonBox(QQuickDialogButtonBox *buttonBox)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ if (buttonBox == d->buttonBox)
+ return;
+
+ if (d->buttonBox) {
+ QQuickFileDialogImpl *fileDialogImpl = qobject_cast<QQuickFileDialogImpl*>(parent());
+ if (fileDialogImpl) {
+ auto dialogPrivate = QQuickDialogPrivate::get(fileDialogImpl);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::accepted,
+ dialogPrivate, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::rejected,
+ dialogPrivate, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::clicked,
+ dialogPrivate, &QQuickDialogPrivate::handleClick);
+ }
+ }
+
+ d->buttonBox = buttonBox;
+
+ if (buttonBox) {
+ QQuickFileDialogImpl *fileDialogImpl = qobject_cast<QQuickFileDialogImpl*>(parent());
+ if (fileDialogImpl) {
+ auto dialogPrivate = QQuickDialogPrivate::get(fileDialogImpl);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::accepted,
+ dialogPrivate, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::rejected,
+ dialogPrivate, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::clicked,
+ dialogPrivate, &QQuickDialogPrivate::handleClick);
+ }
+ }
+
+ emit buttonBoxChanged();
+}
+
+QQuickComboBox *QQuickFileDialogImplAttached::nameFiltersComboBox() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->nameFiltersComboBox;
+}
+
+void QQuickFileDialogImplAttached::setNameFiltersComboBox(QQuickComboBox *nameFiltersComboBox)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ if (nameFiltersComboBox == d->nameFiltersComboBox)
+ return;
+
+ d->nameFiltersComboBox = nameFiltersComboBox;
+
+ QObjectPrivate::connect(d->nameFiltersComboBox, &QQuickComboBox::activated,
+ d, &QQuickFileDialogImplAttachedPrivate::nameFiltersComboBoxItemActivated);
+
+ emit nameFiltersComboBoxChanged();
+}
+
+QString QQuickFileDialogImplAttached::selectedNameFilter() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->nameFiltersComboBox ? d->nameFiltersComboBox->currentText() : QString();
+}
+
+void QQuickFileDialogImplAttached::selectNameFilter(const QString &filter)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ qCDebug(lcAttachedNameFilters) << "selectNameFilter called with" << filter;
+ if (!d->nameFiltersComboBox)
+ return;
+
+ const int indexInComboBox = d->nameFiltersComboBox->find(filter);
+ if (indexInComboBox == -1)
+ return;
+
+ qCDebug(lcAttachedNameFilters) << "setting ComboBox's currentIndex to" << indexInComboBox;
+ d->nameFiltersComboBox->setCurrentIndex(indexInComboBox);
+}
+
+QQuickListView *QQuickFileDialogImplAttached::fileDialogListView() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->fileDialogListView;
+}
+
+void QQuickFileDialogImplAttached::setFileDialogListView(QQuickListView *fileDialogListView)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ if (fileDialogListView == d->fileDialogListView)
+ return;
+
+ d->fileDialogListView = fileDialogListView;
+
+ QObjectPrivate::connect(d->fileDialogListView, &QQuickListView::currentIndexChanged,
+ d, &QQuickFileDialogImplAttachedPrivate::fileDialogListViewCurrentIndexChanged);
+
+ emit fileDialogListViewChanged();
+}
+
+QQuickFolderBreadcrumbBar *QQuickFileDialogImplAttached::breadcrumbBar() const
+{
+ Q_D(const QQuickFileDialogImplAttached);
+ return d->breadcrumbBar;
+}
+
+void QQuickFileDialogImplAttached::setBreadcrumbBar(QQuickFolderBreadcrumbBar *breadcrumbBar)
+{
+ Q_D(QQuickFileDialogImplAttached);
+ if (breadcrumbBar == d->breadcrumbBar)
+ return;
+
+ d->breadcrumbBar = breadcrumbBar;
+ emit breadcrumbBarChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfiledialogimpl_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p.h
new file mode 100644
index 0000000000..23f8cf14a4
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p.h
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFILEDIALOGIMPL_P_H
+#define QQUICKFILEDIALOGIMPL_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/qquicklistview_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickComboBox;
+class QQuickDialogButtonBox;
+
+class QQuickFileDialogImplAttached;
+class QQuickFileDialogImplAttachedPrivate;
+class QQuickFileDialogImplPrivate;
+class QQuickFileNameFilter;
+class QQuickFolderBreadcrumbBar;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImpl : public QQuickDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl currentFolder READ currentFolder WRITE setCurrentFolder NOTIFY currentFolderChanged FINAL)
+ Q_PROPERTY(QUrl selectedFile READ selectedFile WRITE setSelectedFile NOTIFY selectedFileChanged FINAL)
+ Q_PROPERTY(QUrl currentFile READ currentFile WRITE setCurrentFile NOTIFY currentFileChanged FINAL)
+ Q_PROPERTY(QStringList nameFilters READ nameFilters NOTIFY nameFiltersChanged FINAL)
+ Q_PROPERTY(QQuickFileNameFilter *selectedNameFilter READ selectedNameFilter CONSTANT)
+ QML_NAMED_ELEMENT(FileDialogImpl)
+ QML_ATTACHED(QQuickFileDialogImplAttached)
+ QML_ADDED_IN_VERSION(6, 2)
+ Q_MOC_INCLUDE(<QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>)
+ Q_MOC_INCLUDE(<QtQuickDialogs2QuickImpl/private/qquickfolderbreadcrumbbar_p.h>)
+
+public:
+ explicit QQuickFileDialogImpl(QObject *parent = nullptr);
+
+ static QQuickFileDialogImplAttached *qmlAttachedProperties(QObject *object);
+
+ QUrl currentFolder() const;
+ void setCurrentFolder(const QUrl &currentFolder);
+
+ QUrl selectedFile() const;
+ void setSelectedFile(const QUrl &file);
+
+ QUrl currentFile() const;
+ void setCurrentFile(const QUrl &currentFile);
+
+ QSharedPointer<QFileDialogOptions> options() const;
+ void setOptions(const QSharedPointer<QFileDialogOptions> &options);
+
+ QStringList nameFilters() const;
+ void resetNameFilters();
+
+ QQuickFileNameFilter *selectedNameFilter() const;
+
+ void setAcceptLabel(const QString &label);
+ void setRejectLabel(const QString &label);
+
+public Q_SLOTS:
+ void selectNameFilter(const QString &filter);
+
+Q_SIGNALS:
+ void currentFolderChanged(const QUrl &folderUrl);
+ void selectedFileChanged();
+ void currentFileChanged(const QUrl &currentFileUrl);
+ void nameFiltersChanged();
+ void fileSelected(const QUrl &fileUrl);
+ void filterSelected(const QString &filter);
+
+private:
+ void componentComplete() override;
+ void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override;
+
+ Q_DISABLE_COPY(QQuickFileDialogImpl)
+ Q_DECLARE_PRIVATE(QQuickFileDialogImpl)
+};
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFileDialogImplAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickDialogButtonBox *buttonBox READ buttonBox WRITE setButtonBox NOTIFY buttonBoxChanged FINAL)
+ Q_PROPERTY(QQuickComboBox *nameFiltersComboBox READ nameFiltersComboBox WRITE setNameFiltersComboBox NOTIFY nameFiltersComboBoxChanged)
+ Q_PROPERTY(QQuickListView *fileDialogListView READ fileDialogListView WRITE setFileDialogListView NOTIFY fileDialogListViewChanged)
+ Q_PROPERTY(QQuickFolderBreadcrumbBar *breadcrumbBar READ breadcrumbBar WRITE setBreadcrumbBar NOTIFY breadcrumbBarChanged)
+ Q_MOC_INCLUDE(<QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>)
+ Q_MOC_INCLUDE(<QtQuickTemplates2/private/qquickcombobox_p.h>)
+
+public:
+ explicit QQuickFileDialogImplAttached(QObject *parent = nullptr);
+
+ QQuickDialogButtonBox *buttonBox() const;
+ void setButtonBox(QQuickDialogButtonBox *buttonBox);
+
+ QQuickComboBox *nameFiltersComboBox() const;
+ void setNameFiltersComboBox(QQuickComboBox *nameFiltersComboBox);
+
+ QString selectedNameFilter() const;
+ void selectNameFilter(const QString &filter);
+
+ QQuickListView *fileDialogListView() const;
+ void setFileDialogListView(QQuickListView *fileDialogListView);
+
+ QQuickFolderBreadcrumbBar *breadcrumbBar() const;
+ void setBreadcrumbBar(QQuickFolderBreadcrumbBar *breadcrumbBar);
+
+Q_SIGNALS:
+ void buttonBoxChanged();
+ void nameFiltersComboBoxChanged();
+ void fileDialogListViewChanged();
+ void breadcrumbBarChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickFileDialogImplAttached)
+ Q_DECLARE_PRIVATE(QQuickFileDialogImplAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFileDialogImpl)
+
+#endif // QQUICKFILEDIALOGIMPL_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p_p.h
new file mode 100644
index 0000000000..1831a7dc58
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfiledialogimpl_p_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFILEDIALOG_P_P_H
+#define QQUICKFILEDIALOG_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 <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFileNameFilter;
+
+class QQuickFileDialogImplPrivate : public QQuickDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFileDialogImpl)
+
+public:
+ QQuickFileDialogImplPrivate();
+
+ static QQuickFileDialogImplPrivate *get(QQuickFileDialogImpl *dialog)
+ {
+ return dialog->d_func();
+ }
+
+ QQuickFileDialogImplAttached *attachedOrWarn();
+
+ void setNameFilters(const QStringList &filters);
+
+ void updateEnabled();
+ void updateCurrentFile(const QString &oldFolderPath);
+
+ void handleAccept() override;
+ void handleClick(QQuickAbstractButton *button) override;
+
+ QSharedPointer<QFileDialogOptions> options;
+ QUrl currentFolder;
+ QUrl selectedFile;
+ QUrl currentFile;
+ QStringList nameFilters;
+ mutable QQuickFileNameFilter *selectedNameFilter = nullptr;
+ QString acceptLabel;
+ QString rejectLabel;
+};
+
+class QQuickFileDialogImplAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFileDialogImplAttached)
+
+ void nameFiltersComboBoxItemActivated(int index);
+ void fileDialogListViewCurrentIndexChanged();
+
+public:
+ QPointer<QQuickDialogButtonBox> buttonBox;
+ QPointer<QQuickComboBox> nameFiltersComboBox;
+ QPointer<QQuickListView> fileDialogListView;
+ QPointer<QQuickFolderBreadcrumbBar> breadcrumbBar;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFILEDIALOG_P_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp
new file mode 100644
index 0000000000..a474282538
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar.cpp
@@ -0,0 +1,794 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfolderbreadcrumbbar_p.h"
+#include "qquickfolderbreadcrumbbar_p_p.h"
+
+#include <QtCore/qdir.h>
+#include <QtCore/qloggingcategory.h>
+#if QT_CONFIG(shortcut)
+#include <QtGui/private/qshortcutmap_p.h>
+#endif
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQml/QQmlFile>
+#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickpopupitem_p_p.h>
+#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+#include "qquickfiledialogimpl_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcFolderBreadcrumbBar, "qt.quick.dialogs.folderbreadcrumbbar")
+Q_LOGGING_CATEGORY(lcContentSize, "qt.quick.dialogs.folderbreadcrumbbar.contentsize")
+Q_LOGGING_CATEGORY(lcDelegates, "qt.quick.dialogs.folderbreadcrumbbar.delegates")
+Q_LOGGING_CATEGORY(lcShortcuts, "qt.quick.dialogs.folderbreadcrumbbar.shortcuts")
+Q_LOGGING_CATEGORY(lcTextInput, "qt.quick.dialogs.folderbreadcrumbbar.textinput")
+Q_LOGGING_CATEGORY(lcCurrentItem, "qt.quick.dialogs.folderbreadcrumbbar.currentitem")
+
+QQuickItem *QQuickFolderBreadcrumbBarPrivate::createDelegateItem(QQmlComponent *component, const QVariantMap &initialProperties)
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ // If we don't use the correct context, it won't be possible to refer to
+ // the control's id from within the delegates.
+ QQmlContext *creationContext = component->creationContext();
+ // The component might not have been created in QML, in which case
+ // the creation context will be null and we have to create it ourselves.
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext, q);
+ context->setContextObject(q);
+ QQuickItem *item = qobject_cast<QQuickItem*>(component->createWithInitialProperties(initialProperties, context));
+ if (item)
+ QQml_setParent_noEvent(item, q);
+ qCDebug(lcDelegates) << "- created delegate item" << item << "with initialProperties" << initialProperties;
+ return item;
+}
+
+QString QQuickFolderBreadcrumbBarPrivate::folderBaseName(const QString &folderPath)
+{
+ if (folderPath == QLatin1String("/")) {
+ // Unix root.
+ return folderPath;
+ } else if (folderPath.endsWith(QLatin1String(":/"))) {
+ // Windows drive.
+ return folderPath.mid(0, folderPath.size() - 1);
+ }
+ const QString baseName = folderPath.mid(folderPath.lastIndexOf(QLatin1Char('/')) + 1);
+ return baseName;
+}
+
+/*!
+ \internal
+
+ Returns \c { "/foo", "/foo/bar", "/foo/bar/baz" } if \a folder is \c "/foo/bar/baz".
+*/
+QStringList QQuickFolderBreadcrumbBarPrivate::crumbPathsForFolder(const QUrl &folder)
+{
+ const QString folderPath = QDir::fromNativeSeparators(QQmlFile::urlToLocalFileOrQrc(folder));
+ QDir dir(folderPath);
+ // In order to collect the paths for each breadcrumb, we need to work backwards, so we prepend.
+ QStringList paths;
+ do {
+ paths.prepend(dir.absolutePath());
+ } while (dir.cdUp());
+ return paths;
+}
+
+void QQuickFolderBreadcrumbBarPrivate::repopulate()
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ qCDebug(lcDelegates) << "attemping to repopulate breadcrumb bar using folder...";
+
+ if (repopulating)
+ return;
+
+ if (!buttonDelegate || !separatorDelegate || !q->contentItem()) {
+ qCWarning(lcDelegates) << "Both delegates and contentItem must be set before repopulating";
+ return;
+ }
+
+ QBoolBlocker repopulateGuard(repopulating);
+
+ auto failureCleanup = [=](){
+ folderPaths.clear();
+ while (q->count() > 0)
+ q->removeItem(q->itemAt(0));
+ };
+
+ qCDebug(lcDelegates) << "- getting paths for directory" << fileDialog->currentFolder();
+ folderPaths = crumbPathsForFolder(fileDialog->currentFolder());
+
+ while (q->count() > 0)
+ q->removeItem(q->itemAt(0));
+
+ for (int i = 0; i < folderPaths.size(); ++i) {
+ const QString &folderPath = folderPaths.at(i);
+
+ QVariantMap initialProperties = {
+ { QStringLiteral("index"), QVariant::fromValue(i) },
+ { QStringLiteral("folderName"), QVariant::fromValue(folderBaseName(folderPath)) }
+ };
+ QQuickItem *buttonItem = createDelegateItem(buttonDelegate, initialProperties);
+ if (!buttonItem) {
+ qCWarning(lcDelegates) << "Failed creating breadcrumb buttonDelegate item:\n" << buttonDelegate->errorString();
+ failureCleanup();
+ break;
+ }
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(buttonItem)) {
+ QObjectPrivate::connect(button, &QQuickAbstractButton::clicked,
+ this, &QQuickFolderBreadcrumbBarPrivate::crumbClicked);
+ }
+ insertItem(q->count(), buttonItem);
+
+ // Don't add a separator for the last button.
+ if (i < folderPaths.size() - 1) {
+ initialProperties = {};
+ QQuickItem *separatorItem = createDelegateItem(separatorDelegate, initialProperties);
+ if (!separatorItem) {
+ qCWarning(lcDelegates) << "Failed creating breadcrumb separatorDelegate item:\n" << buttonDelegate->errorString();
+ failureCleanup();
+ break;
+ }
+ insertItem(q->count(), separatorItem);
+ }
+ }
+
+ const int finalCount = q->count();
+ // We would do - 2, since separators are included in the count,
+ // but as we don't add a separator for the last button, we only need to subtract 1.
+ const int newCurrentIndex = finalCount > 2 ? finalCount - 1 : -1;
+ qCDebug(lcDelegates) << "- setting currentIndex to" << newCurrentIndex;
+ q->setCurrentIndex(newCurrentIndex);
+
+ updateImplicitContentSize();
+
+ qCDebug(lcDelegates) << "... bar now contains" << q->count()
+ << "buttons and separators in total, for the following paths:" << folderPaths;
+}
+
+void QQuickFolderBreadcrumbBarPrivate::crumbClicked()
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ qCDebug(lcCurrentItem) << "updateCurrentIndex called by sender" << q->sender();
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
+ if (button) {
+ const int buttonIndex = contentModel->indexOf(button, nullptr);
+ q->setCurrentIndex(buttonIndex);
+ const QUrl folderUrl = QUrl::fromLocalFile(folderPaths.at(buttonIndex / 2));
+ // TODO: don't repopulate the whole model when clicking on crumbs
+ qCDebug(lcCurrentItem) << "setting file dialog's folder to" << folderUrl;
+ fileDialog->setCurrentFolder(folderUrl);
+ }
+}
+
+void QQuickFolderBreadcrumbBarPrivate::folderChanged()
+{
+ if (componentComplete)
+ repopulate();
+}
+
+static inline QString upButtonName()
+{
+ return QStringLiteral("upButton");
+}
+
+void QQuickFolderBreadcrumbBarPrivate::cancelUpButton()
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ quickCancelDeferred(q, upButtonName());
+}
+
+void QQuickFolderBreadcrumbBarPrivate::executeUpButton(bool complete)
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ if (upButton.wasExecuted())
+ return;
+
+ if (!upButton || complete)
+ quickBeginDeferred(q, upButtonName(), upButton);
+ if (complete)
+ quickCompleteDeferred(q, upButtonName(), upButton);
+}
+
+void QQuickFolderBreadcrumbBarPrivate::goUp()
+{
+ QDir dir(QQmlFile::urlToLocalFileOrQrc(fileDialog->currentFolder()));
+ dir.cdUp();
+ fileDialog->setCurrentFolder(QUrl::fromLocalFile(dir.absolutePath()));
+}
+
+static inline QString textFieldName()
+{
+ return QStringLiteral("textField");
+}
+
+void QQuickFolderBreadcrumbBarPrivate::cancelTextField()
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ quickCancelDeferred(q, textFieldName());
+}
+
+void QQuickFolderBreadcrumbBarPrivate::executeTextField(bool complete)
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ if (textField.wasExecuted())
+ return;
+
+ if (!textField || complete)
+ quickBeginDeferred(q, textFieldName(), textField);
+ if (complete)
+ quickCompleteDeferred(q, textFieldName(), textField);
+}
+
+void QQuickFolderBreadcrumbBarPrivate::toggleTextFieldVisibility()
+{
+ textField->setText(QQmlFile::urlToLocalFileOrQrc(fileDialog->currentFolder()));
+
+ qCDebug(lcTextInput).nospace() << "text field visibility was " << textField->isVisible()
+ << "; setting it to " << !textField->isVisible();
+ textField->setVisible(!textField->isVisible());
+
+ if (textField->isVisible()) {
+ // The text field is now visible, so give it focus,
+ // select the text, and let it handle escape/back.
+ textField->forceActiveFocus(Qt::ShortcutFocusReason);
+ textField->selectAll();
+ }
+
+ // We connect to the TextField's visibleChanged signal, so textFieldVisibleChanged()
+ // will get called automatically and we don't need to call it here.
+
+ contentItem->setVisible(!textField->isVisible());
+
+ // When the TextField is visible, certain items in the dialog need to be disabled.
+ auto fileDialogPrivate = QQuickFileDialogImplPrivate::get(fileDialog);
+ fileDialogPrivate->updateEnabled();
+}
+
+void QQuickFolderBreadcrumbBarPrivate::textFieldAccepted()
+{
+ const QUrl fileUrl = QUrl::fromLocalFile(textField->text());
+ const bool mustExist = fileDialog->options()->acceptMode() != QFileDialogOptions::AcceptSave;
+ const bool enteredPathIsValidUrl = fileUrl.isValid();
+ bool enteredPathExists = false;
+ bool enteredPathIsDir = false;
+ if (enteredPathIsValidUrl) {
+ const QFileInfo fileInfo(textField->text());
+ enteredPathExists = fileInfo.exists();
+ if (enteredPathExists)
+ enteredPathIsDir = fileInfo.isDir();
+ }
+
+ qCDebug(lcTextInput).nospace() << "text field accepted -"
+ << " text=" << textField->text()
+ << " fileUrl=" << fileUrl
+ << " mustExist=" << mustExist
+ << " enteredPathIsValidUrl=" << enteredPathIsValidUrl
+ << " enteredPathExists=" << enteredPathExists
+ << " enteredPathIsDir=" << enteredPathIsDir;
+
+ if (enteredPathIsDir && (enteredPathExists || !mustExist)) {
+ qCDebug(lcTextInput) << "path entered is a folder; setting folder";
+ fileDialog->setCurrentFolder(fileUrl);
+ } else if (!enteredPathIsDir && (enteredPathExists || !mustExist)) {
+ qCDebug(lcTextInput) << "path entered is a file; setting file and calling accept()";
+ // It's important that we set the currentFile here, as that's what
+ // QQuickPlatformFileDialog::selectedFiles() needs to return, and
+ // QQuickFileDialog::accept() sets its file property based on
+ // selectedFiles().
+ fileDialog->setCurrentFile(fileUrl);
+ fileDialog->setSelectedFile(fileUrl);
+ fileDialog->accept();
+ } else {
+ qCDebug(lcTextInput) << "path entered is not valid; not setting file/folder";
+ }
+
+ // If the enter key was pressed and the dialog closed, the text input will lose
+ // active focus, and textFieldActiveFocusChanged() will toggle its visibility.
+ // We should only toggle visibility if the dialog is actually closed, otherwise
+ // we'll end up toggling twice, and the text input will be visible the next time
+ // the dialog is opened.
+ if (fileDialog->isVisible())
+ toggleTextFieldVisibility();
+}
+
+void QQuickFolderBreadcrumbBarPrivate::textFieldVisibleChanged()
+{
+ qCDebug(lcShortcuts) << "text field was either hidden or shown";
+
+ if (textField && textField->isVisible())
+ handleTextFieldShown();
+ else
+ handleTextFieldHidden();
+}
+
+void QQuickFolderBreadcrumbBarPrivate::textFieldActiveFocusChanged()
+{
+ qCDebug(lcTextInput) << "text field activeFocus changed to" << textField->hasActiveFocus();
+
+ // When the text field loses focus, it should be hidden.
+ if (!textField->hasActiveFocus() && textField->isVisible())
+ toggleTextFieldVisibility();
+}
+
+/*
+ When the text field is visible:
+
+ - Ctrl+L should do nothing (matches e.g. Ubuntu and Windows)
+ - Escape/back should hide it
+*/
+void QQuickFolderBreadcrumbBarPrivate::handleTextFieldShown()
+{
+#if QT_CONFIG(shortcut)
+ Q_Q(QQuickFolderBreadcrumbBar);
+ if (editPathToggleShortcutId == 0)
+ return;
+
+ QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
+ qCDebug(lcShortcuts) << "text field was shown; grabbing/ungrabbing relevant shortcuts...";
+
+ // Disable the back/escape shortcuts for QQuickPopup so that the TextField can get them.
+ auto popupItem = qobject_cast<QQuickPopupItem*>(fileDialog->popupItem());
+ popupItem->ungrabShortcut();
+
+ appPrivate->shortcutMap.removeShortcut(editPathToggleShortcutId, q);
+ editPathToggleShortcutId = 0;
+
+ editPathBackShortcutId = appPrivate->shortcutMap.addShortcut(
+ q, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ editPathEscapeShortcutId = appPrivate->shortcutMap.addShortcut(
+ q, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+
+ qCDebug(lcShortcuts).nospace() << "... shortcut IDs:"
+ << " editPathToggleShortcutId=" << editPathToggleShortcutId
+ << " editPathBackShortcutId=" << editPathBackShortcutId
+ << " editPathEscapeShortcutId=" << editPathEscapeShortcutId;
+#endif
+}
+
+/*
+ When the text field is not visible:
+
+ - Ctrl+L should make it visible
+ - Escape/back should close the dialog
+*/
+void QQuickFolderBreadcrumbBarPrivate::handleTextFieldHidden()
+{
+#if QT_CONFIG(shortcut)
+ Q_Q(QQuickFolderBreadcrumbBar);
+
+ QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
+ qCDebug(lcShortcuts) << "text field was hidden; grabbing/ungrabbing relevant shortcuts...";
+
+ if (editPathToggleShortcutId == 0) {
+ editPathToggleShortcutId = appPrivate->shortcutMap.addShortcut(
+ q, Qt::CTRL | Qt::Key_L, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ }
+
+ // When the bar is first completed, this function is called, since the text field starts off hidden.
+ // If removeShortcut is called with a zero id, all shortcuts for the given object will be removed,
+ // and we don't want that.
+ if (editPathBackShortcutId != 0) {
+ appPrivate->shortcutMap.removeShortcut(editPathBackShortcutId, q);
+ editPathBackShortcutId = 0;
+ }
+ if (editPathEscapeShortcutId != 0) {
+ appPrivate->shortcutMap.removeShortcut(editPathEscapeShortcutId, q);
+ editPathEscapeShortcutId = 0;
+ }
+
+ // Re-enable the back/escape shortcuts for QQuickPopup now that TextField no longer needs them.
+ auto popupItem = qobject_cast<QQuickPopupItem*>(fileDialog->popupItem());
+ if (popupItem)
+ popupItem->grabShortcut();
+
+ qCDebug(lcShortcuts).nospace() << "... shortcut IDs: "
+ << " editPathToggleShortcutId=" << editPathToggleShortcutId
+ << " editPathBackShortcutId=" << editPathBackShortcutId
+ << " editPathEscapeShortcutId=" << editPathEscapeShortcutId;
+#endif
+}
+
+void QQuickFolderBreadcrumbBarPrivate::ungrabEditPathShortcuts()
+{
+#if QT_CONFIG(shortcut)
+ Q_Q(QQuickFolderBreadcrumbBar);
+ QGuiApplicationPrivate *appPrivate = QGuiApplicationPrivate::instance();
+ qCDebug(lcShortcuts) << "ungrabbing all edit path shortcuts";
+
+ if (editPathToggleShortcutId != 0) {
+ appPrivate->shortcutMap.removeShortcut(editPathToggleShortcutId, q);
+ editPathToggleShortcutId = 0;
+ }
+ if (editPathBackShortcutId != 0) {
+ appPrivate->shortcutMap.removeShortcut(editPathBackShortcutId, q);
+ editPathBackShortcutId = 0;
+ }
+ if (editPathEscapeShortcutId != 0) {
+ appPrivate->shortcutMap.removeShortcut(editPathEscapeShortcutId, q);
+ editPathEscapeShortcutId = 0;
+ }
+#endif
+}
+
+qreal QQuickFolderBreadcrumbBarPrivate::getContentWidth() const
+{
+ Q_Q(const QQuickFolderBreadcrumbBar);
+ const int count = contentModel->count();
+ qreal totalWidth = qMax(0, count - 1) * spacing;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid())
+ totalWidth += item->implicitWidth();
+ else
+ totalWidth += item->width();
+ }
+ }
+ qCDebug(lcContentSize) << "content width:" << totalWidth;
+ return totalWidth;
+}
+
+qreal QQuickFolderBreadcrumbBarPrivate::getContentHeight() const
+{
+ Q_Q(const QQuickFolderBreadcrumbBar);
+ const int count = contentModel->count();
+ qreal maxHeight = 0;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item)
+ maxHeight = qMax(maxHeight, item->implicitHeight());
+ }
+ qCDebug(lcContentSize) << "content height:" << maxHeight;
+ return maxHeight;
+}
+
+void QQuickFolderBreadcrumbBarPrivate::resizeContent()
+{
+ Q_Q(QQuickFolderBreadcrumbBar);
+ if (contentItem) {
+ const int upButtonSpace = q->upButton() ? q->upButton()->width() + upButtonSpacing : 0;
+ contentItem->setPosition(QPointF(q->leftPadding() + upButtonSpace, q->topPadding()));
+ contentItem->setSize(QSizeF(q->availableWidth() - upButtonSpace, q->availableHeight()));
+
+ if (textField) {
+ textField->setPosition(contentItem->position());
+ textField->setSize(contentItem->size());
+ }
+ }
+}
+
+void QQuickFolderBreadcrumbBarPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ QQuickContainerPrivate::itemGeometryChanged(item, change, diff);
+ if (change.sizeChange())
+ updateImplicitContentSize();
+}
+
+void QQuickFolderBreadcrumbBarPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitWidthChanged(item);
+ if (item != contentItem)
+ updateImplicitContentWidth();
+}
+
+void QQuickFolderBreadcrumbBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitHeightChanged(item);
+ if (item != contentItem)
+ updateImplicitContentHeight();
+}
+
+/*!
+ \internal
+
+ Private class for breadcrumb navigation of a directory.
+
+ Given a FileDialog, FolderBreadCrumbbar creates breadcrumb buttons and
+ separators from the specified delegate components.
+*/
+
+QQuickFolderBreadcrumbBar::QQuickFolderBreadcrumbBar(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickFolderBreadcrumbBarPrivate), parent)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ d->changeTypes |= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+}
+
+QQuickFileDialogImpl *QQuickFolderBreadcrumbBar::fileDialog() const
+{
+ Q_D(const QQuickFolderBreadcrumbBar);
+ return d->fileDialog;
+}
+
+void QQuickFolderBreadcrumbBar::setFileDialog(QQuickFileDialogImpl *fileDialog)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (fileDialog == d->fileDialog)
+ return;
+
+ if (d->fileDialog)
+ QObjectPrivate::disconnect(d->fileDialog, &QQuickFileDialogImpl::currentFolderChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::folderChanged);
+
+ d->fileDialog = fileDialog;
+
+ if (d->fileDialog)
+ QObjectPrivate::connect(d->fileDialog, &QQuickFileDialogImpl::currentFolderChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::folderChanged);
+
+ emit fileDialogChanged();
+}
+
+QQmlComponent *QQuickFolderBreadcrumbBar::buttonDelegate()
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ return d->buttonDelegate;
+}
+
+void QQuickFolderBreadcrumbBar::setButtonDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ qCDebug(lcFolderBreadcrumbBar) << "setButtonDelegate called with" << delegate;
+ if (d->componentComplete) {
+ // Simplify the code by disallowing this.
+ qCWarning(lcFolderBreadcrumbBar) << "BreadcrumbBar does not support setting delegates after component completion";
+ return;
+ }
+
+ if (delegate == d->buttonDelegate)
+ return;
+
+ d->buttonDelegate = delegate;
+ emit buttonDelegateChanged();
+}
+
+QQmlComponent *QQuickFolderBreadcrumbBar::separatorDelegate()
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ return d->separatorDelegate;
+}
+
+void QQuickFolderBreadcrumbBar::setSeparatorDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ qCDebug(lcFolderBreadcrumbBar) << "setSeparatorDelegate called with" << delegate;
+ if (d->componentComplete) {
+ qCWarning(lcFolderBreadcrumbBar) << "BreadcrumbBar does not support setting delegates after component completion";
+ return;
+ }
+
+ if (delegate == d->separatorDelegate)
+ return;
+
+ d->separatorDelegate = delegate;
+ emit separatorDelegateChanged();
+}
+
+QQuickAbstractButton *QQuickFolderBreadcrumbBar::upButton()
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (!d->upButton)
+ d->executeUpButton();
+ return d->upButton;
+}
+
+void QQuickFolderBreadcrumbBar::setUpButton(QQuickAbstractButton *upButton)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (upButton == d->upButton)
+ return;
+
+ if (!d->upButton.isExecuting())
+ d->cancelUpButton();
+
+ if (d->upButton) {
+ QObjectPrivate::disconnect(d->upButton.data(), &QQuickAbstractButton::clicked,
+ d, &QQuickFolderBreadcrumbBarPrivate::goUp);
+ }
+
+ QQuickControlPrivate::hideOldItem(d->upButton);
+ d->upButton = upButton;
+ if (d->upButton) {
+ if (!d->upButton->parentItem())
+ d->upButton->setParentItem(this);
+
+ QObjectPrivate::connect(d->upButton.data(), &QQuickAbstractButton::clicked,
+ d, &QQuickFolderBreadcrumbBarPrivate::goUp);
+ }
+ if (!d->upButton.isExecuting())
+ emit upButtonChanged();
+}
+
+int QQuickFolderBreadcrumbBar::upButtonSpacing() const
+{
+ Q_D(const QQuickFolderBreadcrumbBar);
+ return d->upButtonSpacing;
+}
+
+void QQuickFolderBreadcrumbBar::setUpButtonSpacing(int upButtonSpacing)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (upButtonSpacing == d->upButtonSpacing)
+ return;
+
+ d->upButtonSpacing = upButtonSpacing;
+ emit upButtonSpacingChanged();
+}
+
+QQuickTextField *QQuickFolderBreadcrumbBar::textField()
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ return d->textField;
+}
+
+void QQuickFolderBreadcrumbBar::setTextField(QQuickTextField *textField)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (textField == d->textField)
+ return;
+
+ if (!d->textField.isExecuting())
+ d->cancelUpButton();
+
+ if (d->textField)
+ d->handleTextFieldHidden();
+
+ if (d->textField) {
+ QObjectPrivate::disconnect(d->textField.data(), &QQuickTextInput::visibleChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldVisibleChanged);
+ QObjectPrivate::disconnect(d->textField.data(), &QQuickTextInput::activeFocusChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldActiveFocusChanged);
+ QObjectPrivate::disconnect(d->textField.data(), &QQuickTextInput::accepted,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldAccepted);
+ }
+
+ QQuickControlPrivate::hideOldItem(d->textField);
+ d->textField = textField;
+ if (d->textField) {
+ if (!d->textField->parentItem())
+ d->textField->setParentItem(this);
+
+ d->textField->setVisible(false);
+
+ QObjectPrivate::connect(d->textField.data(), &QQuickTextInput::visibleChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldVisibleChanged);
+ QObjectPrivate::connect(d->textField.data(), &QQuickTextInput::activeFocusChanged,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldActiveFocusChanged);
+ QObjectPrivate::connect(d->textField.data(), &QQuickTextInput::accepted,
+ d, &QQuickFolderBreadcrumbBarPrivate::textFieldAccepted);
+ }
+ if (!d->textField.isExecuting())
+ emit textFieldChanged();
+}
+
+bool QQuickFolderBreadcrumbBar::event(QEvent *event)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickFolderBreadcrumbBar);
+ if (event->type() == QEvent::Shortcut) {
+ QShortcutEvent *shortcutEvent = static_cast<QShortcutEvent *>(event);
+ if (shortcutEvent->shortcutId() == d->editPathToggleShortcutId
+ || shortcutEvent->shortcutId() == d->editPathBackShortcutId
+ || shortcutEvent->shortcutId() == d->editPathEscapeShortcutId) {
+ d->toggleTextFieldVisibility();
+ return true;
+ } else if (shortcutEvent->shortcutId() == d->goUpShortcutId) {
+ d->goUp();
+ }
+ }
+#endif
+ return QQuickItem::event(event);
+}
+
+void QQuickFolderBreadcrumbBar::componentComplete()
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ qCDebug(lcFolderBreadcrumbBar) << "componentComplete";
+ QQuickContainer::componentComplete();
+ d->repopulate();
+
+ if (d->textField) {
+ // Force it to be updated as setTextField() is too early to do it.
+ d->textFieldVisibleChanged();
+ }
+}
+
+void QQuickFolderBreadcrumbBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ Q_D(QQuickFolderBreadcrumbBar);
+ QQuickContainer::itemChange(change, data);
+
+ if (change == QQuickItem::ItemVisibleHasChanged && isComponentComplete()) {
+ if (data.boolValue && d->fileDialog->isVisible()) {
+ // It's visible.
+ d->handleTextFieldHidden();
+
+ d->goUpShortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(
+ this, QKeySequence(Qt::ALT | Qt::Key_Up), Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ } else {
+ // It's hidden.
+ // Hide the text field so that when the dialog gets opened again, it's not still visible.
+ if (d->textField)
+ d->textField->setVisible(false);
+
+ // Make the ListView visible again.
+ if (d->contentItem)
+ d->contentItem->setVisible(true);
+
+ // We also need to ungrab all shortcuts when we're not visible.
+ d->ungrabEditPathShortcuts();
+
+ if (d->goUpShortcutId != 0) {
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(d->goUpShortcutId, this);
+ d->goUpShortcutId = 0;
+ }
+ }
+ }
+}
+
+bool QQuickFolderBreadcrumbBar::isContent(QQuickItem *item) const
+{
+ if (!qmlContext(item))
+ return false;
+
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return false;
+
+ return true;
+}
+
+QFont QQuickFolderBreadcrumbBar::defaultFont() const
+{
+ // TODO
+ return QQuickTheme::font(QQuickTheme::TabBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickFolderBreadcrumbBar::accessibleRole() const
+{
+ // TODO
+ return QAccessible::PageTabList;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfolderbreadcrumbbar_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h
new file mode 100644
index 0000000000..5e14f5b04f
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFOLDERBREADCRUMBBAR_P_H
+#define QQUICKFOLDERBREADCRUMBBAR_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/qqmlcomponent.h>
+#include <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFolderBreadcrumbBarPrivate;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFolderBreadcrumbBar : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickFileDialogImpl *fileDialog READ fileDialog WRITE setFileDialog NOTIFY fileDialogChanged)
+ Q_PROPERTY(QQmlComponent *buttonDelegate READ buttonDelegate WRITE setButtonDelegate NOTIFY buttonDelegateChanged)
+ Q_PROPERTY(QQmlComponent *separatorDelegate READ separatorDelegate WRITE setSeparatorDelegate NOTIFY separatorDelegateChanged)
+ Q_PROPERTY(QQuickAbstractButton *upButton READ upButton WRITE setUpButton NOTIFY upButtonChanged)
+ Q_PROPERTY(QQuickTextField *textField READ textField WRITE setTextField NOTIFY textFieldChanged)
+ Q_PROPERTY(int upButtonSpacing READ upButtonSpacing WRITE setUpButtonSpacing NOTIFY upButtonSpacingChanged)
+ QML_NAMED_ELEMENT(FolderBreadcrumbBar)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ explicit QQuickFolderBreadcrumbBar(QQuickItem *parent = nullptr);
+
+ QQuickFileDialogImpl *fileDialog() const;
+ void setFileDialog(QQuickFileDialogImpl *fileDialog);
+
+ QQmlComponent *buttonDelegate();
+ void setButtonDelegate(QQmlComponent *delegate);
+
+ QQmlComponent *separatorDelegate();
+ void setSeparatorDelegate(QQmlComponent *delegate);
+
+ QQuickAbstractButton *upButton();
+ void setUpButton(QQuickAbstractButton *upButton);
+
+ int upButtonSpacing() const;
+ void setUpButtonSpacing(int upButtonSpacing);
+
+ QQuickTextField *textField();
+ void setTextField(QQuickTextField *textField);
+
+Q_SIGNALS:
+ void fileDialogChanged();
+ void buttonDelegateChanged();
+ void separatorDelegateChanged();
+ void upButtonChanged();
+ void upButtonSpacingChanged();
+ void textFieldChanged();
+
+protected:
+ bool event(QEvent *event) override;
+
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+
+ bool isContent(QQuickItem *item) const override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickFolderBreadcrumbBar)
+ Q_DECLARE_PRIVATE(QQuickFolderBreadcrumbBar)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFolderBreadcrumbBar)
+
+#endif // QQUICKFOLDERBREADCRUMBBAR_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h
new file mode 100644
index 0000000000..4616b6a9c5
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfolderbreadcrumbbar_p_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFOLDERBREADCRUMBBAR_P_P_H
+#define QQUICKFOLDERBREADCRUMBBAR_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 <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+#include <QtQuickTemplates2/private/qquickdeferredexecute_p_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAbstractButton;
+class QQuickTextField;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFolderBreadcrumbBarPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFolderBreadcrumbBar)
+
+public:
+ QQuickItem *createDelegateItem(QQmlComponent *component, const QVariantMap &initialProperties);
+ static QString folderBaseName(const QString &folderPath);
+ static QStringList crumbPathsForFolder(const QUrl &folder);
+ void repopulate();
+ void crumbClicked();
+ void folderChanged();
+
+ void cancelUpButton();
+ void executeUpButton(bool complete = false);
+ void goUp();
+
+ void cancelTextField();
+ void executeTextField(bool complete = false);
+ void toggleTextFieldVisibility();
+ void textFieldAccepted();
+
+ void textFieldVisibleChanged();
+ void textFieldActiveFocusChanged();
+ void handleTextFieldShown();
+ void handleTextFieldHidden();
+ void ungrabEditPathShortcuts();
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+ void resizeContent() override;
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+private:
+ QQuickFileDialogImpl *fileDialog = nullptr;
+ QList<QString> folderPaths;
+ QQmlComponent *buttonDelegate = nullptr;
+ QQmlComponent *separatorDelegate = nullptr;
+ QQuickDeferredPointer<QQuickAbstractButton> upButton;
+ QQuickDeferredPointer<QQuickTextField> textField;
+ int editPathToggleShortcutId = 0;
+ int editPathBackShortcutId = 0;
+ int editPathEscapeShortcutId = 0;
+ int goUpShortcutId = 0;
+ int upButtonSpacing = 0;
+ bool repopulating = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFOLDERBREADCRUMBBAR_P_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl.cpp
new file mode 100644
index 0000000000..ba0b69ef26
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl.cpp
@@ -0,0 +1,865 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfontdialogimpl_p.h"
+#include "qquickfontdialogimpl_p_p.h"
+
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p_p.h>
+#include <private/qfontdatabase_p.h>
+
+#include <QRegularExpression>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcAttachedProperty, "qt.quick.dialogs.quickfontdialogimpl.attachedOrWarn")
+
+QQuickFontDialogImplPrivate::QQuickFontDialogImplPrivate()
+{
+}
+
+QQuickFontDialogImplAttached *QQuickFontDialogImplPrivate::attachedOrWarn()
+{
+ Q_Q(QQuickFontDialogImpl);
+ QQuickFontDialogImplAttached *attached = static_cast<QQuickFontDialogImplAttached *>(
+ qmlAttachedPropertiesObject<QQuickFontDialogImpl>(q));
+ if (!attached) {
+ qCWarning(lcAttachedProperty)
+ << "Expected FontDialogImpl attached object to be present on" << this;
+ }
+ return attached;
+}
+
+void QQuickFontDialogImplPrivate::handleAccept() { }
+
+void QQuickFontDialogImplPrivate::handleClick(QQuickAbstractButton *button)
+{
+ Q_Q(QQuickFontDialogImpl);
+ if (buttonRole(button) == QPlatformDialogHelper::AcceptRole) {
+ q->accept();
+ QQuickDialogPrivate::handleClick(button);
+ }
+}
+
+QQuickFontDialogImpl::QQuickFontDialogImpl(QObject *parent)
+ : QQuickDialog(*(new QQuickFontDialogImplPrivate), parent)
+{
+}
+
+QQuickFontDialogImplAttached *QQuickFontDialogImpl::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickFontDialogImplAttached(object);
+}
+
+QSharedPointer<QFontDialogOptions> QQuickFontDialogImpl::options() const
+{
+ Q_D(const QQuickFontDialogImpl);
+
+ return d->options;
+}
+
+void QQuickFontDialogImpl::setOptions(const QSharedPointer<QFontDialogOptions> &options)
+{
+ Q_D(QQuickFontDialogImpl);
+
+ if (options == d->options)
+ return;
+
+ d->options = options;
+
+ emit optionsChanged();
+}
+
+QFont QQuickFontDialogImpl::currentFont() const
+{
+ Q_D(const QQuickFontDialogImpl);
+ return d->currentFont;
+}
+
+void QQuickFontDialogImpl::setCurrentFont(const QFont &font, bool selectInListViews)
+{
+ Q_D(QQuickFontDialogImpl);
+
+ if (font == d->currentFont)
+ return;
+
+ d->currentFont = font;
+
+ emit currentFontChanged(font);
+
+ if (!selectInListViews)
+ return;
+
+ QQuickFontDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ attached->selectFontInListViews(font);
+}
+
+void QQuickFontDialogImpl::init()
+{
+ Q_D(QQuickFontDialogImpl);
+ QQuickFontDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ if (!attached->familyListView()->model().isValid())
+ attached->updateFamilies();
+
+ attached->buttonBox()->setVisible(!(options()->options() & QFontDialogOptions::NoButtons));
+}
+
+void QQuickFontDialogImpl::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickFontDialogImpl);
+
+ QQuickDialog::keyReleaseEvent(event);
+
+ QQuickFontDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ // The family and style text edits are read-only so that they
+ // can show the current selection but also allow key input to "search".
+ // This is why we handle just the release event, and don't accept it.
+ if (window()->activeFocusItem() == attached->familyEdit())
+ attached->searchFamily(event->text());
+ else if (window()->activeFocusItem() == attached->styleEdit())
+ attached->searchStyle(event->text());
+}
+
+void QQuickFontDialogImpl::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QQuickFontDialogImpl);
+
+ QQuickDialog::focusOutEvent(event);
+
+ QQuickFontDialogImplAttached *attached = d->attachedOrWarn();
+ if (!attached)
+ return;
+
+ attached->clearSearch();
+}
+
+QQuickFontDialogImplAttached::QQuickFontDialogImplAttached(QObject *parent)
+ : QObject(*(new QQuickFontDialogImplAttachedPrivate), parent),
+ m_writingSystem(QFontDatabase::Any),
+ m_selectedSize(-1),
+ m_smoothlyScalable(false),
+ m_ignoreFamilyUpdate(false),
+ m_ignoreStyleUpdate(false)
+{
+ if (!qobject_cast<QQuickFontDialogImpl *>(parent)) {
+ qmlWarning(this) << "FontDialogImpl attached properties should only be "
+ << "accessed through the root FileDialogImpl instance";
+ }
+}
+
+QQuickListView *QQuickFontDialogImplAttached::familyListView() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->familyListView;
+}
+
+void QQuickFontDialogImplAttached::setFamilyListView(QQuickListView *familyListView)
+{
+ Q_D(QQuickFontDialogImplAttached);
+ if (d->familyListView == familyListView)
+ return;
+
+ if (d->familyListView) {
+ disconnect(d->familyListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_familyChanged);
+ }
+
+ d->familyListView = familyListView;
+
+ if (familyListView) {
+ connect(d->familyListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_familyChanged);
+ }
+
+ emit familyListViewChanged();
+}
+
+QQuickListView *QQuickFontDialogImplAttached::styleListView() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->styleListView;
+}
+
+void QQuickFontDialogImplAttached::setStyleListView(QQuickListView *styleListView)
+{
+ Q_D(QQuickFontDialogImplAttached);
+ if (d->styleListView == styleListView)
+ return;
+
+ if (d->styleListView) {
+ disconnect(d->styleListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_styleChanged);
+ }
+
+ d->styleListView = styleListView;
+
+ if (styleListView) {
+ connect(d->styleListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_styleChanged);
+ }
+
+ emit styleListViewChanged();
+}
+
+QQuickListView *QQuickFontDialogImplAttached::sizeListView() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->sizeListView;
+}
+
+void QQuickFontDialogImplAttached::setSizeListView(QQuickListView *sizeListView)
+{
+ Q_D(QQuickFontDialogImplAttached);
+ if (d->sizeListView == sizeListView)
+ return;
+
+ if (d->sizeListView) {
+ disconnect(d->sizeListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_sizeChanged);
+ }
+
+ d->sizeListView = sizeListView;
+
+ if (d->sizeListView) {
+ connect(d->sizeListView, &QQuickListView::currentIndexChanged,
+ this, &QQuickFontDialogImplAttached::_q_sizeChanged);
+ }
+
+ emit sizeListViewChanged();
+}
+
+QQuickTextEdit *QQuickFontDialogImplAttached::sampleEdit() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->sampleEdit;
+}
+
+void QQuickFontDialogImplAttached::setSampleEdit(QQuickTextEdit *sampleEdit)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->sampleEdit == sampleEdit)
+ return;
+
+ if (d->sampleEdit) {
+ QObjectPrivate::disconnect(d->sampleEdit, &QQuickTextEdit::fontChanged,
+ d, &QQuickFontDialogImplAttachedPrivate::currentFontChanged);
+ }
+
+ d->sampleEdit = sampleEdit;
+
+ if (d->sampleEdit) {
+ QObjectPrivate::connect(d->sampleEdit, &QQuickTextEdit::fontChanged,
+ d, &QQuickFontDialogImplAttachedPrivate::currentFontChanged);
+
+ d->sampleEdit->setText(QFontDatabase::writingSystemSample(m_writingSystem));
+ }
+
+ emit sampleEditChanged();
+}
+
+QQuickDialogButtonBox *QQuickFontDialogImplAttached::buttonBox() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->buttonBox;
+}
+
+void QQuickFontDialogImplAttached::setButtonBox(QQuickDialogButtonBox *buttonBox)
+{
+ Q_D(QQuickFontDialogImplAttached);
+ if (buttonBox == d->buttonBox)
+ return;
+
+ if (d->buttonBox) {
+ QQuickFontDialogImpl *fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(parent());
+ if (fontDialogImpl) {
+ auto dialogPrivate = QQuickDialogPrivate::get(fontDialogImpl);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::accepted,
+ dialogPrivate, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::rejected,
+ dialogPrivate, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::disconnect(d->buttonBox, &QQuickDialogButtonBox::clicked, dialogPrivate,
+ &QQuickDialogPrivate::handleClick);
+ }
+ }
+
+ d->buttonBox = buttonBox;
+
+ if (buttonBox) {
+ QQuickFontDialogImpl *fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(parent());
+ if (fontDialogImpl) {
+ auto dialogPrivate = QQuickDialogPrivate::get(fontDialogImpl);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::accepted, dialogPrivate,
+ &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::rejected, dialogPrivate,
+ &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::connect(d->buttonBox, &QQuickDialogButtonBox::clicked, dialogPrivate,
+ &QQuickDialogPrivate::handleClick);
+ }
+ }
+
+ emit buttonBoxChanged();
+}
+
+QQuickComboBox *QQuickFontDialogImplAttached::writingSystemComboBox() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->writingSystemComboBox;
+}
+
+void QQuickFontDialogImplAttached::setWritingSystemComboBox(QQuickComboBox *writingSystemComboBox)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->writingSystemComboBox == writingSystemComboBox)
+ return;
+
+ if (d->writingSystemComboBox) {
+ disconnect(d->writingSystemComboBox, &QQuickComboBox::activated,
+ this, &QQuickFontDialogImplAttached::_q_writingSystemChanged);
+ }
+
+ d->writingSystemComboBox = writingSystemComboBox;
+
+ if (d->writingSystemComboBox) {
+ QStringList writingSystemModel;
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ QFontDatabase::WritingSystem ws = QFontDatabase::WritingSystem(i);
+ QString wsName = QFontDatabase::writingSystemName(ws);
+ if (wsName.isEmpty())
+ break;
+ writingSystemModel.append(wsName);
+ }
+
+ d->writingSystemComboBox->setModel(writingSystemModel);
+
+ connect(d->writingSystemComboBox, &QQuickComboBox::activated,
+ this, &QQuickFontDialogImplAttached::_q_writingSystemChanged);
+ }
+
+ emit writingSystemComboBoxChanged();
+}
+
+QQuickCheckBox *QQuickFontDialogImplAttached::underlineCheckBox() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->underlineCheckBox;
+}
+
+void QQuickFontDialogImplAttached::setUnderlineCheckBox(QQuickCheckBox *underlineCheckBox)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->underlineCheckBox == underlineCheckBox)
+ return;
+
+ if (d->underlineCheckBox) {
+ disconnect(d->underlineCheckBox, &QQuickCheckBox::checkStateChanged,
+ this, &QQuickFontDialogImplAttached::_q_updateSample);
+ }
+
+ d->underlineCheckBox = underlineCheckBox;
+
+ if (d->underlineCheckBox) {
+ connect(d->underlineCheckBox, &QQuickCheckBox::checkStateChanged,
+ this, &QQuickFontDialogImplAttached::_q_updateSample);
+ }
+
+ emit underlineCheckBoxChanged();
+}
+
+QQuickCheckBox *QQuickFontDialogImplAttached::strikeoutCheckBox() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->strikeoutCheckBox;
+}
+
+void QQuickFontDialogImplAttached::setStrikeoutCheckBox(QQuickCheckBox *strikeoutCheckBox)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->strikeoutCheckBox == strikeoutCheckBox)
+ return;
+
+ if (d->strikeoutCheckBox) {
+ disconnect(d->strikeoutCheckBox, &QQuickCheckBox::checkStateChanged,
+ this, &QQuickFontDialogImplAttached::_q_updateSample);
+ }
+
+ d->strikeoutCheckBox = strikeoutCheckBox;
+
+ if (d->strikeoutCheckBox) {
+ connect(d->strikeoutCheckBox, &QQuickCheckBox::checkStateChanged,
+ this, &QQuickFontDialogImplAttached::_q_updateSample);
+ }
+
+ emit strikeoutCheckBoxChanged();
+}
+
+QQuickTextField *QQuickFontDialogImplAttached::familyEdit() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->familyEdit;
+}
+
+void QQuickFontDialogImplAttached::setFamilyEdit(QQuickTextField *familyEdit)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->familyEdit == familyEdit)
+ return;
+
+ d->familyEdit = familyEdit;
+
+ emit familyEditChanged();
+}
+
+QQuickTextField *QQuickFontDialogImplAttached::styleEdit() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->styleEdit;
+}
+
+void QQuickFontDialogImplAttached::setStyleEdit(QQuickTextField *styleEdit)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->styleEdit == styleEdit)
+ return;
+
+ d->styleEdit = styleEdit;
+
+ emit styleEditChanged();
+}
+
+QQuickTextField *QQuickFontDialogImplAttached::sizeEdit() const
+{
+ Q_D(const QQuickFontDialogImplAttached);
+ return d->sizeEdit;
+}
+
+void QQuickFontDialogImplAttached::setSizeEdit(QQuickTextField *sizeEdit)
+{
+ Q_D(QQuickFontDialogImplAttached);
+
+ if (d->sizeEdit == sizeEdit)
+ return;
+
+ if (d->sizeEdit) {
+ disconnect(d->sizeEdit, &QQuickTextField::textChanged,
+ this, &QQuickFontDialogImplAttached::_q_sizeEdited);
+ }
+
+ d->sizeEdit = sizeEdit;
+
+ if (d->sizeEdit) {
+ connect(d->sizeEdit, &QQuickTextField::textChanged,
+ this, &QQuickFontDialogImplAttached::_q_sizeEdited);
+ }
+
+ emit sizeEditChanged();
+}
+
+static int findFamilyInModel(const QString &selectedFamily, const QStringList &model)
+{
+ enum match_t { MATCH_NONE = 0, MATCH_LAST_RESORT = 1, MATCH_APP = 2, MATCH_FAMILY = 3 };
+ QString foundryName1, familyName1, foundryName2, familyName2;
+ int bestFamilyMatch = -1;
+ match_t bestFamilyType = MATCH_NONE;
+ const QFont f;
+
+ QFontDatabasePrivate::parseFontName(selectedFamily, foundryName1, familyName1);
+
+ int i = 0;
+ for (auto it = model.constBegin(); it != model.constEnd(); ++it, ++i) {
+ QFontDatabasePrivate::parseFontName(*it, foundryName2, familyName2);
+
+ if (familyName1 == familyName2) {
+ bestFamilyType = MATCH_FAMILY;
+ if (foundryName1 == foundryName2)
+ return i;
+ else
+ bestFamilyMatch = i;
+ }
+
+ // fallbacks
+ match_t type = MATCH_NONE;
+ if (bestFamilyType <= MATCH_NONE && familyName2 == QStringLiteral("helvetica"))
+ type = MATCH_LAST_RESORT;
+ if (bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.families().constFirst())
+ type = MATCH_APP;
+ if (type != MATCH_NONE) {
+ bestFamilyType = type;
+ bestFamilyMatch = i;
+ }
+ }
+
+ return bestFamilyMatch;
+}
+
+static int findStyleInModel(const QString &selectedStyle, const QStringList &model)
+{
+ if (model.isEmpty())
+ return -1;
+
+ if (!selectedStyle.isEmpty()) {
+ const int idx = model.indexOf(QRegularExpression(QRegularExpression::escape(selectedStyle), QRegularExpression::CaseInsensitiveOption));
+ if (idx >= 0)
+ return idx;
+
+ enum class StyleClass {Unknown, Normal, Italic};
+ auto classifyStyleFallback = [](const QString & style) {
+ if (style.toLower() == QLatin1String("italic") || style.toLower() == QLatin1String("oblique"))
+ return StyleClass::Italic;
+ if (style.toLower() == QLatin1String("normal") || style.toLower() == QLatin1String("regular"))
+ return StyleClass::Normal;
+ return StyleClass::Unknown;
+ };
+
+ auto styleClass = classifyStyleFallback(selectedStyle);
+
+ if (styleClass != StyleClass::Unknown)
+ for (int i = 0; i < model.count(); ++i)
+ if (classifyStyleFallback(model.at(i)) == styleClass)
+ return i;
+ }
+ return 0;
+}
+
+/*!
+ \internal
+
+ Updates the model for the family list view, and attempt
+ to reselect the previously selected font family.
+ */
+void QQuickFontDialogImplAttached::updateFamilies()
+{
+ const QFontDialogOptions::FontDialogOptions scalableMask(
+ QFontDialogOptions::ScalableFonts | QFontDialogOptions::NonScalableFonts);
+
+ const QFontDialogOptions::FontDialogOptions spacingMask(QFontDialogOptions::ProportionalFonts
+ | QFontDialogOptions::MonospacedFonts);
+
+ const auto p = qobject_cast<QQuickFontDialogImpl *>(parent());
+
+ const auto options = p->options()->options();
+
+ QStringList familyNames;
+ const auto families = QFontDatabase::families(m_writingSystem);
+ for (const auto &family : families) {
+ if (QFontDatabase::isPrivateFamily(family))
+ continue;
+
+ if ((options & scalableMask) && (options & scalableMask) != scalableMask) {
+ if (bool(options & QFontDialogOptions::ScalableFonts)
+ != QFontDatabase::isSmoothlyScalable(family))
+ continue;
+ }
+
+ if ((options & spacingMask) && (options & scalableMask) != spacingMask) {
+ if (bool(options & QFontDialogOptions::MonospacedFonts)
+ != QFontDatabase::isFixedPitch(family))
+ continue;
+ }
+
+ familyNames << family;
+ }
+
+ auto listView = familyListView();
+
+ // Index will be set to -1 on empty model, and 0 for non empty models.
+ m_ignoreFamilyUpdate = !m_selectedFamily.isEmpty();
+ listView->setModel(familyNames);
+ m_ignoreFamilyUpdate = false;
+
+ // Will overwrite selectedFamily and selectedStyle
+ listView->setCurrentIndex(findFamilyInModel(m_selectedFamily, familyNames));
+
+ if (familyNames.isEmpty())
+ _q_familyChanged();
+}
+
+/*!
+ \internal
+
+ Updates the model for the style list view, and
+ attempt to reselect the style that was previously selected.
+
+ Calls updateSizes()
+ */
+void QQuickFontDialogImplAttached::updateStyles()
+{
+ const QString family = familyListView()->currentIndex() >= 0 ? m_selectedFamily : QString();
+ const QStringList styles = QFontDatabase::styles(family);
+
+ auto listView = styleListView();
+
+ m_ignoreStyleUpdate = !m_selectedStyle.isEmpty();
+ listView->setModel(styles);
+
+ if (styles.isEmpty()) {
+ styleEdit()->clear();
+ m_smoothlyScalable = false;
+ } else {
+ int newIndex = findStyleInModel(m_selectedStyle, styles);
+
+ listView->setCurrentIndex(newIndex);
+
+ m_selectedStyle = styles.at(newIndex);
+ styleEdit()->setText(m_selectedStyle);
+
+ m_smoothlyScalable = QFontDatabase::isSmoothlyScalable(m_selectedFamily, m_selectedStyle);
+ }
+
+ m_ignoreStyleUpdate = false;
+
+ updateSizes();
+}
+
+/*!
+ \internal
+
+ Updates the model for the size list view,
+ and attempts to reselect the size that was previously selected
+ */
+void QQuickFontDialogImplAttached::updateSizes()
+{
+ if (!m_selectedFamily.isEmpty()) {
+ const QList<int> sizes = QFontDatabase::pointSizes(m_selectedFamily, m_selectedStyle);
+
+ QStringList str_sizes;
+
+ str_sizes.reserve(sizes.size());
+
+ int idx = 0, current = -1;
+ for (QList<int>::const_iterator it = sizes.constBegin(); it != sizes.constEnd(); it++) {
+ str_sizes.append(QString::number(*it));
+ if (current == -1 && m_selectedSize == *it) {
+ current = idx;
+ }
+ ++idx;
+ }
+
+ auto listView = sizeListView();
+
+ // only select the first element in the model when this function is first called and the new model isn't empty
+ listView->setModel(str_sizes);
+
+ if (current != -1)
+ listView->setCurrentIndex(current);
+
+ sizeEdit()->setText(!m_smoothlyScalable && listView->currentIndex() > 0
+ ? str_sizes.at(listView->currentIndex())
+ : QString::number(m_selectedSize));
+ } else {
+ qCWarning(lcAttachedProperty) << "Warning! selectedFamily is empty";
+ sizeEdit()->clear();
+ }
+
+ _q_updateSample();
+}
+
+void QQuickFontDialogImplAttached::_q_updateSample()
+{
+ if (m_selectedFamily.isEmpty())
+ return;
+
+ const int pSize = sizeEdit()->text().toInt();
+
+ QFont newFont = QFontDatabase::font(m_selectedFamily, m_selectedStyle, pSize);
+
+ newFont.setUnderline(underlineCheckBox()->isChecked());
+ newFont.setStrikeOut(strikeoutCheckBox()->isChecked());
+
+ sampleEdit()->setFont(newFont);
+}
+
+void QQuickFontDialogImplAttached::_q_writingSystemChanged(int index)
+{
+ m_writingSystem = QFontDatabase::WritingSystem(index);
+ sampleEdit()->setText(QFontDatabase::writingSystemSample(m_writingSystem));
+
+ updateFamilies();
+}
+
+void QQuickFontDialogImplAttached::searchListView(const QString &s, QQuickListView *listView)
+{
+ const QStringList model = listView->model().toStringList();
+
+ bool redo = false;
+
+ do {
+ m_search.append(s);
+
+ for (int i = 0; i < model.count(); ++i) {
+ if (model.at(i).startsWith(m_search, Qt::CaseInsensitive)) {
+ listView->setCurrentIndex(i);
+ return;
+ }
+ }
+
+ clearSearch();
+
+ redo = !redo;
+ } while (redo);
+}
+
+void QQuickFontDialogImplAttached::clearSearch()
+{
+ m_search.clear();
+}
+
+void QQuickFontDialogImplAttached::_q_familyChanged()
+{
+ if (m_ignoreFamilyUpdate)
+ return;
+
+ const int index = familyListView()->currentIndex();
+
+ if (index < 0) {
+ familyEdit()->clear();
+ } else {
+ m_selectedFamily = familyListView()->model().toStringList().at(index);
+ familyEdit()->setText(m_selectedFamily);
+ }
+
+ updateStyles();
+}
+
+void QQuickFontDialogImplAttached::_q_styleChanged()
+{
+ if (m_ignoreStyleUpdate)
+ return;
+
+ const int index = styleListView()->currentIndex();
+
+ if (index < 0) {
+ qCWarning(lcAttachedProperty) << "currentIndex changed to -1";
+ return;
+ }
+
+ m_selectedStyle = styleListView()->model().toStringList().at(index);
+ styleEdit()->setText(m_selectedStyle);
+ m_smoothlyScalable = QFontDatabase::isSmoothlyScalable(m_selectedFamily, m_selectedStyle);
+
+ updateSizes();
+}
+
+void QQuickFontDialogImplAttached::_q_sizeEdited()
+{
+ const int size = qAbs(sizeEdit()->text().toInt());
+
+ if (size == m_selectedSize)
+ return;
+
+ m_selectedSize = size;
+
+ if (sizeListView()->count()) {
+ auto model = sizeListView()->model().toStringList();
+
+ int i;
+ for (i = 0; i < model.count() - 1; ++i) {
+ if (model.at(i).toInt() >= size)
+ break;
+ }
+
+ QSignalBlocker blocker(sizeListView());
+ if (model.at(i).toInt() == size)
+ sizeListView()->setCurrentIndex(i);
+ else
+ sizeListView()->setCurrentIndex(-1);
+ }
+
+ _q_updateSample();
+}
+
+void QQuickFontDialogImplAttached::_q_sizeChanged()
+{
+ const int index = sizeListView()->currentIndex();
+
+ if (index < 0) {
+ qCWarning(lcAttachedProperty) << "currentIndex changed to -1";
+ return;
+ }
+
+ const QString s = sizeListView()->model().toStringList().at(index);
+ m_selectedSize = s.toInt();
+
+ sizeEdit()->setText(s);
+
+ _q_updateSample();
+}
+
+void QQuickFontDialogImplAttachedPrivate::currentFontChanged(const QFont &font)
+{
+ auto fontDialogImpl = qobject_cast<QQuickFontDialogImpl *>(parent);
+
+ if (!fontDialogImpl) {
+ return;
+ }
+
+ fontDialogImpl->setCurrentFont(font);
+
+ if (fontDialogImpl->options()->testOption(QFontDialogOptions::NoButtons))
+ emit fontDialogImpl->fontSelected(font);
+}
+
+void QQuickFontDialogImplAttached::selectFontInListViews(const QFont &font)
+{
+ {
+ QSignalBlocker blocker(sampleEdit());
+ familyListView()->setCurrentIndex(findFamilyInModel(font.families().constFirst(), familyListView()->model().toStringList()));
+ styleListView()->setCurrentIndex(findStyleInModel(QFontDatabase::styleString(font), styleListView()->model().toStringList()));
+ sizeEdit()->setText(QString::number(font.pointSize()));
+
+ underlineCheckBox()->setChecked(font.underline());
+ strikeoutCheckBox()->setChecked(font.strikeOut());
+ }
+
+ _q_updateSample();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfontdialogimpl_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p.h
new file mode 100644
index 0000000000..899f1d4b04
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFONTDIALOGIMPL_P_H
+#define QQUICKFONTDIALOGIMPL_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/qfontdatabase.h>
+#include <QtQuick/private/qquicklistview_p.h>
+#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquickcheckbox_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDialogButtonBox;
+
+class QQuickFontDialogImplAttached;
+class QQuickFontDialogImplAttachedPrivate;
+class QQuickFontDialogImplPrivate;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFontDialogImpl : public QQuickDialog
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont currentFont READ currentFont WRITE setCurrentFont NOTIFY currentFontChanged FINAL)
+ QML_NAMED_ELEMENT(FontDialogImpl)
+ QML_ATTACHED(QQuickFontDialogImplAttached)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ explicit QQuickFontDialogImpl(QObject *parent = nullptr);
+
+ static QQuickFontDialogImplAttached *qmlAttachedProperties(QObject *object);
+
+ QSharedPointer<QFontDialogOptions> options() const;
+ void setOptions(const QSharedPointer<QFontDialogOptions> &options);
+
+ QFont currentFont() const;
+ void setCurrentFont(const QFont &font, bool selectInListViews = false);
+
+ void init();
+
+Q_SIGNALS:
+ void optionsChanged();
+ void currentFontChanged(const QFont &font);
+ void fontSelected(const QFont &font);
+
+private:
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+
+ Q_DISABLE_COPY(QQuickFontDialogImpl)
+ Q_DECLARE_PRIVATE(QQuickFontDialogImpl)
+};
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickFontDialogImplAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickListView *familyListView READ familyListView WRITE setFamilyListView
+ NOTIFY familyListViewChanged)
+ Q_PROPERTY(QQuickListView *styleListView READ styleListView WRITE setStyleListView
+ NOTIFY styleListViewChanged)
+ Q_PROPERTY(QQuickListView *sizeListView READ sizeListView WRITE setSizeListView
+ NOTIFY sizeListViewChanged)
+ Q_PROPERTY(QQuickTextEdit *sampleEdit READ sampleEdit WRITE setSampleEdit
+ NOTIFY sampleEditChanged)
+ Q_PROPERTY(QQuickDialogButtonBox *buttonBox READ buttonBox WRITE setButtonBox
+ NOTIFY buttonBoxChanged)
+ Q_PROPERTY(QQuickComboBox *writingSystemComboBox READ writingSystemComboBox
+ WRITE setWritingSystemComboBox NOTIFY writingSystemComboBoxChanged)
+ Q_PROPERTY(QQuickCheckBox *underlineCheckBox READ underlineCheckBox WRITE setUnderlineCheckBox
+ NOTIFY underlineCheckBoxChanged)
+ Q_PROPERTY(QQuickCheckBox *strikeoutCheckBox READ strikeoutCheckBox WRITE setStrikeoutCheckBox
+ NOTIFY strikeoutCheckBoxChanged)
+
+ Q_PROPERTY(QQuickTextField *familyEdit READ familyEdit WRITE setFamilyEdit
+ NOTIFY familyEditChanged)
+ Q_PROPERTY(QQuickTextField *styleEdit READ styleEdit WRITE setStyleEdit NOTIFY styleEditChanged)
+ Q_PROPERTY(QQuickTextField *sizeEdit READ sizeEdit WRITE setSizeEdit NOTIFY sizeEditChanged)
+
+ Q_MOC_INCLUDE(<QtQuickTemplates2 / private / qquickdialogbuttonbox_p.h>)
+
+public:
+ explicit QQuickFontDialogImplAttached(QObject *parent = nullptr);
+
+ QQuickListView *familyListView() const;
+ void setFamilyListView(QQuickListView *familyListView);
+
+ QQuickListView *styleListView() const;
+ void setStyleListView(QQuickListView *styleListView);
+
+ QQuickListView *sizeListView() const;
+ void setSizeListView(QQuickListView *sizeListView);
+
+ QQuickTextEdit *sampleEdit() const;
+ void setSampleEdit(QQuickTextEdit *sampleEdit);
+
+ QQuickDialogButtonBox *buttonBox() const;
+ void setButtonBox(QQuickDialogButtonBox *buttonBox);
+
+ QQuickComboBox *writingSystemComboBox() const;
+ void setWritingSystemComboBox(QQuickComboBox *writingSystemComboBox);
+
+ QQuickCheckBox *underlineCheckBox() const;
+ void setUnderlineCheckBox(QQuickCheckBox *underlineCheckBox);
+
+ QQuickCheckBox *strikeoutCheckBox() const;
+ void setStrikeoutCheckBox(QQuickCheckBox *strikethroughCheckBox);
+
+ QQuickTextField *familyEdit() const;
+ void setFamilyEdit(QQuickTextField *familyEdit);
+
+ QQuickTextField *styleEdit() const;
+ void setStyleEdit(QQuickTextField *styleEdit);
+
+ QQuickTextField *sizeEdit() const;
+ void setSizeEdit(QQuickTextField *sizeEdit);
+
+Q_SIGNALS:
+ void buttonBoxChanged();
+ void familyListViewChanged();
+ void styleListViewChanged();
+ void sizeListViewChanged();
+ void sampleEditChanged();
+ void writingSystemComboBoxChanged();
+ void underlineCheckBoxChanged();
+ void strikeoutCheckBoxChanged();
+ void familyEditChanged();
+ void styleEditChanged();
+ void sizeEditChanged();
+
+public:
+ void searchFamily(const QString &s) { searchListView(s, familyListView()); }
+ void searchStyle(const QString &s) { searchListView(s, styleListView()); }
+ void clearSearch();
+
+ void updateFamilies();
+ void selectFontInListViews(const QFont &font);
+
+private:
+ void updateStyles();
+ void updateSizes();
+
+ void _q_familyChanged();
+ void _q_styleChanged();
+ void _q_sizeEdited();
+ void _q_sizeChanged();
+ void _q_updateSample();
+
+ void _q_writingSystemChanged(int index);
+
+ void searchListView(const QString &s, QQuickListView *listView);
+
+ QFontDatabase::WritingSystem m_writingSystem;
+ QString m_selectedFamily;
+ QString m_selectedStyle;
+ QString m_search;
+ int m_selectedSize;
+ bool m_smoothlyScalable;
+ bool m_ignoreFamilyUpdate;
+ bool m_ignoreStyleUpdate;
+
+ Q_DISABLE_COPY(QQuickFontDialogImplAttached)
+ Q_DECLARE_PRIVATE(QQuickFontDialogImplAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFontDialogImpl)
+
+#endif // QQUICKFONTDIALOGIMPL_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p_p.h
new file mode 100644
index 0000000000..8de3480dd9
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickfontdialogimpl_p_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFONTDIALOGIMPL_P_P_H
+#define QQUICKFONTDIALOGIMPL_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 <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+
+#include "qquickfontdialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFontDialogImplPrivate : public QQuickDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFontDialogImpl)
+public:
+ QQuickFontDialogImplPrivate();
+
+ static QQuickFontDialogImplPrivate *get(QQuickFontDialogImpl *dialog)
+ {
+ return dialog->d_func();
+ }
+
+ QQuickFontDialogImplAttached *attachedOrWarn();
+
+ void updateEnabled();
+
+ void handleAccept() override;
+ void handleClick(QQuickAbstractButton *button) override;
+
+ QSharedPointer<QFontDialogOptions> options;
+
+ QFont currentFont;
+};
+
+class QQuickFontDialogImplAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickFontDialogImplAttached)
+
+ void currentFontChanged(const QFont &font);
+
+public:
+ QPointer<QQuickDialogButtonBox> buttonBox;
+ QPointer<QQuickListView> familyListView;
+ QPointer<QQuickListView> styleListView;
+ QPointer<QQuickListView> sizeListView;
+ QPointer<QQuickTextEdit> sampleEdit;
+ QPointer<QQuickComboBox> writingSystemComboBox;
+ QPointer<QQuickCheckBox> underlineCheckBox;
+ QPointer<QQuickCheckBox> strikeoutCheckBox;
+ QPointer<QQuickTextField> familyEdit;
+ QPointer<QQuickTextField> styleEdit;
+ QPointer<QQuickTextField> sizeEdit;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFONTDIALOGIMPL_P_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog.cpp
new file mode 100644
index 0000000000..a2d0f8f41c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickplatformfiledialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qwindow.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquickpopupanchors_p.h>
+
+#include "qquickfiledialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQuickPlatformFileDialog, "qt.quick.dialogs.quickplatformfiledialog")
+
+/*!
+ \class QQuickPlatformFileDialog
+ \internal
+
+ An interface that QQuickFileDialog can use to access the non-native Qt Quick FileDialog.
+
+ Both this and the native implementations are created in QQuickAbstractDialog::create().
+*/
+QQuickPlatformFileDialog::QQuickPlatformFileDialog(QObject *parent)
+{
+ qCDebug(lcQuickPlatformFileDialog) << "creating non-native Qt Quick FileDialog with parent" << parent;
+
+ // Set a parent so that we get deleted if we can't be shown for whatever reason.
+ // Our eventual parent should be the window, though.
+ setParent(parent);
+
+ auto qmlContext = ::qmlContext(parent);
+ if (!qmlContext) {
+ qmlWarning(parent) << "No QQmlContext for QQuickPlatformFileDialog; can't create non-native FileDialog implementation";
+ return;
+ }
+
+ const auto dialogQmlUrl = QUrl(QStringLiteral("qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/qml/FileDialog.qml"));
+ QQmlComponent fileDialogComponent(qmlContext->engine(), dialogQmlUrl, parent);
+ if (!fileDialogComponent.isReady()) {
+ qmlWarning(parent) << "Failed to load non-native FileDialog implementation:\n" << fileDialogComponent.errorString();
+ return;
+ }
+ m_dialog = qobject_cast<QQuickFileDialogImpl*>(fileDialogComponent.create());
+ if (!m_dialog) {
+ qmlWarning(parent) << "Failed to create an instance of the non-native FileDialog:\n" << fileDialogComponent.errorString();
+ return;
+ }
+ // Give it a parent until it's parented to the window in show().
+ m_dialog->setParent(this);
+
+ connect(m_dialog, &QQuickDialog::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog, &QQuickDialog::rejected, this, &QPlatformDialogHelper::reject);
+
+ connect(m_dialog, &QQuickFileDialogImpl::fileSelected, this, &QQuickPlatformFileDialog::fileSelected);
+ // TODO: add support for multiple file selection (QTBUG-92585)
+// connect(m_dialog, &QQuickFileDialogImpl::filesSelected, [this](const QList<QString> &files) {
+// QList<QUrl> urls;
+// urls.reserve(files.count());
+// for (const QString &file : files)
+// urls += QUrl::fromLocalFile(file);
+// emit filesSelected(urls);
+// });
+ connect(m_dialog, &QQuickFileDialogImpl::currentFileChanged, this, &QQuickPlatformFileDialog::currentChanged);
+ connect(m_dialog, &QQuickFileDialogImpl::currentFolderChanged, this, &QQuickPlatformFileDialog::directoryEntered);
+ connect(m_dialog, &QQuickFileDialogImpl::filterSelected, this, &QQuickPlatformFileDialog::filterSelected);
+
+ // We would do this in QQuickFileDialogImpl, but we need to ensure that folderChanged()
+ // is connected to directoryEntered() before setting it to ensure that the QQuickFileDialog is notified.
+ if (m_dialog->currentFolder().isEmpty())
+ m_dialog->setCurrentFolder(QUrl::fromLocalFile(QDir().absolutePath()));
+}
+
+bool QQuickPlatformFileDialog::isValid() const
+{
+ return m_dialog;
+}
+
+bool QQuickPlatformFileDialog::defaultNameFilterDisables() const
+{
+ return false;
+}
+
+void QQuickPlatformFileDialog::setDirectory(const QUrl &directory)
+{
+ if (!m_dialog)
+ return;
+
+ m_dialog->setCurrentFolder(directory);
+}
+
+QUrl QQuickPlatformFileDialog::directory() const
+{
+ if (!m_dialog)
+ return {};
+
+ return m_dialog->currentFolder();
+}
+
+void QQuickPlatformFileDialog::selectFile(const QUrl &file)
+{
+ if (!m_dialog)
+ return;
+
+ m_dialog->setSelectedFile(file);
+}
+
+QList<QUrl> QQuickPlatformFileDialog::selectedFiles() const
+{
+ // TODO: support for multiple selected files
+ return { m_dialog->currentFile() };
+}
+
+void QQuickPlatformFileDialog::setFilter()
+{
+}
+
+void QQuickPlatformFileDialog::selectNameFilter(const QString &filter)
+{
+ // There is a bit of a problem with order here - QQuickFileDialog::onShow()
+ // is called before our show(), but it needs to set the selected filter
+ // (which we can't do in our show() because we don't know about QQuickFileDialog).
+ // So, delay setting the filter until we're shown. This shouldn't be an issue
+ // in practice, since it doesn't make sense for the filter to programmatically
+ // change while the dialog is visible.
+ m_pendingNameFilter = filter;
+}
+
+QString QQuickPlatformFileDialog::selectedNameFilter() const
+{
+ return m_dialog->selectedNameFilter()->name();
+}
+
+void QQuickPlatformFileDialog::exec()
+{
+ qCWarning(lcQuickPlatformFileDialog) << "exec() is not supported for the Qt Quick FileDialog fallback";
+}
+
+bool QQuickPlatformFileDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ qCDebug(lcQuickPlatformFileDialog) << "show called with flags" << flags <<
+ "modality" << modality << "parent" << parent;
+ if (!m_dialog)
+ return false;
+
+ if (!parent)
+ return false;
+
+ auto quickWindow = qobject_cast<QQuickWindow*>(parent);
+ if (!quickWindow) {
+ qmlInfo(this->parent()) << "Parent window (" << parent << ") of non-native dialog is not a QQuickWindow";
+ return false;
+ }
+ m_dialog->setParent(parent);
+ m_dialog->resetParentItem();
+
+ auto popupPrivate = QQuickPopupPrivate::get(m_dialog);
+ popupPrivate->getAnchors()->setCenterIn(m_dialog->parentItem());
+
+ QSharedPointer<QFileDialogOptions> options = QPlatformFileDialogHelper::options();
+ m_dialog->setTitle(options->windowTitle());
+ m_dialog->setOptions(options);
+ m_dialog->selectNameFilter(m_pendingNameFilter);
+ m_pendingNameFilter.clear();
+ m_dialog->setAcceptLabel(options->isLabelExplicitlySet(QFileDialogOptions::Accept)
+ ? options->labelText(QFileDialogOptions::Accept) : QString());
+ m_dialog->setRejectLabel(options->isLabelExplicitlySet(QFileDialogOptions::Reject)
+ ? options->labelText(QFileDialogOptions::Reject) : QString());
+
+ m_dialog->open();
+ return true;
+}
+
+void QQuickPlatformFileDialog::hide()
+{
+ if (!m_dialog)
+ return;
+
+ m_dialog->close();
+}
+
+QQuickFileDialogImpl *QQuickPlatformFileDialog::dialog() const
+{
+ return m_dialog;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickplatformfiledialog_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog_p.h
new file mode 100644
index 0000000000..883b7ed9b7
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfiledialog_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPLATFORMFILEDIALOG_P_H
+#define QQUICKPLATFORMFILEDIALOG_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/qpa/qplatformdialoghelper.h>
+
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFileDialogImpl;
+class QWindow;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickPlatformFileDialog : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickPlatformFileDialog(QObject *parent);
+ ~QQuickPlatformFileDialog() = default;
+
+ bool isValid() const;
+ bool defaultNameFilterDisables() const override;
+ void setDirectory(const QUrl &directory) override;
+ QUrl directory() const override;
+ void selectFile(const QUrl &file) override;
+ QList<QUrl> selectedFiles() const override;
+ void setFilter() override;
+ void selectNameFilter(const QString &filter) override;
+ QString selectedNameFilter() const override;
+
+ void exec() override;
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) override;
+ void hide() override;
+
+ QQuickFileDialogImpl *dialog() const;
+
+private:
+ QQuickFileDialogImpl *m_dialog = nullptr;
+ QString m_pendingNameFilter;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPLATFORMFILEDIALOG_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog.cpp b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog.cpp
new file mode 100644
index 0000000000..0512ac1581
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog.cpp
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickplatformfontdialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qwindow.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquickpopupanchors_p.h>
+
+#include "qquickfontdialogimpl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcQuickPlatformFontDialog, "qt.quick.dialogs.quickplatformfontdialog")
+
+/*!
+ \class QQuickPlatformFontDialog
+ \internal
+
+ An interface that QQuickFontDialog can use to access the non-native Qt Quick FontDialog.
+
+ Both this and the native implementations are created in QQuickAbstractDialog::create().
+
+*/
+QQuickPlatformFontDialog::QQuickPlatformFontDialog(QObject *parent)
+{
+ qCDebug(lcQuickPlatformFontDialog)
+ << "creating non-native Qt Quick FontDialog with parent" << parent;
+
+ // Set a parent so that we get deleted if we can't be shown for whatever reason.
+ // Our eventual parent should be the window, though.
+ setParent(parent);
+
+ auto qmlContext = ::qmlContext(parent);
+ if (!qmlContext) {
+ qmlWarning(parent) << "No QQmlContext for QQuickPlatformFontDialog; can't create "
+ "non-native FontDialog implementation";
+ return;
+ }
+
+ const auto dialogQmlUrl = QUrl(QStringLiteral(
+ "qrc:/qt-project.org/imports/QtQuick/Dialogs/quickimpl/qml/FontDialog.qml"));
+
+ QQmlComponent fontDialogComponent(qmlContext->engine(), dialogQmlUrl, parent);
+ if (!fontDialogComponent.isReady()) {
+ qmlWarning(parent) << "Failed to load non-native FontDialog implementation:\n"
+ << fontDialogComponent.errorString();
+ return;
+ }
+
+ m_dialog = qobject_cast<QQuickFontDialogImpl *>(fontDialogComponent.create());
+
+ if (!m_dialog) {
+ qmlWarning(parent) << "Failed to create an instance of the non-native FontDialog:\n"
+ << fontDialogComponent.errorString();
+ return;
+ }
+
+ m_dialog->setParent(this);
+
+ connect(m_dialog, &QQuickDialog::accepted, this, &QPlatformDialogHelper::accept);
+ connect(m_dialog, &QQuickDialog::rejected, this, &QPlatformDialogHelper::reject);
+
+ connect(m_dialog, &QQuickFontDialogImpl::currentFontChanged,
+ this, &QQuickPlatformFontDialog::currentFontChanged);
+ connect(m_dialog, &QQuickFontDialogImpl::fontSelected, this, &QQuickPlatformFontDialog::fontSelected);
+}
+
+bool QQuickPlatformFontDialog::isValid() const
+{
+ return m_dialog;
+}
+
+void QQuickPlatformFontDialog::setCurrentFont(const QFont &font)
+{
+ if (m_dialog)
+ m_dialog->setCurrentFont(font, true);
+}
+
+QFont QQuickPlatformFontDialog::currentFont() const
+{
+ return m_dialog ? m_dialog->currentFont() : QFont();
+}
+
+void QQuickPlatformFontDialog::exec()
+{
+ qCWarning(lcQuickPlatformFontDialog)
+ << "exec() is not supported for the Qt Quick FontDialog fallback";
+}
+
+bool QQuickPlatformFontDialog::show(Qt::WindowFlags flags, Qt::WindowModality modality,
+ QWindow *parent)
+{
+ qCDebug(lcQuickPlatformFontDialog)
+ << "show called with flags" << flags << "modality" << modality << "parent" << parent;
+
+ if (!isValid())
+ return false;
+
+ if (!parent)
+ return false;
+
+ auto quickWindow = qobject_cast<QQuickWindow *>(parent);
+ if (!quickWindow) {
+ qmlInfo(this->parent()) << "Parent window (" << parent
+ << ") of non-native dialog is not a QQuickWindow";
+ return false;
+ }
+ m_dialog->setParent(parent);
+ m_dialog->resetParentItem();
+
+ auto popupPrivate = QQuickPopupPrivate::get(m_dialog);
+ popupPrivate->getAnchors()->setCenterIn(m_dialog->parentItem());
+
+ QSharedPointer<QFontDialogOptions> options = QPlatformFontDialogHelper::options();
+ m_dialog->setTitle(options->windowTitle());
+ m_dialog->setOptions(options);
+
+ m_dialog->init();
+
+ m_dialog->open();
+ return true;
+}
+
+void QQuickPlatformFontDialog::hide()
+{
+ if (isValid())
+ m_dialog->close();
+}
+
+QQuickFontDialogImpl *QQuickPlatformFontDialog::dialog() const
+{
+ return m_dialog;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickplatformfontdialog_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog_p.h
new file mode 100644
index 0000000000..a5009facab
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qquickplatformfontdialog_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPLATFORMFONTDIALOG_P_H
+#define QQUICKPLATFORMFONTDIALOG_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/qpa/qplatformdialoghelper.h>
+
+#include "qtquickdialogs2quickimplglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFontDialogImpl;
+class QWindow;
+
+class Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT QQuickPlatformFontDialog
+ : public QPlatformFontDialogHelper
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickPlatformFontDialog(QObject *parent);
+ ~QQuickPlatformFontDialog() = default;
+
+ bool isValid() const;
+
+ virtual void setCurrentFont(const QFont &font) override;
+ virtual QFont currentFont() const override;
+
+ void exec() override;
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent) override;
+ void hide() override;
+
+ QQuickFontDialogImpl *dialog() const;
+
+private:
+ QQuickFontDialogImpl *m_dialog = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPLATFORMFONTDIALOG_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplforeign_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplforeign_p.h
new file mode 100644
index 0000000000..b1740606e3
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplforeign_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKDIALOGS2QUICKIMPLFOREIGN_P_H
+#define QTQUICKDIALOGS2QUICKIMPLFOREIGN_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 <QtQuickDialogs2Utils/private/qquickfilenamefilter_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+
+QT_BEGIN_NAMESPACE
+
+struct QQuickFileNameFilterQuickDialogs2QuickImplForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickFileNameFilter)
+ QML_ADDED_IN_VERSION(6, 2)
+};
+
+// TODO: remove these ones when not needed (QTBUG-88179)
+
+// verticalPadding, etc.
+struct QQuickControlForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickControl)
+ QML_ADDED_IN_VERSION(2, 0)
+};
+
+struct QQuickAbstractButtonForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickAbstractButton)
+ QML_ADDED_IN_VERSION(2, 0)
+};
+
+struct QQuickIconForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickIcon)
+ QML_ADDED_IN_VERSION(6, 2)
+};
+
+// For leftInset, etc.
+struct QQuickPopupForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickPopup)
+ QML_ADDED_IN_VERSION(2, 0)
+};
+
+struct QQuickDialogForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickDialog)
+ QML_ADDED_IN_VERSION(2, 1)
+};
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKDIALOGS2QUICKIMPLFOREIGN_P_H
diff --git a/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplglobal_p.h b/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplglobal_p.h
new file mode 100644
index 0000000000..38b5a01bea
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2quickimpl/qtquickdialogs2quickimplglobal_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKDIALOGS2QUICKIMPLGLOBAL_P_H
+#define QTQUICKDIALOGS2QUICKIMPLGLOBAL_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>
+#include <QtQml/private/qqmlglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKDIALOGS2QUICKIMPL_LIB)
+# define Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKDIALOGS2QUICKIMPL_PRIVATE_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKDIALOGS2QUICKIMPLGLOBAL_P_H
diff --git a/src/quickdialogs2/quickdialogs2utils/CMakeLists.txt b/src/quickdialogs2/quickdialogs2utils/CMakeLists.txt
new file mode 100644
index 0000000000..0242ffcf6c
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2utils/CMakeLists.txt
@@ -0,0 +1,23 @@
+# This library exists because QuickDialogs2 and QuickDialogs2QuickImpl
+# both need QQuickNameFilter. QQuickNameFilter was originally in
+# QuickDialogs2. Since QuickDialogs2 already links to
+# QuickDialogs2QuickImpl, making the latter link to the former (to get
+# access to QQuickNameFilter) would result in a circular dependency,
+# so we have this library as a result.
+
+qt_internal_add_module(QuickDialogs2Utils
+ SOURCES
+ qquickfilenamefilter.cpp
+ qquickfilenamefilter_p.h
+ qtquickdialogs2utilsglobal_p.h
+ DEFINES
+ QT_BUILD_QUICKDIALOGS2UTILS_LIB
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ LIBRARIES
+ Qt::GuiPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+)
diff --git a/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter.cpp b/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter.cpp
new file mode 100644
index 0000000000..0d99d33789
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickfilenamefilter_p.h"
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcFileNameFilter, "qt.quick.dialogs.qquickfilenamefilter")
+
+QQuickFileNameFilter::QQuickFileNameFilter(QObject *parent)
+ : QObject(parent), m_index(-1)
+{
+}
+
+int QQuickFileNameFilter::index() const
+{
+ return m_index;
+}
+
+void QQuickFileNameFilter::setIndex(int index)
+{
+ if (m_index == index)
+ return;
+
+ m_index = index;
+ emit indexChanged(index);
+}
+
+QString QQuickFileNameFilter::name() const
+{
+ return m_name;
+}
+
+QStringList QQuickFileNameFilter::extensions() const
+{
+ return m_extensions;
+}
+
+QStringList QQuickFileNameFilter::globs() const
+{
+ return m_globs;
+}
+
+QSharedPointer<QFileDialogOptions> QQuickFileNameFilter::options() const
+{
+ return m_options;
+}
+
+void QQuickFileNameFilter::setOptions(const QSharedPointer<QFileDialogOptions> &options)
+{
+ m_options = options;
+}
+
+static QString extractName(const QString &filter)
+{
+ return filter.left(filter.indexOf(QLatin1Char('(')) - 1);
+}
+
+static QString extractExtension(QStringView filter)
+{
+ return filter.mid(filter.indexOf(QLatin1Char('.')) + 1).toString();
+}
+
+static void extractExtensionsAndGlobs(QStringView filter, QStringList &extensions, QStringList &globs)
+{
+ extensions.clear();
+ globs.clear();
+
+ const int from = filter.indexOf(QLatin1Char('('));
+ const int to = filter.lastIndexOf(QLatin1Char(')')) - 1;
+ if (from >= 0 && from < to) {
+ const QStringView ref = filter.mid(from + 1, to - from);
+ const QList<QStringView> exts = ref.split(QLatin1Char(' '), Qt::SkipEmptyParts);
+ // For example, given the filter "HTML files (*.html *.htm)",
+ // "ref" would be "*.html" and "*.htm".
+ for (const QStringView &ref : exts) {
+ extensions += extractExtension(ref);
+ globs += ref.toString();
+ }
+ }
+}
+
+void QQuickFileNameFilter::update(const QString &filter)
+{
+ const QStringList filters = nameFilters();
+
+ const int oldIndex = m_index;
+ const QString oldName = m_name;
+ const QStringList oldExtensions = m_extensions;
+ const QStringList oldGlobs = m_globs;
+
+ m_index = filters.indexOf(filter);
+ m_name = extractName(filter);
+ extractExtensionsAndGlobs(filter, m_extensions, m_globs);
+
+ if (oldIndex != m_index)
+ emit indexChanged(m_index);
+ if (oldName != m_name)
+ emit nameChanged(m_name);
+ if (oldExtensions != m_extensions)
+ emit extensionsChanged(m_extensions);
+ if (oldGlobs != m_globs)
+ emit globsChanged(m_globs);
+
+ qCDebug(lcFileNameFilter).nospace() << "update called on " << this << " of " << parent()
+ << " with filter " << filter << " (current filters are " << filters << "):"
+ << "\n old index=" << oldIndex << "new index=" << m_index
+ << "\n old name=" << oldName << "new name=" << m_name
+ << "\n old extensions=" << oldExtensions << "new extensions=" << m_extensions
+ << "\n old glob=s" << oldGlobs << "new globs=" << m_globs;
+}
+
+QStringList QQuickFileNameFilter::nameFilters() const
+{
+ return m_options ? m_options->nameFilters() : QStringList();
+}
+
+QString QQuickFileNameFilter::nameFilter(int index) const
+{
+ return m_options ? m_options->nameFilters().value(index) : QString();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickfilenamefilter_p.cpp"
diff --git a/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter_p.h b/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter_p.h
new file mode 100644
index 0000000000..586da8698a
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2utils/qquickfilenamefilter_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFILENAMEFILTER_P_H
+#define QQUICKFILENAMEFILTER_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/qsharedpointer.h>
+#include <QtCore/qstringlist.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+#include "qtquickdialogs2utilsglobal_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKDIALOGS2UTILS_PRIVATE_EXPORT QQuickFileNameFilter : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged FINAL)
+ Q_PROPERTY(QString name READ name NOTIFY nameChanged FINAL)
+ Q_PROPERTY(QStringList extensions READ extensions NOTIFY extensionsChanged FINAL)
+ Q_PROPERTY(QStringList globs READ globs NOTIFY globsChanged FINAL)
+
+public:
+ explicit QQuickFileNameFilter(QObject *parent = nullptr);
+
+ int index() const;
+ void setIndex(int index);
+
+ QString name() const;
+ QStringList extensions() const;
+ QStringList globs() const;
+
+ QSharedPointer<QFileDialogOptions> options() const;
+ void setOptions(const QSharedPointer<QFileDialogOptions> &options);
+
+ void update(const QString &filter);
+
+Q_SIGNALS:
+ void indexChanged(int index);
+ void nameChanged(const QString &name);
+ void extensionsChanged(const QStringList &extensions);
+ void globsChanged(const QStringList &globs);
+
+private:
+ QStringList nameFilters() const;
+ QString nameFilter(int index) const;
+
+ int m_index;
+ QString m_name;
+ QStringList m_extensions;
+ QStringList m_globs;
+ QSharedPointer<QFileDialogOptions> m_options;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFILENAMEFILTER_P_H
diff --git a/src/quickdialogs2/quickdialogs2utils/qtquickdialogs2utilsglobal_p.h b/src/quickdialogs2/quickdialogs2utils/qtquickdialogs2utilsglobal_p.h
new file mode 100644
index 0000000000..52f7a39784
--- /dev/null
+++ b/src/quickdialogs2/quickdialogs2utils/qtquickdialogs2utilsglobal_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Dialogs module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKDIALOGS2UTILSGLOBAL_P_H
+#define QTQUICKDIALOGS2UTILSGLOBAL_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
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKDIALOGS2UTILS_LIB)
+# define Q_QUICKDIALOGS2UTILS_PRIVATE_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKDIALOGS2UTILS_PRIVATE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKDIALOGS2UTILS_PRIVATE_EXPORT
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QTQUICKDIALOGS2UTILSUTILSGLOBAL_P_H
diff --git a/src/quicklayouts/qquickgridlayoutengine.cpp b/src/quicklayouts/qquickgridlayoutengine.cpp
index 5275d70c39..234c3a0d9b 100644
--- a/src/quicklayouts/qquickgridlayoutengine.cpp
+++ b/src/quicklayouts/qquickgridlayoutengine.cpp
@@ -51,11 +51,4 @@ void QQuickGridLayoutEngine::setAlignment(QQuickItem *quickItem, Qt::Alignment a
}
}
-Qt::Alignment QQuickGridLayoutEngine::alignment(QQuickItem *quickItem) const
-{
- if (QGridLayoutItem *item = findLayoutItem(quickItem))
- return item->alignment();
- return {};
-}
-
QT_END_NAMESPACE
diff --git a/src/quicklayouts/qquickgridlayoutengine_p.h b/src/quicklayouts/qquickgridlayoutengine_p.h
index ff42fa4d43..8b1a000e42 100644
--- a/src/quicklayouts/qquickgridlayoutengine_p.h
+++ b/src/quicklayouts/qquickgridlayoutengine_p.h
@@ -154,7 +154,6 @@ public:
}
void setAlignment(QQuickItem *quickItem, Qt::Alignment alignment);
- Qt::Alignment alignment(QQuickItem *quickItem) const;
};
diff --git a/src/quicklayouts/qquicklayout.cpp b/src/quicklayouts/qquicklayout.cpp
index d4841e770f..80fea6923a 100644
--- a/src/quicklayouts/qquicklayout.cpp
+++ b/src/quicklayouts/qquicklayout.cpp
@@ -73,7 +73,11 @@
The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If they are \c
false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink
- between its minimum and maximum size as the layout is resized.
+ between its minimum and maximum size as the layout is resized. If there are multiple items
+ with \l fillWidth (or \l fillHeight) set to \c true, the layout will grow or shrink the items
+ relative to the ratio of their preferred size.
+
+ For more details on the layout algorithm, see also the \l {Qt Quick Layouts Overview}.
\note Do not bind to the x, y, width, or height properties of items in a layout,
as this would conflict with the goals of Layout, and can also cause binding loops.
@@ -786,6 +790,18 @@ void QQuickLayout::componentComplete()
d->m_isReady = true;
}
+void QQuickLayout::maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item)
+{
+ QQuickLayoutAttached *info = attachedLayoutObject(item, false);
+ if (info) {
+ if (info->alignment() == Qt::AlignBaseline && static_cast<QQuickLayout*>(item->parentItem()) == this) {
+ qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ } else {
+ qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ }
+ }
+}
+
void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
{
Q_D(QQuickLayout);
@@ -809,7 +825,7 @@ void QQuickLayout::invalidate(QQuickItem * /*childItem*/)
qCDebug(lcQuickLayouts) << "QQuickLayout::invalidate(), polish()";
polish();
} else {
- qWarning() << "Qt Quick Layouts: Polish loop detected. Aborting after two iterations.";
+ qmlWarning(this) << "Qt Quick Layouts: Polish loop detected. Aborting after two iterations.";
}
}
}
@@ -860,7 +876,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
if (change == ItemChildAddedChange) {
Q_D(QQuickLayout);
QQuickItem *item = value.item;
- qmlobject_connect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ maybeSubscribeToBaseLineOffsetChanges(item);
QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
d->m_hasItemChangeListeners = true;
qCDebug(lcQuickLayouts) << "ChildAdded" << item;
@@ -868,7 +884,7 @@ void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value)
invalidate();
} else if (change == ItemChildRemovedChange) {
QQuickItem *item = value.item;
- qmlobject_disconnect(item, QQuickItem, SIGNAL(baselineOffsetChanged(qreal)), this, QQuickLayout, SLOT(invalidateSenderItem()));
+ maybeSubscribeToBaseLineOffsetChanges(item);
QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
qCDebug(lcQuickLayouts) << "ChildRemoved" << item;
if (isReady())
@@ -1306,3 +1322,5 @@ void QQuickLayout::dumpLayoutTreeRecursive(int level, QString &buf) const
}
QT_END_NAMESPACE
+
+#include "moc_qquicklayout_p.cpp"
diff --git a/src/quicklayouts/qquicklayout_p.h b/src/quicklayouts/qquicklayout_p.h
index 0d577a113e..141fb3c8da 100644
--- a/src/quicklayouts/qquicklayout_p.h
+++ b/src/quicklayouts/qquicklayout_p.h
@@ -121,6 +121,8 @@ public:
void itemDestroyed(QQuickItem *item) override;
void itemVisibilityChanged(QQuickItem *item) override;
+ void maybeSubscribeToBaseLineOffsetChanges(QQuickItem *item);
+
Q_INVOKABLE void _q_dumpLayoutTree() const;
void dumpLayoutTreeRecursive(int level, QString &buf) const;
@@ -173,7 +175,6 @@ protected:
unsigned m_isReady : 1;
unsigned m_disableRearrange : 1;
unsigned m_hasItemChangeListeners : 1; // if false, we don't need to remove its item change listeners...
- mutable QSet<QQuickItem *> m_ignoredItems;
};
diff --git a/src/quicklayouts/qquicklinearlayout.cpp b/src/quicklayouts/qquicklinearlayout.cpp
index 2f97708b52..b4267704c6 100644
--- a/src/quicklayouts/qquicklinearlayout.cpp
+++ b/src/quicklayouts/qquicklinearlayout.cpp
@@ -53,6 +53,10 @@
\ingroup layouts
\brief Identical to \l GridLayout, but having only one row.
+ To be able to use this type more efficiently, it is recommended that you
+ understand the general mechanism of the Qt Quick Layouts module. Refer to
+ \l{Qt Quick Layouts Overview} for more information.
+
It is available as a convenience for developers, as it offers a cleaner API.
Items in a RowLayout support these attached properties:
@@ -96,7 +100,9 @@
Read more about attached properties \l{QML Object Attributes}{here}.
\sa ColumnLayout
\sa GridLayout
+ \sa StackLayout
\sa Row
+ \sa {Qt Quick Layouts Overview}
*/
/*!
@@ -107,6 +113,10 @@
\ingroup layouts
\brief Identical to \l GridLayout, but having only one column.
+ To be able to use this type more efficiently, it is recommended that you
+ understand the general mechanism of the Qt Quick Layouts module. Refer to
+ \l{Qt Quick Layouts Overview} for more information.
+
It is available as a convenience for developers, as it offers a cleaner API.
Items in a ColumnLayout support these attached properties:
@@ -148,7 +158,9 @@
\sa RowLayout
\sa GridLayout
+ \sa StackLayout
\sa Column
+ \sa {Qt Quick Layouts Overview}
*/
@@ -160,7 +172,9 @@
\ingroup layouts
\brief Provides a way of dynamically arranging items in a grid.
-
+ To be able to use this type more efficiently, it is recommended that you
+ understand the general mechanism of the Qt Quick Layouts module. Refer to
+ \l{Qt Quick Layouts Overview} for more information.
If the GridLayout is resized, all items in the layout will be rearranged. It is similar
to the widget-based QGridLayout. All visible children of the GridLayout element will belong to
@@ -212,7 +226,9 @@
\sa RowLayout
\sa ColumnLayout
+ \sa StackLayout
\sa Grid
+ \sa {Qt Quick Layouts Overview}
*/
@@ -302,6 +318,7 @@ void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignmen
{
Q_D(QQuickGridLayoutBase);
d->engine.setAlignment(item, alignment);
+ maybeSubscribeToBaseLineOffsetChanges(item);
}
QQuickGridLayoutBase::~QQuickGridLayoutBase()
diff --git a/src/quicklayouts/qquickstacklayout.cpp b/src/quicklayouts/qquickstacklayout.cpp
index 19d0033e8b..e49b18e5f2 100644
--- a/src/quicklayouts/qquickstacklayout.cpp
+++ b/src/quicklayouts/qquickstacklayout.cpp
@@ -52,6 +52,10 @@
\brief The StackLayout class provides a stack of items where
only one item is visible at a time.
+ To be able to use this type more efficiently, it is recommended that you
+ understand the general mechanism of the Qt Quick Layouts module. Refer to
+ \l{Qt Quick Layouts Overview} for more information.
+
The current visible item can be modified by setting the \l currentIndex property.
The index corresponds to the order of the StackLayout's children.
@@ -98,6 +102,7 @@
\sa GridLayout
\sa RowLayout
\sa {QtQuick.Controls::StackView}{StackView}
+ \sa {Qt Quick Layouts Overview}
*/
QT_BEGIN_NAMESPACE
@@ -200,6 +205,7 @@ void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickIt
stackLayoutAttached->setIndex(-1);
stackLayoutAttached->setIsCurrentItem(false);
}
+ m_cachedItemSizeHints.remove(item);
invalidate();
} else if (change == ItemChildAddedChange) {
invalidate();
@@ -221,10 +227,8 @@ QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const
maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity());
const int count = itemCount();
- m_cachedItemSizeHints.resize(count);
for (int i = 0; i < count; ++i) {
- SizeHints &hints = m_cachedItemSizeHints[i];
- QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array);
+ SizeHints &hints = cachedItemSizeHints(i);
minS = minS.expandedTo(hints.min());
prefS = prefS.expandedTo(hints.pref());
//maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items.
@@ -290,11 +294,12 @@ void QQuickStackLayout::setAlignment(QQuickItem * /*item*/, Qt::Alignment /*alig
void QQuickStackLayout::invalidate(QQuickItem *childItem)
{
- const int indexOfChild = indexOf(childItem);
- if (indexOfChild >= 0 && indexOfChild < m_cachedItemSizeHints.count()) {
- m_cachedItemSizeHints[indexOfChild].min() = QSizeF();
- m_cachedItemSizeHints[indexOfChild].pref() = QSizeF();
- m_cachedItemSizeHints[indexOfChild].max() = QSizeF();
+ ensureLayoutItemsUpdated();
+ if (childItem) {
+ SizeHints &hints = m_cachedItemSizeHints[childItem];
+ hints.min() = QSizeF();
+ hints.pref() = QSizeF();
+ hints.max() = QSizeF();
}
for (int i = 0; i < Qt::NSizeHints; ++i)
@@ -308,7 +313,6 @@ void QQuickStackLayout::invalidate(QQuickItem *childItem)
void QQuickStackLayout::updateLayoutItems()
{
Q_D(QQuickStackLayout);
- d->m_ignoredItems.clear();
const int count = itemCount();
int oldIndex = d->currentIndex;
if (!d->explicitCurrentIndex)
@@ -335,6 +339,17 @@ void QQuickStackLayout::updateLayoutItems()
}
}
+QQuickStackLayout::SizeHints &QQuickStackLayout::cachedItemSizeHints(int index) const
+{
+ QQuickItem *item = itemAt(index);
+ Q_ASSERT(item);
+ SizeHints &hints = m_cachedItemSizeHints[item]; // will create an entry if it doesn't exist
+ if (!hints.min().isValid())
+ QQuickStackLayout::collectItemSizeHints(item, hints.array);
+ return hints;
+}
+
+
void QQuickStackLayout::rearrange(const QSizeF &newSize)
{
Q_D(QQuickStackLayout);
@@ -346,7 +361,7 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize)
if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count())
return;
- QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex];
+ QQuickStackLayout::SizeHints &hints = cachedItemSizeHints(d->currentIndex);
QQuickItem *item = itemAt(d->currentIndex);
Q_ASSERT(item);
item->setPosition(QPointF(0,0)); // ### respect alignment?
@@ -379,10 +394,7 @@ void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints
bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const
{
- const bool ignored = QQuickItemPrivate::get(item)->isTransparentForPositioner();
- if (ignored)
- d_func()->m_ignoredItems << item;
- return ignored;
+ return QQuickItemPrivate::get(item)->isTransparentForPositioner();
}
QQuickStackLayoutAttached::QQuickStackLayoutAttached(QObject *object)
diff --git a/src/quicklayouts/qquickstacklayout_p.h b/src/quicklayouts/qquickstacklayout_p.h
index 07c2fc3727..a6ba38c20d 100644
--- a/src/quicklayouts/qquickstacklayout_p.h
+++ b/src/quicklayouts/qquickstacklayout_p.h
@@ -111,8 +111,9 @@ private:
QSizeF array[Qt::NSizeHints];
};
- mutable QVector<SizeHints> m_cachedItemSizeHints;
+ mutable QHash<QQuickItem*, SizeHints> m_cachedItemSizeHints;
mutable QSizeF m_cachedSizeHints[Qt::NSizeHints];
+ SizeHints &cachedItemSizeHints(int index) const;
};
class QQuickStackLayoutPrivate : public QQuickLayoutPrivate
diff --git a/src/quicknativestyle/CMakeLists.txt b/src/quicknativestyle/CMakeLists.txt
new file mode 100644
index 0000000000..befd7fed0b
--- /dev/null
+++ b/src/quicknativestyle/CMakeLists.txt
@@ -0,0 +1,100 @@
+#####################################################################
+## qtquickcontrols2nativestyleplugin Plugin:
+#####################################################################
+
+set(qml_files
+ "controls/DefaultButton.qml"
+ "controls/DefaultSlider.qml"
+ "controls/DefaultGroupBox.qml"
+ "controls/DefaultCheckBox.qml"
+ "controls/DefaultRadioButton.qml"
+ "controls/DefaultSpinBox.qml"
+ "controls/DefaultTextField.qml"
+ "controls/DefaultFrame.qml"
+ "controls/DefaultTextArea.qml"
+ "controls/DefaultComboBox.qml"
+ "controls/DefaultScrollBar.qml"
+ "controls/DefaultProgressBar.qml"
+ "controls/DefaultDial.qml"
+)
+
+if(MACOS)
+ list(APPEND qml_files "util/FocusFrame.qml")
+endif()
+
+qt_internal_add_qml_module(qtquickcontrols2nativestyleplugin
+ URI "QtQuick.NativeStyle"
+ VERSION "${PROJECT_VERSION}"
+ CLASSNAME QtQuickControls2NativeStylePlugin
+ DEPENDENCIES
+ QtQuick.Controls/auto
+ QtQuick.Layouts/auto
+ QtQuick/auto
+ PAST_MAJOR_VERSIONS 2
+ PLUGIN_TARGET qtquickcontrols2nativestyleplugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ items/qquickstyleitem.cpp items/qquickstyleitem.h
+ items/qquickstyleitembutton.cpp items/qquickstyleitembutton.h
+ items/qquickstyleitemcheckbox.cpp items/qquickstyleitemcheckbox.h
+ items/qquickstyleitemcombobox.cpp items/qquickstyleitemcombobox.h
+ items/qquickstyleitemdial.cpp items/qquickstyleitemdial.h
+ items/qquickstyleitemframe.cpp items/qquickstyleitemframe.h
+ items/qquickstyleitemgroupbox.cpp items/qquickstyleitemgroupbox.h
+ items/qquickstyleitemprogressbar.cpp items/qquickstyleitemprogressbar.h
+ items/qquickstyleitemradiobutton.cpp items/qquickstyleitemradiobutton.h
+ items/qquickstyleitemscrollbar.cpp items/qquickstyleitemscrollbar.h
+ items/qquickstyleitemslider.cpp items/qquickstyleitemslider.h
+ items/qquickstyleitemspinbox.cpp items/qquickstyleitemspinbox.h
+ items/qquickstyleitemtextfield.cpp items/qquickstyleitemtextfield.h
+ qstyle/qquickcommonstyle.cpp qstyle/qquickcommonstyle.h qstyle/qquickcommonstyle_p.h
+ qstyle/qquickcommonstylepixmaps_p.h
+ qstyle/qquickdrawutil.cpp qstyle/qquickdrawutil.h
+ qstyle/qquicknativestyle.cpp qstyle/qquicknativestyle.h
+ qstyle/qquickstyle.cpp qstyle/qquickstyle.h qstyle/qquickstyle_p.h
+ qstyle/qquickstylehelper.cpp qstyle/qquickstylehelper_p.h
+ qstyle/qquickstyleoption.cpp qstyle/qquickstyleoption.h
+ qtquickcontrols2nativestyleplugin.cpp
+ QML_FILES
+ ${qml_files}
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ items
+ qstyle
+ util
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickControls2Private
+ Qt::QuickPrivate
+ Qt::QuickTemplates2Private
+)
+
+qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION MACOS
+ SOURCES
+ items/qquickstyleitemscrollviewcorner.cpp items/qquickstyleitemscrollviewcorner.h
+ qstyle/mac/qquickmacstyle_mac.mm qstyle/mac/qquickmacstyle_mac_p.h
+ qstyle/mac/qquickmacstyle_mac_p_p.h
+ util/qquickmacfocusframe.h util/qquickmacfocusframe.mm
+ INCLUDE_DIRECTORIES
+ qstyle/mac
+ LIBRARIES
+ ${FWAppKit}
+)
+
+qt_internal_extend_target(qtquickcontrols2nativestyleplugin CONDITION WIN32
+ SOURCES
+ qstyle/windows/qquickwindowsstyle.cpp qstyle/windows/qquickwindowsstyle_p.h
+ qstyle/windows/qquickwindowsstyle_p_p.h
+ qstyle/windows/qquickwindowsxpstyle.cpp
+ INCLUDE_DIRECTORIES
+ qstyle/windows
+ LIBRARIES
+ gdi32
+ user32
+ uxtheme
+)
diff --git a/src/quicknativestyle/controls/DefaultButton.qml b/src/quicknativestyle/controls/DefaultButton.qml
new file mode 100644
index 0000000000..b6d8e42789
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultButton.qml
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.Button {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ leftPadding: __nativeBackground ? background.contentPadding.left : 5
+ rightPadding: __nativeBackground ? background.contentPadding.right : 5
+ topPadding: __nativeBackground ? background.contentPadding.top : 5
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom : 5
+
+ background: NativeStyle.Button {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ }
+
+ icon.width: 24
+ icon.height: 24
+ icon.color: control.palette.buttonText
+
+ contentItem: IconLabel {
+ spacing: control.spacing
+ mirrored: control.mirrored
+ display: control.display
+
+ icon: control.icon
+ text: control.text
+ font: control.font
+ color: control.palette.buttonText
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultCheckBox.qml b/src/quicknativestyle/controls/DefaultCheckBox.qml
new file mode 100644
index 0000000000..45e4988958
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultCheckBox.qml
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.NativeStyle as NativeStyle
+
+T.CheckBox {
+ id: control
+
+ readonly property bool nativeIndicator: indicator instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: nativeIndicator ? 0 : 6
+ padding: nativeIndicator ? 0 : 6
+
+ indicator: NativeStyle.CheckBox {
+ control: control
+ y: control.topPadding + (control.availableHeight - height) >> 1
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ useNinePatchImage: false
+ }
+
+ contentItem: CheckLabel {
+ text: control.text
+ font: control.font
+ color: control.palette.windowText
+
+ // For some reason, the other styles set padding here (in the delegate), instead of in
+ // the control above. And they also adjust the indicator position by setting x and y
+ // explicitly (instead of using insets). So we follow the same pattern to ensure that
+ // setting a custom contentItem delegate from the app will end up looking the same for
+ // all styles. But this should probably be fixed for all styles (to make them work the
+ // same way as e.g Buttons).
+ leftPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.left
+ else
+ indicator && !mirrored ? indicator.width + spacing : 0
+ }
+
+ topPadding: nativeIndicator ? indicator.contentPadding.top : 0
+ rightPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.right
+ else
+ indicator && mirrored ? indicator.width + spacing : 0
+ }
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultComboBox.qml b/src/quicknativestyle/controls/DefaultComboBox.qml
new file mode 100644
index 0000000000..d3f168d567
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultComboBox.qml
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Window
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.ComboBox {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ 90 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ leftPadding: __nativeBackground ? background.contentPadding.left : 5
+ rightPadding: __nativeBackground ? background.contentPadding.right : 5
+ topPadding: __nativeBackground ? background.contentPadding.top : 5
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom : 5
+
+ contentItem: T.TextField {
+ implicitWidth: contentWidth
+ implicitHeight: contentHeight
+ text: control.editable ? control.editText : control.displayText
+
+ enabled: control.editable
+ autoScroll: control.editable
+ readOnly: control.down
+ inputMethodHints: control.inputMethodHints
+ validator: control.validator
+ selectByMouse: control.selectTextByMouse
+
+ font: control.font
+ color: control.editable ? control.palette.text : control.palette.buttonText
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ background: NativeStyle.ComboBox {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ }
+
+ delegate: ItemDelegate {
+ width: ListView.view.width
+ text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
+ palette.text: control.palette.text
+ palette.highlightedText: control.palette.highlightedText
+ font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal
+ highlighted: control.highlightedIndex === index
+ hoverEnabled: control.hoverEnabled
+ }
+
+ popup: T.Popup {
+ readonly property var layoutMargins: control.__nativeBackground ? control.background.layoutMargins : null
+ x: layoutMargins ? layoutMargins.left : 0
+ y: control.height - (layoutMargins ? layoutMargins.bottom : 0)
+ width: control.width - (layoutMargins ? layoutMargins.left + layoutMargins.right : 0)
+ height: Math.min(contentItem.implicitHeight, control.Window.height - topMargin - bottomMargin)
+ topMargin: 6
+ bottomMargin: 6
+
+ contentItem: ListView {
+ clip: true
+ implicitHeight: contentHeight
+ model: control.delegateModel
+ currentIndex: control.highlightedIndex
+ highlightMoveDuration: 0
+
+ Rectangle {
+ z: 10
+ width: parent.width
+ height: parent.height
+ color: "transparent"
+ border.color: control.palette.mid
+ }
+
+ T.ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ color: control.palette.window
+ }
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultDial.qml b/src/quicknativestyle/controls/DefaultDial.qml
new file mode 100644
index 0000000000..9ede707662
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultDial.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.Dial {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ 80 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ 80 /* minimum */ )
+
+ background: NativeStyle.Dial {
+ control: control
+ useNinePatchImage: false
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultFrame.qml b/src/quicknativestyle/controls/DefaultFrame.qml
new file mode 100644
index 0000000000..77ca612501
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultFrame.qml
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.Frame {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ leftPadding: __nativeBackground ? background.contentPadding.left : 12
+ rightPadding: __nativeBackground ? background.contentPadding.right : 12
+ topPadding: __nativeBackground ? background.contentPadding.top : 12
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom : 12
+
+ background: NativeStyle.Frame {
+ control: control
+ contentWidth: control.contentWidth
+ contentHeight: control.contentHeight
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultGroupBox.qml b/src/quicknativestyle/controls/DefaultGroupBox.qml
new file mode 100644
index 0000000000..dcaeaaf8a9
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultGroupBox.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.GroupBox {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ contentWidth + leftPadding + rightPadding,
+ implicitLabelWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding)
+
+ label: Rectangle {
+ color: control.palette.window
+ property point labelPos : control.__nativeBackground
+ ? background.labelPos
+ : Qt.point(0,0)
+ x: labelPos.x + background.x
+ y: labelPos.y + background.y - (__nativeBackground ? background.groupBoxPadding.top : 0)
+ width: children[0].implicitWidth
+ height: children[0].implicitHeight
+ Text {
+ width: parent.width
+ height: parent.height
+ text: control.title
+ font: control.font
+ color: control.palette.windowText
+ elide: Text.ElideRight
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ leftPadding: __nativeBackground ? background.contentPadding.left : 0
+ rightPadding: __nativeBackground ? background.contentPadding.right : 0
+ topPadding: __nativeBackground ? background.contentPadding.top : 0
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom : 0
+
+ leftInset: __nativeBackground ? background.groupBoxPadding.left : 0
+ topInset: __nativeBackground ? background.groupBoxPadding.top : 0
+
+ background: NativeStyle.GroupBox {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultProgressBar.qml b/src/quicknativestyle/controls/DefaultProgressBar.qml
new file mode 100644
index 0000000000..77934b31c4
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultProgressBar.qml
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+import QtQuick.NativeStyle as NativeStyle
+
+T.ProgressBar {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding,
+ control.horizontal ? 90 : 0 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ control.vertical ? 90 : 0 /* minimum */ )
+
+ background: NativeStyle.ProgressBar {
+ control: control
+ useNinePatchImage: false
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultRadioButton.qml b/src/quicknativestyle/controls/DefaultRadioButton.qml
new file mode 100644
index 0000000000..91f340b716
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultRadioButton.qml
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Templates as T
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.NativeStyle as NativeStyle
+
+T.RadioButton {
+ id: control
+
+ readonly property bool nativeIndicator: indicator instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding,
+ implicitIndicatorHeight + topPadding + bottomPadding)
+
+ spacing: nativeIndicator ? 0 : 6
+ padding: nativeIndicator ? 0 : 6
+
+ indicator: NativeStyle.RadioButton {
+ control: control
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ useNinePatchImage: false
+// Component.onCompleted: {
+// var f = indicator.font(control)
+// control.font.pixelSize = f.pixelSize
+// print(f)
+// }
+ }
+
+ contentItem: CheckLabel {
+ text: control.text
+ font: control.font
+ color: control.palette.windowText
+
+ // For some reason, the other styles set padding here (in the delegate), instead of in
+ // the control above. And they also adjust the indicator position by setting x and y
+ // explicitly (instead of using insets). So we follow the same pattern to ensure that
+ // setting a custom contentItem delegate from the app will end up looking the same for
+ // all styles. But this should probably be fixed for all styles (to make them work the
+ // same way as e.g Buttons).
+ leftPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.left
+ else
+ indicator && !mirrored ? indicator.width + spacing : 0
+ }
+
+ rightPadding: {
+ if (nativeIndicator)
+ indicator.contentPadding.right
+ else
+ indicator && mirrored ? indicator.width + spacing : 0
+ }
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultScrollBar.qml b/src/quicknativestyle/controls/DefaultScrollBar.qml
new file mode 100644
index 0000000000..ef20f7016c
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultScrollBar.qml
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.ScrollBar {
+ id: control
+
+ readonly property bool __nativeContentItem: contentItem instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ visible: policy === T.ScrollBar.AlwaysOn || (policy === T.ScrollBar.AsNeeded && size < 1.0)
+ minimumSize: !__nativeContentItem ? 10 : orientation === Qt.Vertical ?
+ contentItem.minimumSize.height / height : contentItem.minimumSize.width / width
+
+ background: NativeStyle.ScrollBar {
+ control: control
+ subControl: NativeStyle.ScrollBar.Groove
+ }
+
+ contentItem: NativeStyle.ScrollBar {
+ control: control
+ subControl: NativeStyle.ScrollBar.Handle
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultSlider.qml b/src/quicknativestyle/controls/DefaultSlider.qml
new file mode 100644
index 0000000000..6d4521720c
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultSlider.qml
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.Slider {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitHandleWidth + leftPadding + rightPadding,
+ control.horizontal ? 90 : 0 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitHandleHeight + topPadding + bottomPadding,
+ control.vertical ? 90 : 0 /* minimum */ )
+
+ background: NativeStyle.Slider {
+ control: control
+ subControl: NativeStyle.Slider.Groove
+ // We normally cannot use a nine patch image for the
+ // groove if we draw tickmarks (since then the scaling
+ // would scale the tickmarks too). The groove might
+ // also use a different background color before, and
+ // after, the handle.
+ useNinePatchImage: false
+ }
+
+ handle: NativeStyle.Slider {
+ control: control
+ subControl: NativeStyle.Slider.Handle
+ x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
+ y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
+ useNinePatchImage: false
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultSpinBox.qml b/src/quicknativestyle/controls/DefaultSpinBox.qml
new file mode 100644
index 0000000000..640aab0020
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultSpinBox.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.SpinBox {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: Math.max(implicitBackgroundWidth + spacing + up.implicitIndicatorWidth
+ + leftInset + rightInset,
+ 90 /* minimum */ )
+ implicitHeight: Math.max(implicitBackgroundHeight, up.implicitIndicatorHeight + down.implicitIndicatorHeight
+ + (spacing * 3)) + topInset + bottomInset
+
+ spacing: 2
+
+ leftPadding: (__nativeBackground ? background.contentPadding.left: 0)
+ topPadding: (__nativeBackground ? background.contentPadding.top: 0)
+ rightPadding: (__nativeBackground ? background.contentPadding.right : 0) + up.implicitIndicatorWidth + spacing
+ bottomPadding: (__nativeBackground ? background.contentPadding.bottom: 0) + spacing
+
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+
+ contentItem: TextInput {
+ text: control.displayText
+ font: font.font
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ horizontalAlignment: Qt.AlignLeft
+ verticalAlignment: Qt.AlignVCenter
+
+ topPadding: 2
+ bottomPadding: 2
+ leftPadding: 10
+ rightPadding: 10
+
+ readOnly: !control.editable
+ validator: control.validator
+ inputMethodHints: control.inputMethodHints
+ }
+
+ up.indicator: NativeStyle.SpinBox {
+ control: control
+ subControl: NativeStyle.SpinBox.Up
+ x: parent.width - width - spacing
+ y: (parent.height / 2) - height
+ useNinePatchImage: false
+ }
+
+ down.indicator: NativeStyle.SpinBox {
+ control: control
+ subControl: NativeStyle.SpinBox.Down
+ x: up.indicator.x
+ y: up.indicator.y + up.indicator.height
+ useNinePatchImage: false
+ }
+
+ background: NativeStyle.SpinBox {
+ control: control
+ subControl: NativeStyle.SpinBox.Frame
+ contentWidth: contentItem.implicitWidth
+ contentHeight: contentItem.implicitHeight
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultTextArea.qml b/src/quicknativestyle/controls/DefaultTextArea.qml
new file mode 100644
index 0000000000..c598baf1c5
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultTextArea.qml
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.TextArea {
+ id: control
+
+ implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
+ implicitBackgroundWidth + leftInset + rightInset,
+ placeholder.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
+ implicitBackgroundHeight + topInset + bottomInset,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ leftPadding: 7
+ rightPadding: 7
+ topPadding: 3
+ bottomPadding: 3
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: TextInput.AlignTop
+
+ PlaceholderText {
+ id: placeholder
+ x: control.leftPadding
+ y: control.topPadding
+ width: control.availableWidth
+ height: control.availableHeight
+ text: control.placeholderText
+ font: control.font
+ color: control.placeholderTextColor
+ verticalAlignment: control.verticalAlignment
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: Rectangle {
+ color: control.palette.light
+ }
+}
diff --git a/src/quicknativestyle/controls/DefaultTextField.qml b/src/quicknativestyle/controls/DefaultTextField.qml
new file mode 100644
index 0000000000..6b366fedeb
--- /dev/null
+++ b/src/quicknativestyle/controls/DefaultTextField.qml
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Controls.impl
+import QtQuick.Templates as T
+import QtQuick.NativeStyle as NativeStyle
+
+T.TextField {
+ id: control
+
+ readonly property bool __nativeBackground: background instanceof NativeStyle.StyleItem
+
+ implicitWidth: implicitBackgroundWidth + leftInset + rightInset
+ || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
+
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ contentHeight + topPadding + bottomPadding,
+ placeholder.implicitHeight + topPadding + bottomPadding)
+
+ leftPadding: __nativeBackground ? background.contentPadding.left: 7
+ rightPadding: __nativeBackground ? background.contentPadding.right: 7
+ topPadding: __nativeBackground ? background.contentPadding.top: 3
+ bottomPadding: __nativeBackground ? background.contentPadding.bottom: 3
+
+ color: control.palette.text
+ selectionColor: control.palette.highlight
+ selectedTextColor: control.palette.highlightedText
+ placeholderTextColor: control.palette.placeholderText
+ verticalAlignment: TextInput.AlignTop
+
+ 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
+ visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
+ elide: Text.ElideRight
+ renderType: control.renderType
+ }
+
+ background: NativeStyle.TextField {
+ control: control
+ contentWidth: Math.max(control.contentWidth, placeholder.implicitWidth)
+ contentHeight: control.contentHeight
+ }
+}
diff --git a/src/quicknativestyle/controls/controls.pri b/src/quicknativestyle/controls/controls.pri
new file mode 100644
index 0000000000..8675989e29
--- /dev/null
+++ b/src/quicknativestyle/controls/controls.pri
@@ -0,0 +1,14 @@
+QML_FILES += \
+ $$PWD/DefaultButton.qml \
+ $$PWD/DefaultSlider.qml \
+ $$PWD/DefaultGroupBox.qml \
+ $$PWD/DefaultCheckBox.qml \
+ $$PWD/DefaultRadioButton.qml \
+ $$PWD/DefaultSpinBox.qml \
+ $$PWD/DefaultTextField.qml \
+ $$PWD/DefaultFrame.qml \
+ $$PWD/DefaultTextArea.qml \
+ $$PWD/DefaultComboBox.qml \
+ $$PWD/DefaultScrollBar.qml \
+ $$PWD/DefaultProgressBar.qml \
+ $$PWD/DefaultDial.qml \
diff --git a/src/quicknativestyle/items/items.pri b/src/quicknativestyle/items/items.pri
new file mode 100644
index 0000000000..5b6d9251a2
--- /dev/null
+++ b/src/quicknativestyle/items/items.pri
@@ -0,0 +1,36 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qquickstyleitem.h \
+ $$PWD/qquickstyleitembutton.h \
+ $$PWD/qquickstyleitemgroupbox.h \
+ $$PWD/qquickstyleitemcheckbox.h \
+ $$PWD/qquickstyleitemradiobutton.h \
+ $$PWD/qquickstyleitemslider.h \
+ $$PWD/qquickstyleitemspinbox.h \
+ $$PWD/qquickstyleitemtextfield.h \
+ $$PWD/qquickstyleitemframe.h \
+ $$PWD/qquickstyleitemcombobox.h \
+ $$PWD/qquickstyleitemscrollbar.h \
+ $$PWD/qquickstyleitemprogressbar.h \
+ $$PWD/qquickstyleitemdial.h \
+
+SOURCES += \
+ $$PWD/qquickstyleitem.cpp \
+ $$PWD/qquickstyleitembutton.cpp \
+ $$PWD/qquickstyleitemgroupbox.cpp \
+ $$PWD/qquickstyleitemcheckbox.cpp \
+ $$PWD/qquickstyleitemradiobutton.cpp \
+ $$PWD/qquickstyleitemslider.cpp \
+ $$PWD/qquickstyleitemspinbox.cpp \
+ $$PWD/qquickstyleitemtextfield.cpp \
+ $$PWD/qquickstyleitemframe.cpp \
+ $$PWD/qquickstyleitemcombobox.cpp \
+ $$PWD/qquickstyleitemscrollbar.cpp \
+ $$PWD/qquickstyleitemprogressbar.cpp \
+ $$PWD/qquickstyleitemdial.cpp \
+
+macos {
+ HEADERS += $$PWD/qquickstyleitemscrollviewcorner.h
+ SOURCES += $$PWD/qquickstyleitemscrollviewcorner.cpp
+}
diff --git a/src/quicknativestyle/items/qquickstyleitem.cpp b/src/quicknativestyle/items/qquickstyleitem.cpp
new file mode 100644
index 0000000000..7e8403ad30
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitem.cpp
@@ -0,0 +1,578 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitem.h"
+
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtCore/qdir.h>
+
+#include <QtQuick/qsgninepatchnode.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qquickrendercontrol.h>
+
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
+
+#include <QtQml/qqml.h>
+
+#include "qquickstyleitembutton.h"
+#include "qquickstylehelper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QDebug operator<<(QDebug debug, const QQuickStyleMargins &padding)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "StyleMargins(";
+ debug << padding.left() << ", ";
+ debug << padding.top() << ", ";
+ debug << padding.right() << ", ";
+ debug << padding.bottom();
+ debug << ')';
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const StyleItemGeometry &cg)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "StyleItemGeometry(";
+ debug << "implicitSize:" << cg.implicitSize << ", ";
+ debug << "contentRect:" << cg.contentRect << ", ";
+ debug << "layoutRect:" << cg.layoutRect << ", ";
+ debug << "minimumSize:" << cg.minimumSize << ", ";
+ debug << "9patchMargins:" << cg.ninePatchMargins;
+ debug << ')';
+ return debug;
+}
+
+int QQuickStyleItem::dprAlignedSize(const int size) const
+{
+ // Return the first value equal to or bigger than size
+ // that is a whole number when multiplied with the dpr.
+ static int multiplier = [&]() {
+ const qreal dpr = window()->effectiveDevicePixelRatio();
+ for (int m = 1; m <= 10; ++m) {
+ const qreal v = m * dpr;
+ if (v == int(v))
+ return m;
+ }
+
+ qWarning() << "The current dpr (" << dpr << ") is not supported"
+ << "by the style and might result in drawing artifacts";
+ return 1;
+ }();
+
+ return int(qCeil(qreal(size) / qreal(multiplier)) * multiplier);
+}
+
+QQuickStyleItem::QQuickStyleItem(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setFlag(QQuickItem::ItemHasContents);
+}
+
+QQuickStyleItem::~QQuickStyleItem()
+{
+}
+
+void QQuickStyleItem::connectToControl() const
+{
+ connect(m_control, &QQuickStyleItem::enabledChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(m_control, &QQuickItem::activeFocusChanged, this, &QQuickStyleItem::markImageDirty);
+
+ if (QQuickWindow *win = window()) {
+ connect(win, &QQuickWindow::activeChanged, this, &QQuickStyleItem::markImageDirty);
+ m_connectedWindow = win;
+ }
+}
+
+void QQuickStyleItem::markImageDirty()
+{
+ m_dirty.setFlag(DirtyFlag::Image);
+ if (isComponentComplete())
+ polish();
+}
+
+void QQuickStyleItem::markGeometryDirty()
+{
+ m_dirty.setFlag(DirtyFlag::Geometry);
+ if (isComponentComplete())
+ polish();
+}
+
+QSGNode *QQuickStyleItem::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *)
+{
+ QSGNinePatchNode *node = static_cast<QSGNinePatchNode *>(oldNode);
+ if (!node)
+ node = window()->createNinePatchNode();
+
+ if (m_paintedImage.isNull()) {
+ // If we cannot create a texture, the node should not exist either
+ // because its material requires a texture.
+ delete node;
+ return nullptr;
+ }
+
+ const auto texture = window()->createTextureFromImage(m_paintedImage, QQuickWindow::TextureCanUseAtlas);
+
+ QRectF bounds = boundingRect();
+ const qreal dpr = window()->effectiveDevicePixelRatio();
+ const QSizeF unscaledImageSize = QSizeF(m_paintedImage.size()) / dpr;
+
+ // We can scale the image up with a nine patch node, but should
+ // avoid to scale it down. Otherwise the nine patch image will look
+ // wrapped (or look truncated, in case of no padding). So if the
+ // item is smaller that the image, don't scale.
+ if (bounds.width() < unscaledImageSize.width())
+ bounds.setWidth(unscaledImageSize.width());
+ if (bounds.height() < unscaledImageSize.height())
+ bounds.setHeight(unscaledImageSize.height());
+
+#ifdef QT_DEBUG
+ if (m_debugFlags.testFlag(Unscaled)) {
+ bounds.setSize(unscaledImageSize);
+ qqc2Info() << "Setting qsg node size to the unscaled size of m_paintedImage:" << bounds;
+ }
+#endif
+
+ if (m_useNinePatchImage) {
+ QMargins padding = m_styleItemGeometry.ninePatchMargins;
+ if (padding.right() == -1) {
+ // Special case: a padding of -1 means that
+ // the image shouldn't scale in the given direction.
+ padding.setLeft(0);
+ padding.setRight(0);
+ }
+ if (padding.bottom() == -1) {
+ padding.setTop(0);
+ padding.setBottom(0);
+ }
+ node->setPadding(padding.left(), padding.top(), padding.right(), padding.bottom());
+ }
+
+ node->setBounds(bounds);
+ node->setTexture(texture);
+ node->setDevicePixelRatio(dpr);
+ node->update();
+
+ return node;
+}
+
+QStyle::State QQuickStyleItem::controlSize(QQuickItem *item)
+{
+ // TODO: add proper API for small and mini
+ if (item->metaObject()->indexOfProperty("qqc2_style_small") != -1)
+ return QStyle::State_Small;
+ if (item->metaObject()->indexOfProperty("qqc2_style_mini") != -1)
+ return QStyle::State_Mini;
+ return QStyle::State_None;
+}
+
+static QWindow *effectiveWindow(QQuickWindow *window)
+{
+ QWindow *renderWindow = QQuickRenderControl::renderWindowFor(window);
+ return renderWindow ? renderWindow : window;
+}
+
+void QQuickStyleItem::initStyleOptionBase(QStyleOption &styleOption) const
+{
+ Q_ASSERT(m_control);
+
+ styleOption.control = const_cast<QQuickItem *>(control<QQuickItem>());
+ styleOption.window = effectiveWindow(window());
+ styleOption.palette = QQuickItemPrivate::get(m_control)->palette()->toQPalette();
+ styleOption.rect = QRect(QPoint(0, 0), imageSize());
+
+ styleOption.state = QStyle::State_None;
+ styleOption.state |= controlSize(styleOption.control);
+
+ // Note: not all controls inherit from QQuickControl (e.g QQuickTextField)
+ if (const auto quickControl = dynamic_cast<QQuickControl *>(m_control.data()))
+ styleOption.direction = quickControl->isMirrored() ? Qt::RightToLeft : Qt::LeftToRight;
+
+ if (styleOption.window) {
+ if (styleOption.window->isActive())
+ styleOption.state |= QStyle::State_Active;
+ if (m_control->isEnabled())
+ styleOption.state |= QStyle::State_Enabled;
+ if (m_control->hasActiveFocus())
+ styleOption.state |= QStyle::State_HasFocus;
+ if (m_control->isUnderMouse())
+ styleOption.state |= QStyle::State_MouseOver;
+ // Should this depend on the focusReason (e.g. only TabFocus) ?
+ styleOption.state |= QStyle::State_KeyboardFocusChange;
+ }
+
+ if (m_overrideState != None) {
+ // In Button.qml we fade between two versions of
+ // the handle, depending on if it's hovered or not
+ if (m_overrideState & AlwaysHovered)
+ styleOption.state |= QStyle::State_MouseOver;
+ else if (m_overrideState & NeverHovered)
+ styleOption.state &= ~QStyle::State_MouseOver;
+ }
+
+ qqc2Info() << styleOption;
+}
+
+void QQuickStyleItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+
+ // Ensure that we only schedule a new geometry update
+ // and polish if this geometry change was caused by
+ // something else than us already updating geometry.
+ if (!m_polishing)
+ markGeometryDirty();
+}
+
+void QQuickStyleItem::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ QQuickItem::itemChange(change, data);
+
+ switch (change) {
+ case QQuickItem::ItemVisibleHasChanged:
+ if (data.boolValue)
+ markImageDirty();
+ break;
+ case QQuickItem::ItemSceneChange: {
+ markImageDirty();
+ QQuickWindow *win = data.window;
+ if (m_connectedWindow)
+ disconnect(m_connectedWindow, &QQuickWindow::activeChanged, this, &QQuickStyleItem::markImageDirty);
+ if (win)
+ connect(win, &QQuickWindow::activeChanged, this, &QQuickStyleItem::markImageDirty);
+ m_connectedWindow = win;
+ break;}
+ default:
+ break;
+ }
+}
+
+void QQuickStyleItem::updateGeometry()
+{
+ qqc2InfoHeading("GEOMETRY");
+ m_dirty.setFlag(DirtyFlag::Geometry, false);
+
+ const QQuickStyleMargins oldContentPadding = contentPadding();
+ const QQuickStyleMargins oldLayoutMargins = layoutMargins();
+ const QSize oldMinimumSize = minimumSize();
+
+ m_styleItemGeometry = calculateGeometry();
+
+#ifdef QT_DEBUG
+ if (m_styleItemGeometry.minimumSize.isEmpty())
+ qmlWarning(this) << "minimumSize is empty!";
+#endif
+
+ if (m_styleItemGeometry.implicitSize.isEmpty()) {
+ // If the item has no contents (or its size is
+ // empty), we just use the minimum size as implicit size.
+ m_styleItemGeometry.implicitSize = m_styleItemGeometry.minimumSize;
+ qqc2Info() << "implicitSize is empty, using minimumSize instead";
+ }
+
+ if (contentPadding() != oldContentPadding)
+ emit contentPaddingChanged();
+ if (layoutMargins() != oldLayoutMargins)
+ emit layoutMarginsChanged();
+ if (minimumSize() != oldMinimumSize)
+ emit minimumSizeChanged();
+
+ setImplicitSize(m_styleItemGeometry.implicitSize.width(), m_styleItemGeometry.implicitSize.height());
+
+ qqc2Info() << m_styleItemGeometry
+ << "bounding rect:" << boundingRect()
+ << "layout margins:" << layoutMargins()
+ << "content padding:" << contentPadding()
+ << "input content size:" << m_contentSize;
+}
+
+void QQuickStyleItem::paintControlToImage()
+{
+ qqc2InfoHeading("PAINT");
+ const QSize imgSize = imageSize();
+ if (imgSize.isEmpty())
+ return;
+
+ m_dirty.setFlag(DirtyFlag::Image, false);
+
+ // The size of m_paintedImage should normally be imgSize * dpr. The problem is
+ // that the dpr can be e.g 1.25, which means that the size can end up having a
+ // fraction. But an image cannot have a size with a fraction, so it would need
+ // to be rounded. But on the flip side, rounding the size means that the size
+ // of the scene graph node (which is, when the texture is not scaled,
+ // m_paintedImage.size() / dpr), will end up with a fraction instead. And this
+ // causes rendering artifacts in the scene graph when the texture is mapped
+ // to physical screen coordinates. So for that reason we calculate an image size
+ // that might be slightly larger than imgSize, so that imgSize * dpr lands on a
+ // whole number. The result is that neither the image size, nor the scene graph
+ // node, ends up with a size that has a fraction.
+ const qreal dpr = window()->effectiveDevicePixelRatio();
+ const int alignedW = int(dprAlignedSize(imgSize.width()) * dpr);
+ const int alignedH = int(dprAlignedSize(imgSize.height()) * dpr);
+ const QSize alignedSize = QSize(alignedW, alignedH);
+
+ if (m_paintedImage.size() != alignedSize) {
+ m_paintedImage = QImage(alignedSize, QImage::Format_ARGB32_Premultiplied);
+ m_paintedImage.setDevicePixelRatio(dpr);
+ qqc2Info() << "created image with dpr aligned size:" << alignedSize;
+ }
+
+ m_paintedImage.fill(Qt::transparent);
+
+ QPainter painter(&m_paintedImage);
+ paintEvent(&painter);
+
+#ifdef QT_DEBUG
+ if (m_debugFlags != NoDebug) {
+ painter.setPen(QColor(255, 0, 0, 255));
+ if (m_debugFlags.testFlag(ImageRect))
+ painter.drawRect(QRect(QPoint(0, 0), alignedSize / dpr));
+ if (m_debugFlags.testFlag(LayoutRect)) {
+ const auto m = layoutMargins();
+ QRect rect = QRect(QPoint(0, 0), imgSize);
+ rect.adjust(m.left(), m.top(), -m.right(), -m.bottom());
+ painter.drawRect(rect);
+ }
+ if (m_debugFlags.testFlag(ContentRect)) {
+ const auto p = contentPadding();
+ QRect rect = QRect(QPoint(0, 0), imgSize);
+ rect.adjust(p.left(), p.top(), -p.right(), -p.bottom());
+ painter.drawRect(rect);
+ }
+ if (m_debugFlags.testFlag(InputContentSize)) {
+ const int offset = 2;
+ const QPoint p = m_styleItemGeometry.contentRect.topLeft();
+ painter.drawLine(p.x() - offset, p.y() - offset, p.x() + m_contentSize.width(), p.y() - offset);
+ painter.drawLine(p.x() - offset, p.y() - offset, p.x() - offset, p.y() + m_contentSize.height());
+ }
+ if (m_debugFlags.testFlag(NinePatchMargins)) {
+ const QMargins m = m_styleItemGeometry.ninePatchMargins;
+ if (m.right() != -1) {
+ painter.drawLine(m.left(), 0, m.left(), imgSize.height());
+ painter.drawLine(imgSize.width() - m.right(), 0, imgSize.width() - m.right(), imgSize.height());
+ }
+ if (m.bottom() != -1) {
+ painter.drawLine(0, m.top(), imgSize.width(), m.top());
+ painter.drawLine(0, imgSize.height() - m.bottom(), imgSize.width(), imgSize.height() - m.bottom());
+ }
+ }
+ if (m_debugFlags.testFlag(SaveImage)) {
+ static int nr = -1;
+ ++nr;
+ static QString filename = QStringLiteral("styleitem_saveimage_");
+ const QString path = QDir::current().absoluteFilePath(filename);
+ const QString name = path + QString::number(nr) + QStringLiteral(".png");
+ m_paintedImage.save(name);
+ qDebug() << "image saved to:" << name;
+ }
+ }
+#endif
+
+ update();
+}
+
+void QQuickStyleItem::updatePolish()
+{
+ QScopedValueRollback<bool> guard(m_polishing, true);
+
+ const bool dirtyGeometry = m_dirty & DirtyFlag::Geometry;
+ const bool dirtyImage = isVisible() && ((m_dirty & DirtyFlag::Image) || (!m_useNinePatchImage && dirtyGeometry));
+
+ if (dirtyGeometry)
+ updateGeometry();
+ if (dirtyImage)
+ paintControlToImage();
+}
+
+#ifdef QT_DEBUG
+void QQuickStyleItem::addDebugInfo()
+{
+ // Example debug strings:
+ // "QQC2_NATIVESTYLE_DEBUG="myButton output contentRect"
+ // "QQC2_NATIVESTYLE_DEBUG="ComboBox ninepatchmargins"
+ // "QQC2_NATIVESTYLE_DEBUG="All layoutrect"
+
+ static const auto debugString = qEnvironmentVariable("QQC2_NATIVESTYLE_DEBUG");
+ static const auto matchAll = debugString.startsWith(QLatin1String("All "));
+ static const auto prefix = QStringLiteral("QQuickStyleItem");
+ if (debugString.isEmpty())
+ return;
+
+ const auto objectName = m_control->objectName();
+ const auto typeName = QString::fromUtf8(metaObject()->className()).remove(prefix);
+ const bool matchName = !objectName.isEmpty() && debugString.startsWith(objectName);
+ const bool matchType = debugString.startsWith(typeName);
+
+ if (!(matchAll || matchName || matchType))
+ return;
+
+#define QQC2_DEBUG_FLAG(FLAG) \
+ if (debugString.contains(QLatin1String(#FLAG), Qt::CaseInsensitive)) m_debugFlags |= FLAG
+
+ QQC2_DEBUG_FLAG(Info);
+ QQC2_DEBUG_FLAG(ImageRect);
+ QQC2_DEBUG_FLAG(ContentRect);
+ QQC2_DEBUG_FLAG(LayoutRect);
+ QQC2_DEBUG_FLAG(InputContentSize);
+ QQC2_DEBUG_FLAG(DontUseNinePatchImage);
+ QQC2_DEBUG_FLAG(NinePatchMargins);
+ QQC2_DEBUG_FLAG(Unscaled);
+ QQC2_DEBUG_FLAG(Debug);
+ QQC2_DEBUG_FLAG(SaveImage);
+
+ if (m_debugFlags & (DontUseNinePatchImage
+ | InputContentSize
+ | ContentRect
+ | LayoutRect
+ | NinePatchMargins)) {
+ // Some rects will not fit inside the drawn image unless
+ // we switch off (nine patch) image scaling.
+ m_debugFlags |= DontUseNinePatchImage;
+ m_useNinePatchImage = false;
+ }
+
+ if (m_debugFlags != NoDebug)
+ qDebug() << "debug options set for" << typeName << "(" << objectName << "):" << m_debugFlags;
+ else
+ qDebug() << "available debug options:" << DebugFlags(0xFFFF);
+}
+#endif
+
+void QQuickStyleItem::componentComplete()
+{
+ Q_ASSERT_X(m_control, Q_FUNC_INFO, "You need to assign a value to property 'control'");
+#ifdef QT_DEBUG
+ addDebugInfo();
+#endif
+ QQuickItem::componentComplete();
+ updateGeometry();
+ connectToControl();
+ polish();
+}
+
+qreal QQuickStyleItem::contentWidth()
+{
+ return m_contentSize.width();
+}
+
+void QQuickStyleItem::setContentWidth(qreal contentWidth)
+{
+ if (qFuzzyCompare(m_contentSize.width(), contentWidth))
+ return;
+
+ m_contentSize.setWidth(contentWidth);
+ markGeometryDirty();
+}
+
+qreal QQuickStyleItem::contentHeight()
+{
+ return m_contentSize.height();
+}
+
+void QQuickStyleItem::setContentHeight(qreal contentHeight)
+{
+ if (qFuzzyCompare(m_contentSize.height(), contentHeight))
+ return;
+
+ m_contentSize.setHeight(contentHeight);
+ markGeometryDirty();
+}
+
+QQuickStyleMargins QQuickStyleItem::contentPadding() const
+{
+ const QRect outerRect(QPoint(0, 0), m_styleItemGeometry.implicitSize);
+ return QQuickStyleMargins(outerRect, m_styleItemGeometry.contentRect);
+}
+
+QQuickStyleMargins QQuickStyleItem::layoutMargins() const
+{
+ // ### TODO: layoutRect is currently not being used for anything. But
+ // eventually this information will be needed by layouts to align the controls
+ // correctly. This because the images drawn by QStyle are usually a bit bigger
+ // than the control(frame) itself, to e.g make room for shadow effects
+ // or focus rects/glow. And this will differ from control to control. The
+ // layoutRect will then inform where the frame of the control is.
+ QQuickStyleMargins margins;
+ if (m_styleItemGeometry.layoutRect.isValid()) {
+ const QRect outerRect(QPoint(0, 0), m_styleItemGeometry.implicitSize);
+ margins = QQuickStyleMargins(outerRect, m_styleItemGeometry.layoutRect);
+ }
+ return margins;
+}
+
+QSize QQuickStyleItem::minimumSize() const
+{
+ // The style item should not be scaled below this size.
+ // Otherwise the image will be truncated.
+ return m_styleItemGeometry.minimumSize;
+}
+
+QSize QQuickStyleItem::imageSize() const
+{
+ // Returns the size of the QImage (unscaled) that
+ // is used to draw the control from QStyle.
+ return m_useNinePatchImage ? m_styleItemGeometry.minimumSize : size().toSize();
+}
+
+qreal QQuickStyleItem::focusFrameRadius() const
+{
+ return m_styleItemGeometry.focusFrameRadius;
+}
+
+QFont QQuickStyleItem::styleFont(QQuickItem *control) const
+{
+ Q_ASSERT(control);
+ // Note: This function should be treated as if it was static
+ // (meaning, don't assume anything in this object to be initialized).
+ // Resolving the font/font size should be done early on from QML, before we get
+ // around to calculate geometry and paint. Otherwise we typically need to do it
+ // all over again when/if the font changes. In practice this means that other
+ // items in QML that uses a style font, and at the same time, affects our input
+ // contentSize, cannot wait for this item to be fully constructed before it
+ // gets the font. So we need to resolve it here and now, even if this
+ // object might be in a half initialized state (hence also the control
+ // argument, instead of relying on m_control to be set).
+ return QGuiApplication::font();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitem.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitem.h b/src/quicknativestyle/items/qquickstyleitem.h
new file mode 100644
index 0000000000..503260aaee
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitem.h
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEM_H
+#define QQUICKSTYLEITEM_H
+
+#include <QtCore/qdebug.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+#include "qquicknativestyle.h"
+#include "qquickstyle.h"
+#include "qquickstyleoption.h"
+
+// Work-around for now, to avoid creator getting confused
+// about missing macros. Should eventually be defined
+// in qt declarative somewhere I assume.
+#ifndef QML_NAMED_ELEMENT
+#define QML_NAMED_ELEMENT(NAME)
+#define QML_UNCREATABLE(NAME)
+#endif
+
+#ifdef QT_DEBUG
+#define qqc2Debug() if (m_debugFlags.testFlag(Debug)) qDebug() << __FUNCTION__ << ":"
+#define qqc2Info() if (m_debugFlags.testFlag(Info)) qDebug() << __FUNCTION__ << ":"
+#define qqc2InfoHeading(HEADING) if (m_debugFlags.testFlag(Info)) qDebug() << "--------" << HEADING << "--------"
+#else
+#define qqc2Debug() if (false) qDebug()
+#define qqc2Info() if (false) qDebug()
+#define qqc2InfoHeading(HEADING) if (false) qDebug()
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQC2;
+
+class QQuickStyleMargins
+{
+ Q_GADGET
+
+ Q_PROPERTY(int left READ left())
+ Q_PROPERTY(int top READ top())
+ Q_PROPERTY(int right READ right())
+ Q_PROPERTY(int bottom READ bottom())
+
+ QML_NAMED_ELEMENT(stylemargins)
+ QML_UNCREATABLE("")
+
+public:
+ QQuickStyleMargins() {}
+ QQuickStyleMargins(const QQuickStyleMargins &other) : m_margins(other.m_margins) {}
+ QQuickStyleMargins(const QMargins &margins) : m_margins(margins) {}
+ QQuickStyleMargins(const QRect &outer, const QRect &inner)
+ {
+ const int left = inner.left() - outer.left();
+ const int top = inner.top() - outer.top();
+ const int right = outer.right() - inner.right();
+ const int bottom = outer.bottom() - inner.bottom();
+ m_margins = QMargins(left, top, right, bottom);
+ }
+
+ inline void operator=(const QQuickStyleMargins &other) { m_margins = other.m_margins; }
+ inline bool operator==(const QQuickStyleMargins &other) const { return other.m_margins == m_margins; }
+ inline bool operator!=(const QQuickStyleMargins &other) const { return other.m_margins != m_margins; }
+
+ inline int left() const { return m_margins.left(); }
+ inline int right() const { return m_margins.right(); }
+ inline int top() const { return m_margins.top(); }
+ inline int bottom() const { return m_margins.bottom(); }
+
+ QMargins m_margins;
+};
+
+QDebug operator<<(QDebug debug, const QQuickStyleMargins &padding);
+
+struct StyleItemGeometry
+{
+ /*
+ A QQuickStyleItem is responsible for drawing a control, or a part of it.
+
+ 'minimumSize' should be the minimum possible size that the item can
+ have _without_ taking content size into consideration (and still render
+ correctly). This will also be the size of the image that the item is drawn
+ to, unless QQuickStyleItem::useNinePatchImage is set to false. In that
+ case, the size of the image will be set to the size of the item instead
+ (which is set from QML, and will typically be the same as the size of the control).
+ The default way to calculate minimumSize is to call style()->sizeFromContents()
+ with an empty content size. This is not always well supported by the legacy QStyle
+ implementation, which means that you might e.g get an empty size in return.
+ For those cases, the correct solution is to go into the specific platform style
+ and change it so that it returns a valid size also for this special case.
+
+ 'implicitSize' should reflect the preferred size of the item, taking the
+ given content size (as set from QML) into account. But not all controls
+ have contents (slider), and for many controls, the content/label is instead
+ placed outside the item/background image (radiobutton). In both cases, the
+ size of the item will not include the content size, and implicitSize can
+ usually be set equal to minimumSize instead.
+
+ 'contentRect' should be the free space where the contents can be placed. Note that
+ this rect doesn't need to have the same size as the contentSize provided as input
+ to the style item. Instead, QStyle can typically calculate a rect that is bigger, to
+ e.g center the contents inside the control.
+
+ 'layoutRect' can be set to shift the position of the whole control so
+ that aligns correctly with the other controls. This is important for
+ controls that draws e.g shadows or focus rings. Such adornments should
+ be painted, but not be included when aligning the controls.
+ */
+
+ QSize minimumSize;
+ QSize implicitSize;
+ QRect contentRect;
+ QRect layoutRect; // If invalid, there are no layout margins!
+ QMargins ninePatchMargins;
+ qreal focusFrameRadius;
+};
+
+QDebug operator<<(QDebug debug, const StyleItemGeometry &cg);
+
+class QQuickStyleItem : public QQuickItem
+{
+ Q_OBJECT
+
+ // Input
+ Q_PROPERTY(QQuickItem *control MEMBER m_control NOTIFY controlChanged)
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth)
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight)
+ Q_PROPERTY(bool useNinePatchImage MEMBER m_useNinePatchImage)
+ Q_PROPERTY(OverrideState overrideState MEMBER m_overrideState)
+
+ // Output
+ Q_PROPERTY(QQuickStyleMargins contentPadding READ contentPadding() NOTIFY contentPaddingChanged)
+ Q_PROPERTY(QQuickStyleMargins layoutMargins READ layoutMargins() NOTIFY layoutMarginsChanged)
+ Q_PROPERTY(QSize minimumSize READ minimumSize() NOTIFY minimumSizeChanged)
+ Q_PROPERTY(int transitionDuration MEMBER m_transitionDuration CONSTANT)
+
+ QML_NAMED_ELEMENT(StyleItem)
+ QML_UNCREATABLE("StyleItem is an abstract base class.")
+
+public:
+ enum DirtyFlag {
+ Nothing = 0,
+ Geometry,
+ Image,
+ Everything = 255
+ };
+ Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag)
+
+ enum OverrideState {
+ None = 0,
+ AlwaysHovered,
+ NeverHovered,
+ AlwaysSunken
+ };
+ Q_ENUM(OverrideState)
+
+
+#ifdef QT_DEBUG
+ enum DebugFlag {
+ NoDebug = 0x000,
+ Debug = 0x001,
+ Info = 0x002,
+ ImageRect = 0x004,
+ ContentRect = 0x008,
+ LayoutRect = 0x010,
+ Unscaled = 0x020,
+ InputContentSize = 0x040,
+ DontUseNinePatchImage = 0x080,
+ NinePatchMargins = 0x100,
+ SaveImage = 0x200,
+ };
+ Q_DECLARE_FLAGS(DebugFlags, DebugFlag)
+ Q_FLAG(DebugFlags)
+#endif
+
+ explicit QQuickStyleItem(QQuickItem *parent = nullptr);
+ ~QQuickStyleItem() override;
+
+ qreal contentWidth();
+ void setContentWidth(qreal contentWidth);
+ qreal contentHeight();
+ void setContentHeight(qreal contentHeight);
+
+ QQuickStyleMargins contentPadding() const;
+ QQuickStyleMargins layoutMargins() const;
+ QSize minimumSize() const;
+ QSize imageSize() const;
+ qreal focusFrameRadius() const;
+
+ Q_INVOKABLE virtual QFont styleFont(QQuickItem *control) const;
+
+ void markGeometryDirty();
+ void markImageDirty();
+
+signals:
+ void controlChanged();
+ void contentPaddingChanged();
+ void layoutMarginsChanged();
+ void fontChanged();
+ void minimumSizeChanged();
+
+protected:
+ void componentComplete() override;
+ QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void updatePolish() override;
+
+ virtual void connectToControl() const;
+ virtual void paintEvent(QPainter *painter) const = 0;
+ virtual StyleItemGeometry calculateGeometry() = 0;
+
+ static QStyle::State controlSize(QQuickItem *item);
+ void initStyleOptionBase(QStyleOption &styleOption) const;
+
+ inline QSize contentSize() const { return QSize(qCeil(m_contentSize.width()), qCeil(m_contentSize.height())); }
+ inline static QStyle *style() { return QQuickNativeStyle::style(); }
+
+ template <class T> inline const T* control() const {
+#ifdef QT_DEBUG
+ if (!dynamic_cast<T *>(m_control.data())) {
+ qmlWarning(this) << "control property is not of correct type";
+ Q_UNREACHABLE();
+ }
+#endif
+ return static_cast<T *>(m_control.data());
+ }
+
+#ifdef QT_DEBUG
+ DebugFlags m_debugFlags = NoDebug;
+#endif
+ OverrideState m_overrideState = None;
+
+private:
+ inline void updateGeometry();
+ inline void paintControlToImage();
+
+ int dprAlignedSize(const int size) const;
+
+#ifdef QT_DEBUG
+ void addDebugInfo();
+#endif
+
+private:
+ QPointer<QQuickItem> m_control;
+ QImage m_paintedImage;
+ StyleItemGeometry m_styleItemGeometry;
+ QSizeF m_contentSize;
+
+ DirtyFlags m_dirty = Everything;
+ bool m_useNinePatchImage = true;
+ bool m_polishing = false;
+ mutable QQuickWindow *m_connectedWindow = nullptr;
+
+#ifdef Q_OS_MACOS
+ int m_transitionDuration = 150;
+#else
+ int m_transitionDuration = 400;
+#endif
+
+private:
+ friend class QtQuickControls2MacOSStylePlugin;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickStyleItem::DirtyFlags)
+
+#ifdef QT_DEBUG
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickStyleItem::DebugFlags)
+#endif
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickStyleItem)
+
+#endif // QQUICKSTYLEITEM_H
diff --git a/src/quicknativestyle/items/qquickstyleitembutton.cpp b/src/quicknativestyle/items/qquickstyleitembutton.cpp
new file mode 100644
index 0000000000..0c2c72b920
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitembutton.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitembutton.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemButton::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_PushButtonLabel, controlSize(control));
+}
+
+void QQuickStyleItemButton::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto button = control<QQuickButton>();
+ connect(button, &QQuickButton::downChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(button, &QQuickButton::checkedChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemButton::calculateGeometry()
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_PushButton, &styleOption, QSize(0, 0));
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_PushButton, &styleOption, contentSize());
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subElementRect(QStyle::SE_PushButtonContents, &styleOption);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_PushButtonLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_PushButtonBevel, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_PushButtonFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemButton::paintEvent(QPainter *painter) const
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ style()->drawControl(QStyle::CE_PushButtonBevel, &styleOption, painter);
+}
+
+void QQuickStyleItemButton::initStyleOption(QStyleOptionButton &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto button = control<QQuickButton>();
+
+ if (button->isDown())
+ styleOption.state |= QStyle::State_Sunken;
+ if (!button->isFlat() && !button->isDown())
+ styleOption.state |= QStyle::State_Raised;
+ if (button->isHighlighted() || button->isChecked())
+ styleOption.state |= QStyle::State_On;
+ if (button->isFlat())
+ styleOption.features |= QStyleOptionButton::Flat;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitembutton.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitembutton.h b/src/quicknativestyle/items/qquickstyleitembutton.h
new file mode 100644
index 0000000000..517716702b
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitembutton.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMBUTTON_H
+#define QQUICKSTYLEITEMBUTTON_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemButton : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Button)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionButton &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMBUTTON_H
diff --git a/src/quicknativestyle/items/qquickstyleitemcheckbox.cpp b/src/quicknativestyle/items/qquickstyleitemcheckbox.cpp
new file mode 100644
index 0000000000..db07338cfe
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemcheckbox.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemcheckbox.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemCheckBox::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_RadioButtonLabel, controlSize(control));
+}
+
+void QQuickStyleItemCheckBox::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto checkbox = control<QQuickCheckBox>();
+ connect(checkbox, &QQuickCheckBox::downChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(checkbox, &QQuickCheckBox::checkStateChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemCheckBox::calculateGeometry()
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_CheckBox, &styleOption, QSize(0, 0));
+ geometry.implicitSize = geometry.minimumSize;
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subElementRect(QStyle::SE_CheckBoxContents, &styleOption);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_CheckBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_CheckBox, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_CheckBoxFocusFrameRadius, &styleOption);
+
+ // Spacing seems to already be baked into SE_CheckBoxContents, so ignore until needed
+ //const int space = style()->pixelMetric(QStyle::PM_CheckBoxLabelSpacing, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemCheckBox::paintEvent(QPainter *painter) const
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ style()->drawControl(QStyle::CE_CheckBox, &styleOption, painter);
+}
+
+void QQuickStyleItemCheckBox::initStyleOption(QStyleOptionButton &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto checkbox = control<QQuickCheckBox>();
+
+ styleOption.state |= checkbox->isDown() ? QStyle::State_Sunken : QStyle::State_Raised;
+ if (checkbox->isTristate() && checkbox->checkState() == Qt::PartiallyChecked)
+ styleOption.state |= QStyle::State_NoChange;
+ else
+ styleOption.state |= checkbox->isChecked() ? QStyle::State_On : QStyle::State_Off;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemcheckbox.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemcheckbox.h b/src/quicknativestyle/items/qquickstyleitemcheckbox.h
new file mode 100644
index 0000000000..74b1a4bc50
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemcheckbox.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMCHECKBOX_H
+#define QQUICKSTYLEITEMCHECKBOX_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickcheckbox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemCheckBox : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(CheckBox)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionButton &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMCHECKBOX_H
diff --git a/src/quicknativestyle/items/qquickstyleitemcombobox.cpp b/src/quicknativestyle/items/qquickstyleitemcombobox.cpp
new file mode 100644
index 0000000000..747576b513
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemcombobox.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemcombobox.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemComboBox::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_PushButtonLabel, controlSize(control));
+}
+
+void QQuickStyleItemComboBox::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto comboBox = control<QQuickComboBox>();
+ connect(comboBox, &QQuickComboBox::downChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemComboBox::calculateGeometry()
+{
+ QStyleOptionComboBox styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_ComboBox, &styleOption, QSize(0, 0));
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_ComboBox, &styleOption, contentSize());
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subControlRect(QStyle::CC_ComboBox, &styleOption, QStyle::SC_ComboBoxEditField);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_ComboBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_ComboBox, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_ComboBoxFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemComboBox::paintEvent(QPainter *painter) const
+{
+ QStyleOptionComboBox styleOption;
+ initStyleOption(styleOption);
+ style()->drawComplexControl(QStyle::CC_ComboBox, &styleOption, painter);
+}
+
+void QQuickStyleItemComboBox::initStyleOption(QStyleOptionComboBox &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto comboBox = control<QQuickComboBox>();
+
+ styleOption.subControls = QStyle::SC_ComboBoxArrow | QStyle::SC_ComboBoxFrame | QStyle::SC_ComboBoxEditField;
+ styleOption.frame = true;
+ styleOption.state |= QStyle::State_Selected;
+ styleOption.editable = comboBox->isEditable();
+
+ if (comboBox->isDown())
+ styleOption.state |= QStyle::State_Sunken;
+ if (!comboBox->isFlat() && !comboBox->isDown())
+ styleOption.state |= QStyle::State_Raised;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemcombobox.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemcombobox.h b/src/quicknativestyle/items/qquickstyleitemcombobox.h
new file mode 100644
index 0000000000..c417fae6e7
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemcombobox.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMCOMBOBOX_H
+#define QQUICKSTYLEITEMCOMBOBOX_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemComboBox : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ComboBox)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionComboBox &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMCOMBOBOX_H
diff --git a/src/quicknativestyle/items/qquickstyleitemdial.cpp b/src/quicknativestyle/items/qquickstyleitemdial.cpp
new file mode 100644
index 0000000000..a94ae68d76
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemdial.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemdial.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemDial::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ProgressBarLabel, controlSize(control));
+}
+
+void QQuickStyleItemDial::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto dial = control<QQuickDial>();
+ connect(dial, &QQuickDial::fromChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(dial, &QQuickDial::toChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(dial, &QQuickDial::positionChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(dial, &QQuickDial::valueChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(dial, &QQuickDial::stepSizeChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(dial, &QQuickDial::pressedChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemDial::calculateGeometry()
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_Dial, &styleOption, QSize(0, 0));
+ geometry.implicitSize = geometry.minimumSize;
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_SliderLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_Dial, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_DialFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemDial::paintEvent(QPainter *painter) const
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+ style()->drawComplexControl(QStyle::CC_Dial, &styleOption, painter);
+}
+
+void QQuickStyleItemDial::initStyleOption(QStyleOptionSlider &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto dial = control<QQuickDial>();
+
+ styleOption.subControls = QStyle::SC_SliderGroove | QStyle::SC_SliderHandle;
+ styleOption.activeSubControls = QStyle::SC_None;
+ styleOption.tickInterval = dial->stepSize();
+ styleOption.dialWrapping = dial->wrap();
+ styleOption.upsideDown = true;
+
+ if (dial->isPressed())
+ styleOption.state |= QStyle::State_Sunken;
+
+ if (dial->stepSize() == 0) {
+ styleOption.minimum = 0;
+ styleOption.maximum = 10000;
+ styleOption.sliderPosition = dial->position() * styleOption.maximum;
+ } else {
+ styleOption.minimum = dial->from();
+ styleOption.maximum = dial->to();
+ styleOption.sliderPosition = dial->value();
+ }
+
+ // TODO: add proper API for tickmarks
+ const int index = dial->metaObject()->indexOfProperty("qqc2_style_tickPosition");
+ if (index != -1) {
+ const int tickPosition = dial->metaObject()->property(index).read(dial).toInt();
+ styleOption.tickPosition = QStyleOptionSlider::TickPosition(tickPosition);
+ if (styleOption.tickPosition != QStyleOptionSlider::NoTicks)
+ styleOption.subControls |= QStyle::SC_DialTickmarks;
+ }
+
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemdial.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemdial.h b/src/quicknativestyle/items/qquickstyleitemdial.h
new file mode 100644
index 0000000000..5727919f27
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemdial.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMDIAL_H
+#define QQUICKSTYLEITEMDIAL_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickdial_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemDial : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Dial)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionSlider &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMDIAL_H
diff --git a/src/quicknativestyle/items/qquickstyleitemframe.cpp b/src/quicknativestyle/items/qquickstyleitemframe.cpp
new file mode 100644
index 0000000000..429b6a1dc0
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemframe.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemframe.h"
+
+QT_BEGIN_NAMESPACE
+
+StyleItemGeometry QQuickStyleItemFrame::calculateGeometry()
+{
+ QStyleOptionFrame styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_Frame, &styleOption, QSize(0, 0));
+ geometry.implicitSize = contentSize();
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subElementRect(QStyle::SE_FrameContents, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ShapedFrame, &styleOption, geometry.minimumSize);
+
+ return geometry;
+}
+
+void QQuickStyleItemFrame::paintEvent(QPainter *painter) const
+{
+ QStyleOptionFrame styleOption;
+ initStyleOption(styleOption);
+ style()->drawControl(QStyle::CE_ShapedFrame, &styleOption, painter);
+}
+
+void QQuickStyleItemFrame::initStyleOption(QStyleOptionFrame &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ styleOption.lineWidth = 1;
+ styleOption.frameShape = QStyleOptionFrame::StyledPanel;
+ styleOption.features = QStyleOptionFrame::Flat;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemframe.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemframe.h b/src/quicknativestyle/items/qquickstyleitemframe.h
new file mode 100644
index 0000000000..f44f070881
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemframe.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMFRAME_H
+#define QQUICKSTYLEITEMFRAME_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickframe_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemFrame : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Frame)
+
+protected:
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionFrame &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMFRAME_H
diff --git a/src/quicknativestyle/items/qquickstyleitemgroupbox.cpp b/src/quicknativestyle/items/qquickstyleitemgroupbox.cpp
new file mode 100644
index 0000000000..46cbfda459
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemgroupbox.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemgroupbox.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemGroupBox::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_HeaderLabel, controlSize(control));
+}
+
+StyleItemGeometry QQuickStyleItemGroupBox::calculateGeometry()
+{
+ QStyleOptionGroupBox styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_GroupBox, &styleOption, QSize(0, 0));
+
+ if (!control<QQuickGroupBox>()->title().isEmpty()) {
+ // We don't draw the title, but we need to take
+ // it into calculation for the control size
+ styleOption.text = QStringLiteral(" ");
+ styleOption.subControls |= QStyle::SC_GroupBoxLabel;
+ }
+
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_GroupBox, &styleOption, contentSize());
+ styleOption.rect.setSize(geometry.implicitSize);
+ geometry.contentRect = style()->subControlRect(QStyle::CC_GroupBox, &styleOption, QStyle::SC_GroupBoxContents);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_GroupBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_GroupBox, &styleOption, geometry.minimumSize);
+
+ const QQuickStyleMargins oldGroupBoxPadding = m_groupBoxPadding;
+ const QRect frame = style()->subControlRect(QStyle::CC_GroupBox, &styleOption, QStyle::SC_GroupBoxFrame);
+ m_groupBoxPadding = QQuickStyleMargins(QRect(QPoint(), geometry.implicitSize), frame);
+ if (m_groupBoxPadding != oldGroupBoxPadding)
+ emit groupBoxPaddingChanged();
+
+ const QPointF oldLabelPos = m_labelPos;
+ m_labelPos = style()->subControlRect(QStyle::CC_GroupBox, &styleOption, QStyle::SC_GroupBoxLabel).topLeft();
+ if (m_labelPos != oldLabelPos)
+ emit labelPosChanged();
+ return geometry;
+}
+
+void QQuickStyleItemGroupBox::paintEvent(QPainter *painter) const
+{
+ QStyleOptionGroupBox styleOption;
+ initStyleOption(styleOption);
+ style()->drawComplexControl(QStyle::CC_GroupBox, &styleOption, painter);
+}
+
+void QQuickStyleItemGroupBox::initStyleOption(QStyleOptionGroupBox &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ styleOption.subControls = QStyle::SC_GroupBoxFrame;
+ styleOption.lineWidth = 1;
+}
+
+QQuickStyleMargins QQuickStyleItemGroupBox::groupBoxPadding() const
+{
+ return m_groupBoxPadding;
+}
+
+QPointF QQuickStyleItemGroupBox::labelPos() const
+{
+ return m_labelPos;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemgroupbox.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemgroupbox.h b/src/quicknativestyle/items/qquickstyleitemgroupbox.h
new file mode 100644
index 0000000000..61ecf69d99
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemgroupbox.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMGROUPBOX_H
+#define QQUICKSTYLEITEMGROUPBOX_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickgroupbox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemGroupBox : public QQuickStyleItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickStyleMargins groupBoxPadding READ groupBoxPadding NOTIFY groupBoxPaddingChanged)
+ Q_PROPERTY(QPointF labelPos READ labelPos NOTIFY labelPosChanged)
+ QML_NAMED_ELEMENT(GroupBox)
+
+public:
+ QQuickStyleMargins groupBoxPadding() const;
+ QPointF labelPos() const;
+ QFont styleFont(QQuickItem *control) const override;
+
+signals:
+ void groupBoxPaddingChanged();
+ void labelPosChanged();
+
+protected:
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ QQuickStyleMargins m_groupBoxPadding;
+ QPointF m_labelPos;
+
+ void initStyleOption(QStyleOptionGroupBox &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMGROUPBOX_H
diff --git a/src/quicknativestyle/items/qquickstyleitemprogressbar.cpp b/src/quicknativestyle/items/qquickstyleitemprogressbar.cpp
new file mode 100644
index 0000000000..144b5723d5
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemprogressbar.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemprogressbar.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemProgressBar::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ProgressBarLabel, controlSize(control));
+}
+
+void QQuickStyleItemProgressBar::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto progressBar = control<QQuickProgressBar>();
+ connect(progressBar, &QQuickProgressBar::fromChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(progressBar, &QQuickProgressBar::toChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(progressBar, &QQuickProgressBar::positionChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemProgressBar::calculateGeometry()
+{
+ QStyleOptionProgressBar styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_ProgressBar, &styleOption, QSize(0, 0));
+
+ // From qprogressbar.cpp in qtbase:
+ const int cw = style()->pixelMetric(QStyle::PM_ProgressBarChunkWidth, &styleOption);
+ QFontMetrics fm(control<QQuickProgressBar>()->font());
+ QSize size = QSize(qMax(9, cw) * 7 + fm.horizontalAdvance(QLatin1Char('0')) * 4, fm.height() + 8);
+ if (!(styleOption.state & QStyle::State_Horizontal))
+ size = size.transposed();
+
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_ProgressBar, &styleOption, size);
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subElementRect(QStyle::SE_ProgressBarContents, &styleOption);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_ProgressBarLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ProgressBar, &styleOption, geometry.minimumSize);
+
+ return geometry;
+}
+
+void QQuickStyleItemProgressBar::paintEvent(QPainter *painter) const
+{
+ QStyleOptionProgressBar styleOption;
+ initStyleOption(styleOption);
+#ifndef Q_OS_MACOS
+ const QRect r = styleOption.rect;
+#endif
+ // Note: on macOS, the groove will paint both the background and the contents
+ styleOption.rect = style()->subElementRect(QStyle::SE_ProgressBarGroove, &styleOption);
+ style()->drawControl(QStyle::CE_ProgressBarGroove, &styleOption, painter);
+#ifndef Q_OS_MACOS
+ styleOption.rect = r;
+ styleOption.rect = style()->subElementRect(QStyle::SE_ProgressBarContents, &styleOption);
+ style()->drawControl(QStyle::CE_ProgressBarContents, &styleOption, painter);
+#endif
+}
+
+void QQuickStyleItemProgressBar::initStyleOption(QStyleOptionProgressBar &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto progressBar = control<QQuickProgressBar>();
+
+ styleOption.state = QStyle::State_Horizontal;
+
+ if (progressBar->isIndeterminate()) {
+ styleOption.minimum = 0;
+ styleOption.maximum = 0;
+ } else if (progressBar->to() - progressBar->from() < 100) {
+ // Add some range to support float numbers
+ styleOption.minimum = 0;
+ styleOption.maximum = (progressBar->to() - progressBar->from()) * 100;
+ styleOption.progress = (progressBar->value() - progressBar->from()) * 100;
+ } else {
+ styleOption.minimum = progressBar->from();
+ styleOption.maximum = progressBar->to();
+ styleOption.progress = progressBar->value();
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemprogressbar.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemprogressbar.h b/src/quicknativestyle/items/qquickstyleitemprogressbar.h
new file mode 100644
index 0000000000..572c41ed3f
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemprogressbar.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMPROGRESSBAR_H
+#define QQUICKSTYLEITEMPROGRESSBAR_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickprogressbar_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemProgressBar : public QQuickStyleItem
+{
+ Q_OBJECT
+
+ QML_NAMED_ELEMENT(ProgressBar)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionProgressBar &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMPROGRESSBAR_H
diff --git a/src/quicknativestyle/items/qquickstyleitemradiobutton.cpp b/src/quicknativestyle/items/qquickstyleitemradiobutton.cpp
new file mode 100644
index 0000000000..35704273af
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemradiobutton.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemradiobutton.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemRadioButton::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_RadioButtonLabel, controlSize(control));
+}
+
+void QQuickStyleItemRadioButton::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto checkbox = control<QQuickRadioButton>();
+ connect(checkbox, &QQuickRadioButton::downChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(checkbox, &QQuickRadioButton::checkedChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemRadioButton::calculateGeometry()
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_RadioButton, &styleOption, QSize(0, 0));
+ geometry.implicitSize = geometry.minimumSize;
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subElementRect(QStyle::SE_RadioButtonContents, &styleOption);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_RadioButtonLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_RadioButton, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_RadioButtonFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemRadioButton::paintEvent(QPainter *painter) const
+{
+ QStyleOptionButton styleOption;
+ initStyleOption(styleOption);
+ style()->drawControl(QStyle::CE_RadioButton, &styleOption, painter);
+}
+
+void QQuickStyleItemRadioButton::initStyleOption(QStyleOptionButton &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto checkbox = control<QQuickRadioButton>();
+
+ styleOption.state |= checkbox->isDown() ? QStyle::State_Sunken : QStyle::State_Raised;
+ styleOption.state |= checkbox->isChecked() ? QStyle::State_On : QStyle::State_Off;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemradiobutton.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemradiobutton.h b/src/quicknativestyle/items/qquickstyleitemradiobutton.h
new file mode 100644
index 0000000000..73aad8419c
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemradiobutton.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMRADIOBUTTON_H
+#define QQUICKSTYLEITEMRADIOBUTTON_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickradiobutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemRadioButton : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(RadioButton)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionButton &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMRADIOBUTTON_H
diff --git a/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp b/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp
new file mode 100644
index 0000000000..1ff90b2f19
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemscrollbar.cpp
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemscrollbar.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemScrollBar::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ProgressBarLabel, controlSize(control));
+}
+
+void QQuickStyleItemScrollBar::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto scrollBar = control<QQuickScrollBar>();
+ connect(scrollBar, &QQuickScrollBar::orientationChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(scrollBar, &QQuickScrollBar::pressedChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemScrollBar::calculateGeometry()
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_ScrollBar, &styleOption, QSize(0, 0));
+ if (m_subControl == SubLine || m_subControl == AddLine) {
+ // So far, we know that only the windows style uses these subcontrols,
+ // so we can use hardcoded sizes...
+ QSize sz(16, 17);
+ if (styleOption.orientation == Qt::Vertical)
+ sz.transpose();
+ geometry.minimumSize = sz;
+ }
+ geometry.implicitSize = geometry.minimumSize;
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_ScrollBarLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_ScrollBar, &styleOption, geometry.minimumSize);
+
+ return geometry;
+}
+
+void QQuickStyleItemScrollBar::paintEvent(QPainter *painter) const
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+ if (m_subControl == SubLine || m_subControl == AddLine) {
+ QStyle::SubControl sc = m_subControl == SubLine ? QStyle::SC_ScrollBarSubLine : QStyle::SC_ScrollBarAddLine;
+ QStyleOptionSlider opt = styleOption;
+ opt.subControls = QStyle::SC_ScrollBarAddLine
+ | QStyle::SC_ScrollBarSubLine
+ | QStyle::SC_ScrollBarGroove;
+
+ const qreal scale = window()->effectiveDevicePixelRatio();
+ const QSize scrollBarMinSize = style()->sizeFromContents(QStyle::CT_ScrollBar, &opt, QSize(0, 0));
+ const QSize sz = scrollBarMinSize * scale;
+ QImage scrollBarImage(sz, QImage::Format_ARGB32_Premultiplied);
+ scrollBarImage.setDevicePixelRatio(scale);
+ QPainter p(&scrollBarImage);
+ opt.rect = QRect(QPoint(0, 0), scrollBarMinSize);
+ style()->drawComplexControl(QStyle::CC_ScrollBar, &opt, &p);
+ QRect sourceImageRect = style()->subControlRect(QStyle::CC_ScrollBar, &opt, sc);
+ sourceImageRect = QRect(sourceImageRect.topLeft() * scale, sourceImageRect.size() * scale);
+ painter->drawImage(QPoint(0, 0), scrollBarImage, sourceImageRect);
+ } else {
+ style()->drawComplexControl(QStyle::CC_ScrollBar, &styleOption, painter);
+ }
+}
+
+void QQuickStyleItemScrollBar::initStyleOption(QStyleOptionSlider &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto scrollBar = control<QQuickScrollBar>();
+
+ switch (m_subControl) {
+ case Groove:
+ styleOption.subControls = QStyle::SC_ScrollBarGroove | QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine;
+ break;
+ case Handle:
+ styleOption.subControls = QStyle::SC_ScrollBarSlider;
+ break;
+ case AddLine:
+ styleOption.subControls = QStyle::SC_ScrollBarAddLine;
+ break;
+ case SubLine:
+ styleOption.subControls = QStyle::SC_ScrollBarSubLine;
+ break;
+ }
+
+ styleOption.activeSubControls = QStyle::SC_None;
+ styleOption.orientation = scrollBar->orientation();
+ if (styleOption.orientation == Qt::Horizontal)
+ styleOption.state |= QStyle::State_Horizontal;
+
+ if (scrollBar->isPressed())
+ styleOption.state |= QStyle::State_Sunken;
+
+ if (m_overrideState != None) {
+ // In ScrollBar.qml we fade between two versions of
+ // the handle, depending on if it's hovered or not
+
+ if (m_overrideState == AlwaysHovered) {
+ styleOption.activeSubControls = (styleOption.subControls & (QStyle::SC_ScrollBarSlider | QStyle::SC_ScrollBarGroove | QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine));
+ } else if (m_overrideState == NeverHovered) {
+ styleOption.activeSubControls &= ~(styleOption.subControls & (QStyle::SC_ScrollBarSlider | QStyle::SC_ScrollBarGroove | QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine));
+ } else if (m_overrideState == AlwaysSunken) {
+ styleOption.state |= QStyle::State_Sunken;
+ styleOption.activeSubControls = (styleOption.subControls & (QStyle::SC_ScrollBarSlider | QStyle::SC_ScrollBarGroove | QStyle::SC_ScrollBarAddLine | QStyle::SC_ScrollBarSubLine));
+ }
+ }
+
+ // The following values will let the handle fill 100% of the
+ // groove / imageSize. But when the handle is resized by
+ // QQuickScrollBar, it will end up with the correct size visually.
+ styleOption.pageStep = 1000;
+ styleOption.minimum = 0;
+ styleOption.maximum = 1;
+ styleOption.sliderValue = 0;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemscrollbar.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemscrollbar.h b/src/quicknativestyle/items/qquickstyleitemscrollbar.h
new file mode 100644
index 0000000000..31dc410044
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemscrollbar.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMSCROLLBAR_H
+#define QQUICKSTYLEITEMSCROLLBAR_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickscrollbar_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemScrollBar : public QQuickStyleItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(SubControl subControl MEMBER m_subControl)
+
+ QML_NAMED_ELEMENT(ScrollBar)
+
+public:
+ enum SubControl {
+ Groove = 1,
+ Handle,
+ AddLine,
+ SubLine
+ };
+ Q_ENUM(SubControl)
+
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionSlider &styleOption) const;
+
+private:
+ SubControl m_subControl = Groove;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMSCROLLBAR_H
diff --git a/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.cpp b/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.cpp
new file mode 100644
index 0000000000..ef12703b2d
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemscrollviewcorner.h"
+
+StyleItemGeometry QQuickStyleItemScrollViewCorner::calculateGeometry()
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+
+ // The size of the corner should be the width of the vertical
+ // scrollbar and the height of the horizontal scrollbar.
+ styleOption.orientation = Qt::Vertical;
+ const auto vScrollBarWidth = style()->sizeFromContents(QStyle::CT_ScrollBar, &styleOption, QSize(0, 0)).width();
+ styleOption.orientation = Qt::Horizontal;
+ const auto hScrollBarHeight = style()->sizeFromContents(QStyle::CT_ScrollBar, &styleOption, QSize(0, 0)).height();
+
+ geometry.minimumSize = QSize(vScrollBarWidth, hScrollBarHeight);
+ geometry.implicitSize = geometry.minimumSize;
+
+ return geometry;
+}
+
+void QQuickStyleItemScrollViewCorner::paintEvent(QPainter *painter) const
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+
+ // Grab a center piece of a vertical scrollbar groove onto a QImage, and use this
+ // image to draw a corner. We draw the corner by first drawing the piece as it is, and
+ // then rotate it 90 degrees, clip it into a triangle, and draw it once more on top.
+ // The result is that we end up with one vertical and one horizontal triangle that
+ // together form a filled corner rectangle.
+
+ styleOption.orientation = Qt::Vertical;
+
+ const qreal scale = window()->effectiveDevicePixelRatio();
+ const int grooveWidth = minimumSize().width();
+ const int grooveHeight = minimumSize().height();
+ const QSize scrollBarMinSize = style()->sizeFromContents(QStyle::CT_ScrollBar, &styleOption, QSize(0, 0));
+ const QSize scrollBarSize = scrollBarMinSize + QSize(0, grooveHeight);
+ const int hStart = scrollBarMinSize.height() / 2;
+ const QRect targetImageRect(0, hStart * scale, grooveWidth * scale, grooveHeight * scale);
+
+ QImage scrollBarImage(scrollBarSize * scale, QImage::Format_ARGB32_Premultiplied);
+ scrollBarImage.setDevicePixelRatio(scale);
+ scrollBarImage.fill(Qt::transparent);
+ QPainter scrollBarPainter(&scrollBarImage);
+ styleOption.rect = QRect(QPoint(0, 0), scrollBarSize);
+ style()->drawComplexControl(QStyle::CC_ScrollBar, &styleOption, &scrollBarPainter);
+
+ // Draw vertical groove
+ painter->drawImage(QPoint(0, 0), scrollBarImage, targetImageRect);
+
+ QPainterPath path;
+ path.moveTo(0, 0);
+ path.lineTo(0, grooveHeight);
+ path.lineTo(grooveWidth, grooveHeight);
+ path.closeSubpath();
+
+ QTransform transform;
+ transform.translate(grooveWidth, 0);
+ transform.rotate(90);
+
+ painter->save();
+ painter->setCompositionMode(QPainter::CompositionMode_Source);
+ painter->setClipPath(path);
+ painter->setTransform(transform);
+ // Draw horizontal groove, clipped to a triangle
+ painter->drawImage(QPoint(0, 0), scrollBarImage, targetImageRect);
+ painter->restore();
+}
+
+void QQuickStyleItemScrollViewCorner::initStyleOption(QStyleOptionSlider &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+
+ styleOption.subControls = QStyle::SC_ScrollBarGroove;
+ styleOption.activeSubControls = QStyle::SC_None;
+ styleOption.pageStep = 1000;
+ styleOption.minimum = 0;
+ styleOption.maximum = 1;
+ styleOption.sliderValue = 0;
+}
diff --git a/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.h b/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.h
new file mode 100644
index 0000000000..637a8ea821
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemscrollviewcorner.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMSCROLLVIEWCORNER_H
+#define QQUICKSTYLEITEMSCROLLVIEWCORNER_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickscrollbar_p.h>
+
+class QQuickStyleItemScrollViewCorner : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ScrollViewCorner)
+
+protected:
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionSlider &styleOption) const;
+};
+
+#endif // QQUICKSTYLEITEMSCROLLVIEWCORNER_H
diff --git a/src/quicknativestyle/items/qquickstyleitemslider.cpp b/src/quicknativestyle/items/qquickstyleitemslider.cpp
new file mode 100644
index 0000000000..03f567d6fc
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemslider.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemslider.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemSlider::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ProgressBarLabel, controlSize(control));
+}
+
+void QQuickStyleItemSlider::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto slider = control<QQuickSlider>();
+ connect(slider, &QQuickSlider::fromChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::toChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::positionChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::valueChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::stepSizeChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::pressedChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(slider, &QQuickSlider::orientationChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemSlider::calculateGeometry()
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+
+ StyleItemGeometry geometry;
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_Slider, &styleOption, QSize(0, 0));
+ geometry.implicitSize = geometry.minimumSize;
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_SliderLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_Slider, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_SliderFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemSlider::paintEvent(QPainter *painter) const
+{
+ QStyleOptionSlider styleOption;
+ initStyleOption(styleOption);
+ style()->drawComplexControl(QStyle::CC_Slider, &styleOption, painter);
+}
+
+void QQuickStyleItemSlider::initStyleOption(QStyleOptionSlider &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto slider = control<QQuickSlider>();
+
+ styleOption.subControls = QStyle::SC_None;
+ if (m_subControl & Groove)
+ styleOption.subControls |= QStyle::SC_SliderGroove;
+ if (m_subControl & Handle)
+ styleOption.subControls |= QStyle::SC_SliderHandle;
+ styleOption.activeSubControls = QStyle::SC_None;
+ styleOption.orientation = slider->orientation();
+
+ if (slider->isPressed())
+ styleOption.state |= QStyle::State_Sunken;
+
+ qreal min = 0;
+ qreal max = 1;
+ if (!qFuzzyIsNull(slider->stepSize())) {
+ min = slider->from();
+ max = slider->to();
+
+ // TODO: add proper API for tickmarks
+ const int index = slider->metaObject()->indexOfProperty("qqc2_style_tickPosition");
+ if (index != -1) {
+ const int tickPosition = slider->metaObject()->property(index).read(slider).toInt();
+ styleOption.tickPosition = QStyleOptionSlider::TickPosition(tickPosition);
+ if (styleOption.tickPosition != QStyleOptionSlider::NoTicks)
+ styleOption.subControls |= QStyle::SC_SliderTickmarks;
+ }
+ }
+
+ // Since the [from, to] interval in QQuickSlider is floating point, users can
+ // specify very small ranges and step sizes, (e.g. [0.., 0.25], step size 0.05).
+ // Since the style operates on ints, we cannot pass these values directly to the style,
+ // so we normalize all values to the range [0, 10000]
+ static const qreal Scale = 10000;
+ const qreal normalizeMultiplier = Scale/(max - min);
+ styleOption.tickInterval = int(slider->stepSize() * normalizeMultiplier);
+ styleOption.minimum = 0;
+ styleOption.maximum = int(Scale);
+ styleOption.sliderValue = int((slider->value() - min) * normalizeMultiplier);
+ styleOption.sliderPosition = int(slider->position() * styleOption.maximum);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemslider.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemslider.h b/src/quicknativestyle/items/qquickstyleitemslider.h
new file mode 100644
index 0000000000..0d86a65b87
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemslider.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMSLIDER_H
+#define QQUICKSTYLEITEMSLIDER_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickslider_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemSlider : public QQuickStyleItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(SubControl subControl MEMBER m_subControl)
+
+ QML_NAMED_ELEMENT(Slider)
+
+public:
+ enum SubControl {
+ Groove = 1,
+ Handle,
+ };
+ Q_ENUM(SubControl)
+
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionSlider &styleOption) const;
+
+private:
+ SubControl m_subControl = Groove;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMSLIDER_H
diff --git a/src/quicknativestyle/items/qquickstyleitemspinbox.cpp b/src/quicknativestyle/items/qquickstyleitemspinbox.cpp
new file mode 100644
index 0000000000..2f73da7db7
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemspinbox.cpp
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemspinbox.h"
+#include <QtQuickTemplates2/private/qquickindicatorbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemSpinBox::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ComboBoxLabel, controlSize(control));
+}
+
+void QQuickStyleItemSpinBox::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto spinbox = control<QQuickSpinBox>();
+ connect(spinbox->up(), &QQuickIndicatorButton::pressedChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(spinbox->down(), &QQuickIndicatorButton::pressedChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemSpinBox::calculateGeometry()
+{
+ QStyleOptionSpinBox styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_SpinBox, &styleOption, QSize(0, 0));
+
+ if (styleOption.subControls == QStyle::SC_SpinBoxFrame) {
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_SpinBox, &styleOption, contentSize());
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.contentRect = style()->subControlRect(QStyle::CC_SpinBox, &styleOption, QStyle::SC_SpinBoxEditField);
+ geometry.layoutRect = style()->subElementRect(QStyle::SE_SpinBoxLayoutItem, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CC_SpinBox, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_SpinBoxFocusFrameRadius, &styleOption);
+ } else {
+ geometry.implicitSize = geometry.minimumSize;
+ }
+
+ return geometry;
+}
+
+void QQuickStyleItemSpinBox::paintEvent(QPainter *painter) const
+{
+ QStyleOptionSpinBox styleOption;
+ initStyleOption(styleOption);
+ style()->drawComplexControl(QStyle::CC_SpinBox, &styleOption, painter);
+}
+
+void QQuickStyleItemSpinBox::initStyleOption(QStyleOptionSpinBox &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto spinbox = control<QQuickSpinBox>();
+
+ switch (m_subControl) {
+ case Frame:
+ styleOption.subControls = QStyle::SC_SpinBoxFrame;
+ styleOption.frame = true;
+ break;
+ case Up:
+ styleOption.subControls = (QStyle::SC_SpinBoxUp | QStyle::SC_SpinBoxDown);
+ break;
+ case Down:
+ styleOption.subControls = QStyle::SC_SpinBoxDown;
+ break;
+ }
+
+ if (spinbox->up()->isPressed()) {
+ styleOption.activeSubControls = QStyle::SC_SpinBoxUp;
+ styleOption.state |= QStyle::State_Sunken;
+ } else if (spinbox->down()->isPressed()) {
+ styleOption.activeSubControls = QStyle::SC_SpinBoxDown;
+ styleOption.state |= QStyle::State_Sunken;
+ }
+
+ styleOption.buttonSymbols = QStyleOptionSpinBox::UpDownArrows;
+ styleOption.stepEnabled = QStyleOptionSpinBox::StepEnabled;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemspinbox.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemspinbox.h b/src/quicknativestyle/items/qquickstyleitemspinbox.h
new file mode 100644
index 0000000000..9667d0ffed
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemspinbox.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMSPINBOX_H
+#define QQUICKSTYLEITEMSPINBOX_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquickspinbox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemSpinBox : public QQuickStyleItem
+{
+ Q_OBJECT
+
+ Q_PROPERTY(SubControl subControl MEMBER m_subControl)
+
+ QML_NAMED_ELEMENT(SpinBox)
+
+public:
+ enum SubControl {
+ Frame = 1,
+ Up,
+ Down,
+ };
+ Q_ENUM(SubControl)
+
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionSpinBox &styleOption) const;
+
+private:
+ SubControl m_subControl = Frame;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMSPINBOX_H
diff --git a/src/quicknativestyle/items/qquickstyleitemtextfield.cpp b/src/quicknativestyle/items/qquickstyleitemtextfield.cpp
new file mode 100644
index 0000000000..0b8ab37942
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemtextfield.cpp
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleitemtextfield.h"
+
+QT_BEGIN_NAMESPACE
+
+QFont QQuickStyleItemTextField::styleFont(QQuickItem *control) const
+{
+ return style()->font(QStyle::CE_ComboBoxLabel, controlSize(control));
+}
+
+void QQuickStyleItemTextField::connectToControl() const
+{
+ QQuickStyleItem::connectToControl();
+ auto textField = control<QQuickTextField>();
+ connect(textField, &QQuickTextField::readOnlyChanged, this, &QQuickStyleItem::markImageDirty);
+ connect(textField, &QQuickTextField::focusChanged, this, &QQuickStyleItem::markImageDirty);
+}
+
+StyleItemGeometry QQuickStyleItemTextField::calculateGeometry()
+{
+ QStyleOptionFrame styleOption;
+ initStyleOption(styleOption);
+ StyleItemGeometry geometry;
+
+ geometry.minimumSize = style()->sizeFromContents(QStyle::CT_LineEdit, &styleOption, QSize(0, 0));
+
+ // Inspired by QLineEdit::sizeHint()
+ QFontMetricsF fm(styleFont(const_cast<QQuickItem*>(control<QQuickItem>())));
+ const QSize sz(qCeil(fm.horizontalAdvance(QLatin1Char('x')) * 17),
+ contentSize().height());
+ geometry.implicitSize = style()->sizeFromContents(QStyle::CT_LineEdit, &styleOption, sz);
+
+ styleOption.rect = QRect(QPoint(0, 0), geometry.implicitSize);
+ geometry.layoutRect = styleOption.rect;
+ geometry.contentRect = style()->subElementRect(QStyle::SE_LineEditContents, &styleOption);
+ geometry.ninePatchMargins = style()->ninePatchMargins(QStyle::CE_ShapedFrame, &styleOption, geometry.minimumSize);
+ geometry.focusFrameRadius = style()->pixelMetric(QStyle::PM_TextFieldFocusFrameRadius, &styleOption);
+
+ return geometry;
+}
+
+void QQuickStyleItemTextField::paintEvent(QPainter *painter) const
+{
+ QStyleOptionFrame styleOption;
+ initStyleOption(styleOption);
+ style()->drawPrimitive(QStyle::PE_PanelLineEdit, &styleOption, painter);
+}
+
+void QQuickStyleItemTextField::initStyleOption(QStyleOptionFrame &styleOption) const
+{
+ initStyleOptionBase(styleOption);
+ auto textField = control<QQuickTextField>();
+
+ styleOption.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &styleOption);
+ styleOption.midLineWidth = 0;
+ styleOption.state |= QStyle::State_Sunken;
+ if (textField->isReadOnly())
+ styleOption.state |= QStyle::State_ReadOnly;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyleitemtextfield.cpp"
diff --git a/src/quicknativestyle/items/qquickstyleitemtextfield.h b/src/quicknativestyle/items/qquickstyleitemtextfield.h
new file mode 100644
index 0000000000..9f6b66b729
--- /dev/null
+++ b/src/quicknativestyle/items/qquickstyleitemtextfield.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTYLEITEMTEXTFIELD_H
+#define QQUICKSTYLEITEMTEXTFIELD_H
+
+#include "qquickstyleitem.h"
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStyleItemTextField : public QQuickStyleItem
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(TextField)
+
+public:
+ QFont styleFont(QQuickItem *control) const override;
+
+protected:
+ void connectToControl() const override;
+ void paintEvent(QPainter *painter) const override;
+ StyleItemGeometry calculateGeometry() override;
+
+private:
+ void initStyleOption(QStyleOptionFrame &styleOption) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTYLEITEMTEXTFIELD_H
diff --git a/src/quicknativestyle/qstyle/mac/mac.pri b/src/quicknativestyle/qstyle/mac/mac.pri
new file mode 100644
index 0000000000..2f7ee7d436
--- /dev/null
+++ b/src/quicknativestyle/qstyle/mac/mac.pri
@@ -0,0 +1,12 @@
+LIBS_PRIVATE += -framework AppKit
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qquickmacstyle_mac_p.h \
+ $$PWD/qquickmacstyle_mac_p_p.h
+
+SOURCES +=
+
+OBJECTIVE_SOURCES += \
+ $$PWD/qquickmacstyle_mac.mm
diff --git a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm
new file mode 100644
index 0000000000..0e2f96183f
--- /dev/null
+++ b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac.mm
@@ -0,0 +1,6063 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*
+ Note: The qdoc comments for QMacStyle are contained in
+ .../doc/src/qstyles.qdoc.
+*/
+
+#include <AppKit/AppKit.h>
+
+#include "qquickmacstyle_mac_p.h"
+#include "qquickmacstyle_mac_p_p.h"
+#include "qquickstylehelper_p.h"
+
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+#define QMAC_QAQUASTYLE_SIZE_CONSTRAIN
+//#define DEBUG_SIZE_CONSTRAINT
+
+#include <QtCore/qoperatingsystemversion.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <QtGui/qpainterpath.h>
+#include <QtGui/qpa/qplatformnativeinterface.h>
+#include <QtGui/qpa/qplatformfontdatabase.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qcoregraphics_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <cmath>
+
+QT_USE_NAMESPACE
+
+// OBS! Changing QT_MANGLE_NAMESPACE and QT_NAMESPACE_ALIAS_OBJC_CLASS to take
+// both QT_NAMESPACE and QQC2_NAMESPACE into account (and not only QT_NAMESPACE, which
+// would otherwise be the case). This will make it possible to link in both widgets and
+// controls in the same application when building statically.
+#undef QT_MANGLE_NAMESPACE
+#undef QT_NAMESPACE_ALIAS_OBJC_CLASS
+
+#define QQC2_MANGLE1(a, b) a##_##b
+#define QQC2_MANGLE2(a, b) QQC2_MANGLE1(a, b)
+
+#if defined(QT_NAMESPACE)
+ #define QT_MANGLE_NAMESPACE(name) QQC2_MANGLE2(QQC2_MANGLE1(name, QQC2_NAMESPACE), QT_NAMESPACE)
+ #define QT_NAMESPACE_ALIAS_OBJC_CLASS(name) @compatibility_alias name QT_MANGLE_NAMESPACE(name)
+#else
+ #define QT_MANGLE_NAMESPACE(name) QQC2_MANGLE2(name, QQC2_NAMESPACE)
+ #define QT_NAMESPACE_ALIAS_OBJC_CLASS(name) @compatibility_alias name QT_MANGLE_NAMESPACE(name)
+#endif
+
+@interface QT_MANGLE_NAMESPACE(QIndeterminateProgressIndicator) : NSProgressIndicator
+
+@property (readonly, nonatomic) NSInteger animators;
+
+- (instancetype)init;
+
+- (void)startAnimation;
+- (void)stopAnimation;
+
+- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view;
+
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QIndeterminateProgressIndicator);
+
+@implementation QIndeterminateProgressIndicator
+
+- (instancetype)init
+{
+ if ((self = [super init])) {
+ _animators = 0;
+ self.indeterminate = YES;
+ self.usesThreadedAnimation = NO;
+ self.alphaValue = 0.0;
+ }
+
+ return self;
+}
+
+- (void)startAnimation
+{
+ if (_animators == 0) {
+ self.hidden = NO;
+ [super startAnimation:self];
+ }
+ ++_animators;
+}
+
+- (void)stopAnimation
+{
+ --_animators;
+ if (_animators == 0) {
+ [super stopAnimation:self];
+ self.hidden = YES;
+ [self removeFromSuperviewWithoutNeedingDisplay];
+ }
+}
+
+- (void)drawWithFrame:(CGRect)rect inView:(NSView *)view
+{
+ // The alphaValue change is not strictly necessary, but feels safer.
+ self.alphaValue = 1.0;
+ if (self.superview != view)
+ [view addSubview:self];
+ if (!CGRectEqualToRect(self.frame, rect))
+ self.frame = rect;
+ [self drawRect:rect];
+ self.alphaValue = 0.0;
+}
+
+@end
+
+@interface QT_MANGLE_NAMESPACE(QVerticalSplitView) : NSSplitView
+- (BOOL)isVertical;
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QVerticalSplitView);
+
+@implementation QVerticalSplitView
+- (BOOL)isVertical
+{
+ return YES;
+}
+@end
+
+// See render code in drawPrimitive(PE_FrameTabWidget)
+@interface QT_MANGLE_NAMESPACE(QDarkNSBox) : NSBox
+@end
+
+QT_NAMESPACE_ALIAS_OBJC_CLASS(QDarkNSBox);
+
+@implementation QDarkNSBox
+- (instancetype)init
+{
+ if ((self = [super init])) {
+ self.title = @"";
+ self.titlePosition = NSNoTitle;
+ self.boxType = NSBoxCustom;
+ self.cornerRadius = 3;
+ self.borderColor = [NSColor.controlColor colorWithAlphaComponent:0.1];
+ self.fillColor = [NSColor.darkGrayColor colorWithAlphaComponent:0.2];
+ }
+
+ return self;
+}
+
+- (void)drawRect:(NSRect)rect
+{
+ [super drawRect:rect];
+}
+@end
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2_NAMESPACE {
+
+// The following constants are used for adjusting the size
+// of push buttons so that they are drawn inside their bounds.
+const int QMacStylePrivate::PushButtonLeftOffset = 6;
+const int QMacStylePrivate::PushButtonRightOffset = 12;
+const int QMacStylePrivate::PushButtonContentPadding = 6;
+
+QVector<QPointer<QObject> > QMacStylePrivate::scrollBars;
+
+// Title bar gradient colors for Lion were determined by inspecting PSDs exported
+// using CoreUI's CoreThemeDocument; there is no public API to retrieve them
+
+static QLinearGradient titlebarGradientActive()
+{
+ static QLinearGradient darkGradient = [](){
+ QLinearGradient gradient;
+ // FIXME: colors are chosen somewhat arbitrarily and could be fine-tuned,
+ // or ideally determined by calling a native API.
+ gradient.setColorAt(0, QColor(47, 47, 47));
+ return gradient;
+ }();
+ static QLinearGradient lightGradient = [](){
+ QLinearGradient gradient;
+ gradient.setColorAt(0, QColor(235, 235, 235));
+ gradient.setColorAt(0.5, QColor(210, 210, 210));
+ gradient.setColorAt(0.75, QColor(195, 195, 195));
+ gradient.setColorAt(1, QColor(180, 180, 180));
+ return gradient;
+ }();
+ return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
+}
+
+static QLinearGradient titlebarGradientInactive()
+{
+ static QLinearGradient darkGradient = [](){
+ QLinearGradient gradient;
+ gradient.setColorAt(1, QColor(42, 42, 42));
+ return gradient;
+ }();
+ static QLinearGradient lightGradient = [](){
+ QLinearGradient gradient;
+ gradient.setColorAt(0, QColor(250, 250, 250));
+ gradient.setColorAt(1, QColor(225, 225, 225));
+ return gradient;
+ }();
+ return qt_mac_applicationIsInDarkMode() ? darkGradient : lightGradient;
+}
+
+/*
+ Since macOS 10.14 AppKit is using transparency more extensively, especially for the
+ dark theme. Inactive buttons, for example, are semi-transparent. And we use them to
+ draw tab widget's tab bar. The combination of NSBox (also a part of tab widget)
+ and these transparent buttons gives us an undesired side-effect: an outline of
+ NSBox is visible through transparent buttons. To avoid this, we have this hack below:
+ we clip the area where the line would be visible through the buttons. The area we
+ want to clip away can be described as an intersection of the option's rect and
+ the tab widget's tab bar rect. But some adjustments are required, since those rects
+ are anyway adjusted during the rendering and they are not exactly what you'll see on
+ the screen. Thus this switch-statement inside.
+*/
+static void clipTabBarFrame(const QStyleOption *option, const QMacStyle *style, CGContextRef ctx)
+{
+ Q_ASSERT(option);
+ Q_ASSERT(style);
+ Q_ASSERT(ctx);
+
+ if (qt_mac_applicationIsInDarkMode()) {
+// QTabWidget *tabWidget = qobject_cast<QTabWidget *>(option->styleObject);
+// Q_ASSERT(tabWidget);
+
+// QRect tabBarRect = style->subElementRect(QStyle::SE_TabWidgetTabBar, option, tabWidget).adjusted(2, 0, -3, 0);
+// switch (tabWidget->tabPosition()) {
+// case QTabWidget::South:
+// tabBarRect.setY(tabBarRect.y() + tabBarRect.height() / 2);
+// break;
+// case QTabWidget::North:
+// case QTabWidget::West:
+// tabBarRect = tabBarRect.adjusted(0, 2, 0, -2);
+// break;
+// case QTabWidget::East:
+// tabBarRect = tabBarRect.adjusted(tabBarRect.width() / 2, 2, tabBarRect.width() / 2, -2);
+// }
+
+// const QRegion clipPath = QRegion(option->rect) - tabBarRect;
+// QVarLengthArray<CGRect, 3> cgRects;
+// for (const QRect &qtRect : clipPath)
+// cgRects.push_back(qtRect.toCGRect());
+// if (cgRects.size())
+// CGContextClipToRects(ctx, &cgRects[0], size_t(cgRects.size()));
+ }
+}
+
+static const QColor titlebarSeparatorLineActive(111, 111, 111);
+static const QColor titlebarSeparatorLineInactive(131, 131, 131);
+static const QColor darkModeSeparatorLine(88, 88, 88);
+
+// Gradient colors used for the dock widget title bar and
+// non-unifed tool bar background.
+static const QColor lightMainWindowGradientBegin(240, 240, 240);
+static const QColor lightMainWindowGradientEnd(200, 200, 200);
+static const QColor darkMainWindowGradientBegin(47, 47, 47);
+static const QColor darkMainWindowGradientEnd(47, 47, 47);
+
+static const int DisclosureOffset = 4;
+
+static const qreal titleBarIconTitleSpacing = 5;
+static const qreal titleBarTitleRightMargin = 12;
+static const qreal titleBarButtonSpacing = 8;
+
+// Tab bar colors
+// active: window is active
+// selected: tab is selected
+// hovered: tab is hovered
+bool isDarkMode() { return qt_mac_applicationIsInDarkMode(); }
+
+static const QColor lightTabBarTabBackgroundActive(190, 190, 190);
+static const QColor darkTabBarTabBackgroundActive(38, 38, 38);
+static const QColor tabBarTabBackgroundActive() { return isDarkMode() ? darkTabBarTabBackgroundActive : lightTabBarTabBackgroundActive; }
+
+static const QColor lightTabBarTabBackgroundActiveHovered(178, 178, 178);
+static const QColor darkTabBarTabBackgroundActiveHovered(32, 32, 32);
+static const QColor tabBarTabBackgroundActiveHovered() { return isDarkMode() ? darkTabBarTabBackgroundActiveHovered : lightTabBarTabBackgroundActiveHovered; }
+
+static const QColor lightTabBarTabBackgroundActiveSelected(211, 211, 211);
+static const QColor darkTabBarTabBackgroundActiveSelected(52, 52, 52);
+static const QColor tabBarTabBackgroundActiveSelected() { return isDarkMode() ? darkTabBarTabBackgroundActiveSelected : lightTabBarTabBackgroundActiveSelected; }
+
+static const QColor lightTabBarTabBackground(227, 227, 227);
+static const QColor darkTabBarTabBackground(38, 38, 38);
+static const QColor tabBarTabBackground() { return isDarkMode() ? darkTabBarTabBackground : lightTabBarTabBackground; }
+
+static const QColor lightTabBarTabBackgroundSelected(246, 246, 246);
+static const QColor darkTabBarTabBackgroundSelected(52, 52, 52);
+static const QColor tabBarTabBackgroundSelected() { return isDarkMode() ? darkTabBarTabBackgroundSelected : lightTabBarTabBackgroundSelected; }
+
+static const QColor lightTabBarTabLineActive(160, 160, 160);
+static const QColor darkTabBarTabLineActive(90, 90, 90);
+static const QColor tabBarTabLineActive() { return isDarkMode() ? darkTabBarTabLineActive : lightTabBarTabLineActive; }
+
+static const QColor lightTabBarTabLineActiveHovered(150, 150, 150);
+static const QColor darkTabBarTabLineActiveHovered(90, 90, 90);
+static const QColor tabBarTabLineActiveHovered() { return isDarkMode() ? darkTabBarTabLineActiveHovered : lightTabBarTabLineActiveHovered; }
+
+static const QColor lightTabBarTabLine(210, 210, 210);
+static const QColor darkTabBarTabLine(90, 90, 90);
+static const QColor tabBarTabLine() { return isDarkMode() ? darkTabBarTabLine : lightTabBarTabLine; }
+
+static const QColor lightTabBarTabLineSelected(189, 189, 189);
+static const QColor darkTabBarTabLineSelected(90, 90, 90);
+static const QColor tabBarTabLineSelected() { return isDarkMode() ? darkTabBarTabLineSelected : lightTabBarTabLineSelected; }
+
+static const QColor tabBarCloseButtonBackgroundHovered(162, 162, 162);
+static const QColor tabBarCloseButtonBackgroundPressed(153, 153, 153);
+static const QColor tabBarCloseButtonBackgroundSelectedHovered(192, 192, 192);
+static const QColor tabBarCloseButtonBackgroundSelectedPressed(181, 181, 181);
+static const QColor tabBarCloseButtonCross(100, 100, 100);
+static const QColor tabBarCloseButtonCrossSelected(115, 115, 115);
+
+static const int closeButtonSize = 14;
+static const qreal closeButtonCornerRadius = 2.0;
+
+#ifndef QT_NO_ACCESSIBILITY // This ifdef to avoid "unused function" warning.
+QBrush brushForToolButton(bool isOnKeyWindow)
+{
+ // When a toolbutton in a toolbar is in the 'ON' state, we draw a
+ // partially transparent background. The colors must be different
+ // for 'Aqua' and 'DarkAqua' appearances though.
+ if (isDarkMode())
+ return isOnKeyWindow ? QColor(73, 73, 73, 100) : QColor(56, 56, 56, 100);
+
+ return isOnKeyWindow ? QColor(0, 0, 0, 28) : QColor(0, 0, 0, 21);
+}
+#endif // QT_NO_ACCESSIBILITY
+
+static const int headerSectionArrowHeight = 6;
+static const int headerSectionSeparatorInset = 2;
+
+// One for each of QStyleHelper::WidgetSizePolicy
+static const QMarginsF comboBoxFocusRingMargins[3] = {
+ { 0.5, 2, 3.5, 4 },
+ { 0.5, 1, 2.5, 4 },
+ { 0.5, 1.5, 2.5, 3.5 }
+};
+
+static const QMarginsF pullDownButtonShadowMargins[3] = {
+ { 0.5, -1, 0.5, 2 },
+ { 0.5, -1.5, 0.5, 2.5 },
+ { 0.5, 0, 0.5, 1 }
+};
+
+static const QMarginsF pushButtonShadowMargins[3] = {
+ { 1.5, -1.5, 1.5, 4.5 },
+ { 1.5, -1, 1.5, 4 },
+ { 1.5, 0.5, 1.5, 2.5 }
+};
+
+// These are frame heights as reported by Xcode 9's Interface Builder.
+// Alignemnet rectangle's heights match for push and popup buttons
+// with respective values 21, 18 and 15.
+
+static const qreal comboBoxDefaultHeight[3] = {
+ 26, 22, 19
+};
+
+static const qreal pushButtonDefaultHeight[3] = {
+ 32, 28, 16
+};
+
+static const qreal popupButtonDefaultHeight[3] = {
+ 26, 22, 15
+};
+
+static const int toolButtonArrowSize = 7;
+static const int toolButtonArrowMargin = 2;
+
+static const qreal focusRingWidth = 3.5;
+
+// An application can force 'Aqua' theme while the system theme is one of
+// the 'Dark' variants. Since in Qt we sometimes use NSControls and even
+// NSCells directly without attaching them to any view hierarchy, we have
+// to set NSAppearance.currentAppearance to 'Aqua' manually, to make sure
+// the correct rendering path is triggered. Apple recommends us to un-set
+// the current appearance back after we finished with drawing. This is what
+// AppearanceSync is for.
+
+class AppearanceSync {
+public:
+ AppearanceSync()
+ {
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
+ && !qt_mac_applicationIsInDarkMode()) {
+ auto requiredAppearanceName = NSApplication.sharedApplication.effectiveAppearance.name;
+ if (![NSAppearance.currentAppearance.name isEqualToString:requiredAppearanceName]) {
+ previous = NSAppearance.currentAppearance;
+ NSAppearance.currentAppearance = [NSAppearance appearanceNamed:requiredAppearanceName];
+ }
+ }
+#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ }
+
+ ~AppearanceSync()
+ {
+ if (previous)
+ NSAppearance.currentAppearance = previous;
+ }
+
+private:
+ NSAppearance *previous = nil;
+
+ Q_DISABLE_COPY(AppearanceSync)
+};
+
+static bool setupScroller(NSScroller *scroller, const QStyleOptionSlider *sb)
+{
+ const qreal length = sb->maximum - sb->minimum + sb->pageStep;
+ if (qFuzzyIsNull(length))
+ return false;
+ const qreal proportion = sb->pageStep / length;
+ const qreal range = qreal(sb->maximum - sb->minimum);
+ qreal value = range ? qreal(sb->sliderValue - sb->minimum) / range : 0;
+ if (sb->orientation == Qt::Horizontal && sb->direction == Qt::RightToLeft)
+ value = 1.0 - value;
+
+ scroller.frame = sb->rect.toCGRect();
+ scroller.floatValue = value;
+ scroller.knobProportion = proportion;
+ return true;
+}
+
+static bool setupSlider(NSSlider *slider, const QStyleOptionSlider *sl)
+{
+ if (sl->minimum >= sl->maximum)
+ return false;
+
+ // NSSlider seems to cache values based on tracking and the last layout of the
+ // NSView, resulting in incorrect knob rects that break the interaction with
+ // multiple sliders. So completely reinitialize the slider.
+ [slider initWithFrame:sl->rect.toCGRect()];
+
+ slider.minValue = sl->minimum;
+ slider.maxValue = sl->maximum;
+ slider.intValue = sl->sliderPosition;
+ slider.enabled = sl->state & QStyle::State_Enabled;
+ if (sl->tickPosition != QStyleOptionSlider::NoTicks) {
+ // Set numberOfTickMarks, but TicksBothSides will be treated differently
+ int interval = sl->tickInterval;
+ if (interval == 0) {
+ interval = sl->pageStep;
+ if (interval == 0)
+ interval = sl->singleStep;
+ if (interval == 0)
+ interval = 1; // return false?
+ }
+ slider.numberOfTickMarks = 1 + ((sl->maximum - sl->minimum) / interval);
+
+ const bool ticksAbove = sl->tickPosition == QStyleOptionSlider::TicksAbove;
+ if (sl->orientation == Qt::Horizontal)
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionAbove : NSTickMarkPositionBelow;
+ else
+ slider.tickMarkPosition = ticksAbove ? NSTickMarkPositionLeading : NSTickMarkPositionTrailing;
+ } else {
+ slider.numberOfTickMarks = 0;
+ }
+
+ // Ensure the values set above are reflected when asking
+ // the cell for its metrics and to draw itself.
+ [slider layoutSubtreeIfNeeded];
+
+ if (sl->state & QStyle::State_Sunken) {
+ const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
+ CGPoint pressPoint;
+ pressPoint.x = CGRectGetMidX(knobRect);
+ pressPoint.y = CGRectGetMidY(knobRect);
+ [slider.cell startTrackingAt:pressPoint inView:slider];
+ }
+
+ return true;
+}
+
+static bool isInMacUnifiedToolbarArea(QWindow *window, int windowY)
+{
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ QPlatformNativeInterface::NativeResourceForIntegrationFunction function =
+ nativeInterface->nativeResourceFunctionForIntegration("testContentBorderPosition");
+ if (!function)
+ return false; // Not Cocoa platform plugin.
+
+ typedef bool (*TestContentBorderPositionFunction)(QWindow *, int);
+ return (reinterpret_cast<TestContentBorderPositionFunction>(function))(window, windowY);
+}
+
+
+static void drawTabCloseButton(QPainter *p, bool hover, bool selected, bool pressed, bool documentMode)
+{
+ p->setRenderHints(QPainter::Antialiasing);
+ QRect rect(0, 0, closeButtonSize, closeButtonSize);
+ const int width = rect.width();
+ const int height = rect.height();
+
+ if (hover) {
+ // draw background circle
+ QColor background;
+ if (selected) {
+ if (documentMode)
+ background = pressed ? tabBarCloseButtonBackgroundSelectedPressed : tabBarCloseButtonBackgroundSelectedHovered;
+ else
+ background = QColor(255, 255, 255, pressed ? 150 : 100); // Translucent white
+ } else {
+ background = pressed ? tabBarCloseButtonBackgroundPressed : tabBarCloseButtonBackgroundHovered;
+ if (!documentMode)
+ background = background.lighter(pressed ? 135 : 140); // Lighter tab background, lighter color
+ }
+
+ p->setPen(Qt::transparent);
+ p->setBrush(background);
+ p->drawRoundedRect(rect, closeButtonCornerRadius, closeButtonCornerRadius);
+ }
+
+ // draw cross
+ const int margin = 3;
+ QPen crossPen;
+ crossPen.setColor(selected ? (documentMode ? tabBarCloseButtonCrossSelected : Qt::white) : tabBarCloseButtonCross);
+ crossPen.setWidthF(1.1);
+ crossPen.setCapStyle(Qt::FlatCap);
+ p->setPen(crossPen);
+ p->drawLine(margin, margin, width - margin, height - margin);
+ p->drawLine(margin, height - margin, width - margin, margin);
+}
+
+QRect rotateTabPainter(QPainter *p, QStyleOptionTab::Shape shape, QRect tabRect)
+{
+ const auto tabDirection = QMacStylePrivate::tabDirection(shape);
+ if (QMacStylePrivate::verticalTabs(tabDirection)) {
+ int newX, newY, newRot;
+ if (tabDirection == QMacStylePrivate::East) {
+ newX = tabRect.width();
+ newY = tabRect.y();
+ newRot = 90;
+ } else {
+ newX = 0;
+ newY = tabRect.y() + tabRect.height();
+ newRot = -90;
+ }
+ tabRect.setRect(0, 0, tabRect.height(), tabRect.width());
+ QTransform transform;
+ transform.translate(newX, newY);
+ transform.rotate(newRot);
+ p->setTransform(transform, true);
+ }
+ return tabRect;
+}
+
+void drawTabShape(QPainter *p, const QStyleOptionTab *tabOpt, bool isUnified, int tabOverlap)
+{
+ QRect rect = tabOpt->rect;
+ if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tabOpt->shape)))
+ rect = rect.adjusted(-tabOverlap, 0, 0, 0);
+ else
+ rect = rect.adjusted(0, -tabOverlap, 0, 0);
+
+ p->translate(rect.x(), rect.y());
+ rect.moveLeft(0);
+ rect.moveTop(0);
+ const QRect tabRect = rotateTabPainter(p, tabOpt->shape, rect);
+
+ const int width = tabRect.width();
+ const int height = tabRect.height();
+ const bool active = (tabOpt->state & QStyle::State_Active);
+ const bool selected = (tabOpt->state & QStyle::State_Selected);
+
+ const QRect bodyRect(1, 2, width - 2, height - 3);
+ const QRect topLineRect(1, 0, width - 2, 1);
+ const QRect bottomLineRect(1, height - 1, width - 2, 1);
+ if (selected) {
+ // fill body
+ if (tabOpt->documentMode && isUnified) {
+ p->save();
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->fillRect(tabRect, QColor(Qt::transparent));
+ p->restore();
+ } else if (active) {
+ p->fillRect(bodyRect, tabBarTabBackgroundActiveSelected());
+ // top line
+ p->fillRect(topLineRect, tabBarTabLineSelected());
+ } else {
+ p->fillRect(bodyRect, tabBarTabBackgroundSelected());
+ }
+ } else {
+ // when the mouse is over non selected tabs they get a new color
+ const bool hover = (tabOpt->state & QStyle::State_MouseOver);
+ if (hover) {
+ // fill body
+ p->fillRect(bodyRect, tabBarTabBackgroundActiveHovered());
+ // bottom line
+ p->fillRect(bottomLineRect, isDarkMode() ? QColor(Qt::black) : tabBarTabLineActiveHovered());
+ }
+ }
+
+ // separator lines between tabs
+ const QRect leftLineRect(0, 1, 1, height - 2);
+ const QRect rightLineRect(width - 1, 1, 1, height - 2);
+ const QColor separatorLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
+ p->fillRect(leftLineRect, separatorLineColor);
+ p->fillRect(rightLineRect, separatorLineColor);
+}
+
+void drawTabBase(QPainter *p, const QStyleOptionTabBarBase *tbb)
+{
+ QRect r = tbb->rect;
+// if (QMacStylePrivate::verticalTabs(QMacStylePrivate::tabDirection(tbb->shape)))
+// r.setWidth(w->width());
+// else
+// r.setHeight(w->height());
+
+ const QRect tabRect = rotateTabPainter(p, tbb->shape, r);
+ const int width = tabRect.width();
+ const int height = tabRect.height();
+ const bool active = (tbb->state & QStyle::State_Active);
+
+ // fill body
+ const QRect bodyRect(0, 1, width, height - 1);
+ const QColor bodyColor = active ? tabBarTabBackgroundActive() : tabBarTabBackground();
+ p->fillRect(bodyRect, bodyColor);
+
+ // top line
+ const QRect topLineRect(0, 0, width, 1);
+ const QColor topLineColor = active ? tabBarTabLineActive() : tabBarTabLine();
+ p->fillRect(topLineRect, topLineColor);
+
+ // bottom line
+ const QRect bottomLineRect(0, height - 1, width, 1);
+ bool isDocument = false;
+// if (const QTabBar *tabBar = qobject_cast<const QTabBar*>(w))
+// isDocument = tabBar->documentMode();
+ const QColor bottomLineColor = isDocument && isDarkMode() ? QColor(Qt::black) : active ? tabBarTabLineActive() : tabBarTabLine();
+ p->fillRect(bottomLineRect, bottomLineColor);
+}
+
+static QStyleHelper::WidgetSizePolicy getControlSize(const QStyleOption *option)
+{
+ const auto wsp = QStyleHelper::widgetSizePolicy(option);
+ if (wsp == QStyleHelper::SizeDefault)
+ return QStyleHelper::SizeLarge;
+
+ return wsp;
+}
+
+static QString qt_mac_removeMnemonics(const QString &original)
+{
+ QString returnText(original.size(), QChar());
+ int finalDest = 0;
+ int currPos = 0;
+ int l = original.length();
+ while (l) {
+ if (original.at(currPos) == QLatin1Char('&')) {
+ ++currPos;
+ --l;
+ if (l == 0)
+ break;
+ } else if (original.at(currPos) == QLatin1Char('(') && l >= 4 &&
+ original.at(currPos + 1) == QLatin1Char('&') &&
+ original.at(currPos + 2) != QLatin1Char('&') &&
+ original.at(currPos + 3) == QLatin1Char(')')) {
+ /* remove mnemonics its format is "\s*(&X)" */
+ int n = 0;
+ while (finalDest > n && returnText.at(finalDest - n - 1).isSpace())
+ ++n;
+ finalDest -= n;
+ currPos += 4;
+ l -= 4;
+ continue;
+ }
+ returnText[finalDest] = original.at(currPos);
+ ++currPos;
+ ++finalDest;
+ --l;
+ }
+ returnText.truncate(finalDest);
+ return returnText;
+}
+
+static bool qt_macWindowMainWindow(const QWindow *window)
+{
+ if (window->handle()) {
+ if (NSWindow *nswindow = static_cast<NSWindow*>(
+ QGuiApplication::platformNativeInterface()->
+ nativeResourceForWindow(QByteArrayLiteral("nswindow"),
+ const_cast<QWindow *>(window)))) {
+ return [nswindow isMainWindow];
+ }
+ }
+ return false;
+}
+
+#define LargeSmallMini(option, large, small, mini) \
+ (option->state & QStyle::State_Small) ? small : ((option->state & QStyle::State_Mini) ? mini : large)
+
+/*****************************************************************************
+ QMacCGStyle globals
+ *****************************************************************************/
+const int macItemFrame = 2; // menu item frame width
+const int macItemHMargin = 3; // menu item hor text margin
+const int macRightBorder = 12; // right border on mac
+
+/*****************************************************************************
+ QMacCGStyle utility functions
+ *****************************************************************************/
+
+enum QAquaMetric {
+ // Prepend kThemeMetric to get the HIToolBox constant.
+ // Represents the values already used in QMacStyle.
+ CheckBoxHeight = 0,
+ CheckBoxWidth,
+ EditTextFrameOutset,
+ FocusRectOutset,
+ HSliderHeight,
+ HSliderTickHeight,
+ LargeProgressBarThickness,
+ ListHeaderHeight,
+ MenuSeparatorHeight, // GetThemeMenuSeparatorHeight
+ MiniCheckBoxHeight,
+ MiniCheckBoxWidth,
+ MiniHSliderHeight,
+ MiniHSliderTickHeight,
+ MiniPopupButtonHeight,
+ MiniPushButtonHeight,
+ MiniRadioButtonHeight,
+ MiniRadioButtonWidth,
+ MiniVSliderTickWidth,
+ MiniVSliderWidth,
+ NormalProgressBarThickness,
+ PopupButtonHeight,
+ ProgressBarShadowOutset,
+ PushButtonHeight,
+ RadioButtonHeight,
+ RadioButtonWidth,
+ SeparatorSize,
+ SmallCheckBoxHeight,
+ SmallCheckBoxWidth,
+ SmallHSliderHeight,
+ SmallHSliderTickHeight,
+ SmallPopupButtonHeight,
+ SmallProgressBarShadowOutset,
+ SmallPushButtonHeight,
+ SmallRadioButtonHeight,
+ SmallRadioButtonWidth,
+ SmallVSliderTickWidth,
+ SmallVSliderWidth,
+ VSliderTickWidth,
+ VSliderWidth
+};
+
+static const int qt_mac_aqua_metrics[] = {
+ // Values as of macOS 10.12.4 and Xcode 8.3.1
+ 18 /* CheckBoxHeight */,
+ 18 /* CheckBoxWidth */,
+ 1 /* EditTextFrameOutset */,
+ 4 /* FocusRectOutset */,
+ 22 /* HSliderHeight */,
+ 5 /* HSliderTickHeight */,
+ 16 /* LargeProgressBarThickness */,
+ 17 /* ListHeaderHeight */,
+ 12 /* MenuSeparatorHeight, aka GetThemeMenuSeparatorHeight */,
+ 11 /* MiniCheckBoxHeight */,
+ 11 /* MiniCheckBoxWidth */,
+ 12 /* MiniHSliderHeight */,
+ 4 /* MiniHSliderTickHeight */,
+ 15 /* MiniPopupButtonHeight */,
+ 16 /* MiniPushButtonHeight */,
+ 11 /* MiniRadioButtonHeight */,
+ 11 /* MiniRadioButtonWidth */,
+ 4 /* MiniVSliderTickWidth */,
+ 12 /* MiniVSliderWidth */,
+ 12 /* NormalProgressBarThickness */,
+ 20 /* PopupButtonHeight */,
+ 4 /* ProgressBarShadowOutset */,
+ 20 /* PushButtonHeight */,
+ 18 /* RadioButtonHeight */,
+ 18 /* RadioButtonWidth */,
+ 1 /* SeparatorSize */,
+ 16 /* SmallCheckBoxHeight */,
+ 14 /* SmallCheckBoxWidth */,
+ 15 /* SmallHSliderHeight */,
+ 4 /* SmallHSliderTickHeight */,
+ 17 /* SmallPopupButtonHeight */,
+ 2 /* SmallProgressBarShadowOutset */,
+ 17 /* SmallPushButtonHeight */,
+ 15 /* SmallRadioButtonHeight */,
+ 15 /* SmallRadioButtonWidth */,
+ 4 /* SmallVSliderTickWidth */,
+ 15 /* SmallVSliderWidth */,
+ 5 /* VSliderTickWidth */,
+ 22 /* VSliderWidth */
+};
+
+static inline int qt_mac_aqua_get_metric(QAquaMetric m)
+{
+ return qt_mac_aqua_metrics[m];
+}
+
+static QSize qt_aqua_get_known_size(QStyle::ContentsType ct, const QStyleOption *opt,
+ QSize szHint, QStyleHelper::WidgetSizePolicy sz)
+{
+ QSize ret(-1, -1);
+ if (sz != QStyleHelper::SizeSmall && sz != QStyleHelper::SizeLarge && sz != QStyleHelper::SizeMini) {
+ qDebug("Not sure how to return this...");
+ return ret;
+ }
+// if ((widget && widget->testAttribute(Qt::WA_SetFont)) || !QApplication::desktopSettingsAware()) {
+// // If you're using a custom font and it's bigger than the default font,
+// // then no constraints for you. If you are smaller, we can try to help you out
+// QFont font = qt_app_fonts_hash()->value(widget->metaObject()->className(), QFont());
+// if (widget->font().pointSize() > font.pointSize())
+// return ret;
+// }
+
+ // TODO: investigate how this function is used. 'ct' can/should be
+ // filled out correctly in the styleoption already from the styleitem?
+ Q_ASSERT(ct != QStyle::CT_CustomBase);
+// if (ct == QStyle::CT_CustomBase && widget) {
+//#if QT_CONFIG(pushbutton)
+// if (qobject_cast<const QPushButton *>(widg))
+// ct = QStyle::CT_PushButton;
+//#endif
+// else if (qobject_cast<const QRadioButton *>(widget))
+// ct = QStyle::CT_RadioButton;
+//#if QT_CONFIG(checkbox)
+// else if (qobject_cast<const QCheckBox *>(widg))
+// ct = QStyle::CT_CheckBox;
+//#endif
+//#if QT_CONFIG(combobox)
+// else if (qobject_cast<const QComboBox *>(widg))
+// ct = QStyle::CT_ComboBox;
+//#endif
+//#if QT_CONFIG(toolbutton)
+// else if (qobject_cast<const QToolButton *>(widg))
+// ct = QStyle::CT_ToolButton;
+//#endif
+// else if (qobject_cast<const QSlider *>(widget))
+// ct = QStyle::CT_Slider;
+//#if QT_CONFIG(progressbar)
+// else if (qobject_cast<const QProgressBar *>(widg))
+// ct = QStyle::CT_ProgressBar;
+//#endif
+//#if QT_CONFIG(lineedit)
+// else if (qobject_cast<const QLineEdit *>(widg))
+// ct = QStyle::CT_LineEdit;
+//#endif
+//#if QT_CONFIG(itemviews)
+// else if (qobject_cast<const QHeaderView *>(widg))
+// ct = QStyle::CT_HeaderSection;
+//#endif
+//#if QT_CONFIG(menubar)
+// else if (qobject_cast<const QMenuBar *>(widg))
+// ct = QStyle::CT_MenuBar;
+//#endif
+//#if QT_CONFIG(sizegrip)
+// else if (qobject_cast<const QSizeGrip *>(widg))
+// ct = QStyle::CT_SizeGrip;
+//#endif
+// else
+// return ret;
+// }
+
+ switch (ct) {
+ case QStyle::CT_PushButton: {
+ const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt);
+ if (btn) {
+ QString buttonText = qt_mac_removeMnemonics(btn->text);
+ if (buttonText.contains(QLatin1Char('\n')))
+ ret = QSize(-1, -1);
+ else if (sz == QStyleHelper::SizeLarge)
+ ret = QSize(-1, qt_mac_aqua_get_metric(PushButtonHeight));
+ else if (sz == QStyleHelper::SizeSmall)
+ ret = QSize(-1, qt_mac_aqua_get_metric(SmallPushButtonHeight));
+ else if (sz == QStyleHelper::SizeMini)
+ ret = QSize(-1, qt_mac_aqua_get_metric(MiniPushButtonHeight));
+
+ if (!btn->icon.isNull()){
+ // If the button got an icon, and the icon is larger than the
+ // button, we can't decide on a default size
+ ret.setWidth(-1);
+ if (ret.height() < btn->iconSize.height())
+ ret.setHeight(-1);
+ }
+ else if (buttonText == QLatin1String("OK") || buttonText == QLatin1String("Cancel")){
+ // Aqua Style guidelines restrict the size of OK and Cancel buttons to 68 pixels.
+ // However, this doesn't work for German, therefore only do it for English,
+ // I suppose it would be better to do some sort of lookups for languages
+ // that like to have really long words.
+ // FIXME This is not exactly true. Out of context, OK buttons have their
+ // implicit size calculated the same way as any other button. Inside a
+ // QDialogButtonBox, their size should be calculated such that the action
+ // or accept button (i.e., rightmost) and cancel button have the same width.
+ ret.setWidth(69);
+ }
+ } else {
+ // The only sensible thing to do is to return whatever the style suggests...
+ if (sz == QStyleHelper::SizeLarge)
+ ret = QSize(-1, qt_mac_aqua_get_metric(PushButtonHeight));
+ else if (sz == QStyleHelper::SizeSmall)
+ ret = QSize(-1, qt_mac_aqua_get_metric(SmallPushButtonHeight));
+ else if (sz == QStyleHelper::SizeMini)
+ ret = QSize(-1, qt_mac_aqua_get_metric(MiniPushButtonHeight));
+ else
+ // Since there's no default size we return the large size...
+ ret = QSize(-1, qt_mac_aqua_get_metric(PushButtonHeight));
+ }
+ break; }
+ case QStyle::CT_SizeGrip:
+ // Not HIG kosher: mimic what we were doing earlier until we support 4-edge resizing in MDI subwindows
+ if (sz == QStyleHelper::SizeLarge || sz == QStyleHelper::SizeSmall) {
+ int s = sz == QStyleHelper::SizeSmall ? 16 : 22; // large: pixel measured from HITheme, small: from my hat
+ int width = 0;
+//#if QT_CONFIG(mdiarea)
+// if (widg && qobject_cast<QMdiSubWindow *>(widg->parentWidget()))
+// width = s;
+//#endif
+ ret = QSize(width, s);
+ }
+ break;
+ case QStyle::CT_ComboBox:
+ switch (sz) {
+ case QStyleHelper::SizeLarge:
+ ret = QSize(-1, qt_mac_aqua_get_metric(PopupButtonHeight));
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = QSize(-1, qt_mac_aqua_get_metric(SmallPopupButtonHeight));
+ break;
+ case QStyleHelper::SizeMini:
+ ret = QSize(-1, qt_mac_aqua_get_metric(MiniPopupButtonHeight));
+ break;
+ default:
+ break;
+ }
+ break;
+ case QStyle::CT_ToolButton:
+ if (sz == QStyleHelper::SizeSmall) {
+ int width = 0, height = 0;
+ if (szHint == QSize(-1, -1)) { //just 'guess'..
+//#if QT_CONFIG(toolbutton)
+// const QStyleOptionToolButton *bt = qstyleoption_cast<const QStyleOptionToolButton *>(opt);
+// // If this conversion fails then the widget was not what it claimed to be.
+// if(bt) {
+// if (!bt->icon.isNull()) {
+// QSize iconSize = bt->iconSize;
+// QSize pmSize = bt->icon.actualSize(QSize(32, 32), QIcon::Normal);
+// width = qMax(width, qMax(iconSize.width(), pmSize.width()));
+// height = qMax(height, qMax(iconSize.height(), pmSize.height()));
+// }
+// if (!bt->text.isNull() && bt->toolButtonStyle != Qt::ToolButtonIconOnly) {
+// int text_width = bt->fontMetrics.horizontalAdvance(bt->text),
+// text_height = bt->fontMetrics.height();
+// if (bt->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+// width = qMax(width, text_width);
+// height += text_height;
+// } else {
+// width += text_width;
+// width = qMax(height, text_height);
+// }
+// }
+// } else
+//#endif
+ {
+ // Let's return the size hint...
+ width = szHint.width();
+ height = szHint.height();
+ }
+ } else {
+ width = szHint.width();
+ height = szHint.height();
+ }
+ width = qMax(20, width + 5); //border
+ height = qMax(20, height + 5); //border
+ ret = QSize(width, height);
+ }
+ break;
+ case QStyle::CT_Slider: {
+ int w = -1;
+ const QStyleOptionSlider *sld = qstyleoption_cast<const QStyleOptionSlider *>(opt);
+ // If this conversion fails then the widget was not what it claimed to be.
+ if(sld) {
+ if (sz == QStyleHelper::SizeLarge) {
+ if (sld->orientation == Qt::Horizontal) {
+ w = qt_mac_aqua_get_metric(HSliderHeight);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(HSliderTickHeight);
+ } else {
+ w = qt_mac_aqua_get_metric(VSliderWidth);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(VSliderTickWidth);
+ }
+ } else if (sz == QStyleHelper::SizeSmall) {
+ if (sld->orientation == Qt::Horizontal) {
+ w = qt_mac_aqua_get_metric(SmallHSliderHeight);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(SmallHSliderTickHeight);
+ } else {
+ w = qt_mac_aqua_get_metric(SmallVSliderWidth);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(SmallVSliderTickWidth);
+ }
+ } else if (sz == QStyleHelper::SizeMini) {
+ if (sld->orientation == Qt::Horizontal) {
+ w = qt_mac_aqua_get_metric(MiniHSliderHeight);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(MiniHSliderTickHeight);
+ } else {
+ w = qt_mac_aqua_get_metric(MiniVSliderWidth);
+ if (sld->tickPosition != QStyleOptionSlider::NoTicks)
+ w += qt_mac_aqua_get_metric(MiniVSliderTickWidth);
+ }
+ }
+ } else {
+ // This is tricky, we were requested to find a size for a slider which is not
+ // a slider. We don't know if this is vertical or horizontal or if we need to
+ // have tick marks or not.
+ // For this case we will return an horizontal slider without tick marks.
+ w = qt_mac_aqua_get_metric(HSliderHeight);
+ w += qt_mac_aqua_get_metric(HSliderTickHeight);
+ }
+ if (sld->orientation == Qt::Horizontal)
+ ret.setHeight(w);
+ else
+ ret.setWidth(w);
+ break;
+ }
+//#if QT_CONFIG(progressbar)
+// case QStyle::CT_ProgressBar: {
+// int finalValue = -1;
+// Qt::Orientation orient = Qt::Horizontal;
+// if (const QProgressBar *pb = qobject_cast<const QProgressBar *>(widg))
+// orient = pb->orientation();
+
+// if (sz == QStyleHelper::SizeLarge)
+// finalValue = qt_mac_aqua_get_metric(LargeProgressBarThickness)
+// + qt_mac_aqua_get_metric(ProgressBarShadowOutset);
+// else
+// finalValue = qt_mac_aqua_get_metric(NormalProgressBarThickness)
+// + qt_mac_aqua_get_metric(SmallProgressBarShadowOutset);
+// if (orient == Qt::Horizontal)
+// ret.setHeight(finalValue);
+// else
+// ret.setWidth(finalValue);
+// break;
+// }
+//#endif
+//#if QT_CONFIG(combobox)
+// case QStyle::CT_LineEdit:
+// if (!widg || !qobject_cast<QComboBox *>(widg->parentWidget())) {
+// //should I take into account the font dimentions of the lineedit? -Sam
+// if (sz == QStyleHelper::SizeLarge)
+// ret = QSize(-1, 21);
+// else
+// ret = QSize(-1, 19);
+// }
+// break;
+//#endif
+ case QStyle::CT_HeaderSection:
+//#if QT_CONFIG(treeview)
+// if (isTreeView(widg))
+// ret = QSize(-1, qt_mac_aqua_get_metric(ListHeaderHeight));
+//#endif
+ break;
+ case QStyle::CT_MenuBar:
+ if (sz == QStyleHelper::SizeLarge) {
+ ret = QSize(-1, [[NSApp mainMenu] menuBarHeight]);
+ // In the qt_mac_set_native_menubar(false) case,
+ // we come it here with a zero-height main menu,
+ // preventing the in-window menu from displaying.
+ // Use 22 pixels for the height, by observation.
+ if (ret.height() <= 0)
+ ret.setHeight(22);
+ }
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+#if defined(QMAC_QAQUASTYLE_SIZE_CONSTRAIN) || defined(DEBUG_SIZE_CONSTRAINT)
+static QStyleHelper::WidgetSizePolicy qt_aqua_guess_size(
+ const QSize &large,
+ const QSize &small,
+ const QSize &mini)
+{
+ if (large == QSize(-1, -1)) {
+ if (small != QSize(-1, -1))
+ return QStyleHelper::SizeSmall;
+ if (mini != QSize(-1, -1))
+ return QStyleHelper::SizeMini;
+ return QStyleHelper::SizeDefault;
+ } else if (small == QSize(-1, -1)) {
+ if (mini != QSize(-1, -1))
+ return QStyleHelper::SizeMini;
+ return QStyleHelper::SizeLarge;
+ } else if (mini == QSize(-1, -1)) {
+ return QStyleHelper::SizeLarge;
+ }
+
+ if (qEnvironmentVariableIsSet("QWIDGET_ALL_SMALL"))
+ return QStyleHelper::SizeSmall;
+ else if (qEnvironmentVariableIsSet("QWIDGET_ALL_MINI"))
+ return QStyleHelper::SizeMini;
+
+ return QStyleHelper::SizeLarge;
+}
+#endif
+
+QPainterPath QMacStylePrivate::windowPanelPath(const QRectF &r) const
+{
+ static const qreal CornerPointOffset = 5.5;
+ static const qreal CornerControlOffset = 2.1;
+
+ QPainterPath path;
+ // Top-left corner
+ path.moveTo(r.left(), r.top() + CornerPointOffset);
+ path.cubicTo(r.left(), r.top() + CornerControlOffset,
+ r.left() + CornerControlOffset, r.top(),
+ r.left() + CornerPointOffset, r.top());
+ // Top-right corner
+ path.lineTo(r.right() - CornerPointOffset, r.top());
+ path.cubicTo(r.right() - CornerControlOffset, r.top(),
+ r.right(), r.top() + CornerControlOffset,
+ r.right(), r.top() + CornerPointOffset);
+ // Bottom-right corner
+ path.lineTo(r.right(), r.bottom() - CornerPointOffset);
+ path.cubicTo(r.right(), r.bottom() - CornerControlOffset,
+ r.right() - CornerControlOffset, r.bottom(),
+ r.right() - CornerPointOffset, r.bottom());
+ // Bottom-right corner
+ path.lineTo(r.left() + CornerPointOffset, r.bottom());
+ path.cubicTo(r.left() + CornerControlOffset, r.bottom(),
+ r.left(), r.bottom() - CornerControlOffset,
+ r.left(), r.bottom() - CornerPointOffset);
+ path.lineTo(r.left(), r.top() + CornerPointOffset);
+
+ return path;
+}
+
+QMacStylePrivate::CocoaControlType QMacStylePrivate::windowButtonCocoaControl(QStyle::SubControl sc) const
+{
+ struct WindowButtons {
+ QStyle::SubControl sc;
+ QMacStylePrivate::CocoaControlType ct;
+ };
+
+ static const WindowButtons buttons[] = {
+ { QStyle::SC_TitleBarCloseButton, QMacStylePrivate::Button_WindowClose },
+ { QStyle::SC_TitleBarMinButton, QMacStylePrivate::Button_WindowMiniaturize },
+ { QStyle::SC_TitleBarMaxButton, QMacStylePrivate::Button_WindowZoom }
+ };
+
+ for (const auto &wb : buttons)
+ if (wb.sc == sc)
+ return wb.ct;
+
+ return NoControl;
+}
+
+
+void QMacStylePrivate::tabLayout(const QStyleOptionTab *opt, QRect *textRect, QRect *iconRect) const
+{
+ Q_ASSERT(textRect);
+ Q_ASSERT(iconRect);
+ QRect tr = opt->rect;
+ const bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
+ || opt->shape == QStyleOptionTab::RoundedWest
+ || opt->shape == QStyleOptionTab::TriangularEast
+ || opt->shape == QStyleOptionTab::TriangularWest;
+ if (verticalTabs)
+ tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
+
+ int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
+ int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
+ const int hpadding = 4;
+ const int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
+ if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
+ verticalShift = -verticalShift;
+ tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
+
+ // left widget
+ if (!opt->leftButtonSize.isEmpty()) {
+ const int buttonSize = verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width();
+ tr.setLeft(tr.left() + 4 + buttonSize);
+ // make text aligned to center
+ if (opt->rightButtonSize.isEmpty())
+ tr.setRight(tr.right() - 4 - buttonSize);
+ }
+ // right widget
+ if (!opt->rightButtonSize.isEmpty()) {
+ const int buttonSize = verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width();
+ tr.setRight(tr.right() - 4 - buttonSize);
+ // make text aligned to center
+ if (opt->leftButtonSize.isEmpty())
+ tr.setLeft(tr.left() + 4 + buttonSize);
+ }
+
+ // icon
+ if (!opt->icon.isNull()) {
+ QSize iconSize = opt->iconSize;
+ if (!iconSize.isValid()) {
+ int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
+ iconSize = QSize(iconExtent, iconExtent);
+ }
+ QSize tabIconSize = opt->icon.actualSize(iconSize,
+ (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
+ (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
+ // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
+ tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
+
+ const int stylePadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2 - hpadding;
+
+ if (opt->documentMode) {
+ // documents show the icon as part of the the text
+ const int textWidth =
+ opt->fontMetrics.boundingRect(tr, Qt::AlignCenter | Qt::TextShowMnemonic, opt->text).width();
+ *iconRect = QRect(tr.center().x() - textWidth / 2 - stylePadding - tabIconSize.width(),
+ tr.center().y() - tabIconSize.height() / 2,
+ tabIconSize.width(), tabIconSize.height());
+ } else {
+ *iconRect = QRect(tr.left() + stylePadding, tr.center().y() - tabIconSize.height() / 2,
+ tabIconSize.width(), tabIconSize.height());
+ }
+ if (!verticalTabs)
+ *iconRect = proxyStyle->visualRect(opt->direction, opt->rect, *iconRect);
+
+ tr.setLeft(tr.left() + stylePadding + tabIconSize.width() + 4);
+ tr.setRight(tr.right() - stylePadding - tabIconSize.width() - 4);
+ }
+
+ if (!verticalTabs)
+ tr = proxyStyle->visualRect(opt->direction, opt->rect, tr);
+
+ *textRect = tr;
+}
+
+QMacStylePrivate::Direction QMacStylePrivate::tabDirection(QStyleOptionTab::Shape shape)
+{
+ switch (shape) {
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ return South;
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ return North;
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ return West;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ return East;
+ }
+}
+
+bool QMacStylePrivate::verticalTabs(QMacStylePrivate::Direction direction)
+{
+ return (direction == QMacStylePrivate::East
+ || direction == QMacStylePrivate::West);
+}
+
+QStyleHelper::WidgetSizePolicy QMacStylePrivate::effectiveAquaSizeConstrain(const QStyleOption *option,
+ QStyle::ContentsType ct,
+ QSize szHint, QSize *insz) const
+{
+ QStyleHelper::WidgetSizePolicy sz = aquaSizeConstrain(option, ct, szHint, insz);
+ if (sz == QStyleHelper::SizeDefault)
+ return QStyleHelper::SizeLarge;
+ return sz;
+}
+
+QStyleHelper::WidgetSizePolicy QMacStylePrivate::aquaSizeConstrain(const QStyleOption *option,
+ QStyle::ContentsType ct, QSize szHint, QSize *insz) const
+{
+ if (!option)
+ return QStyleHelper::SizeLarge;
+
+ if (option->state & QStyle::State_Small)
+ return QStyleHelper::SizeSmall;
+ if (option->state & QStyle::State_Mini)
+ return QStyleHelper::SizeMini;
+
+ return QStyleHelper::SizeLarge;
+
+}
+
+uint qHash(const QMacStylePrivate::CocoaControl &cw, uint seed = 0)
+{
+ return ((cw.type << 2) | cw.size) ^ seed;
+}
+
+QMacStylePrivate::CocoaControl::CocoaControl()
+ : type(NoControl), size(QStyleHelper::SizeDefault)
+{
+}
+
+QMacStylePrivate::CocoaControl::CocoaControl(CocoaControlType t, QStyleHelper::WidgetSizePolicy s)
+ : type(t), size(s)
+{
+}
+
+bool QMacStylePrivate::CocoaControl::operator==(const CocoaControl &other) const
+{
+ return other.type == type && other.size == size;
+}
+
+QSizeF QMacStylePrivate::CocoaControl::defaultFrameSize() const
+{
+ // We need this because things like NSView.alignmentRectInsets
+ // or -[NSCell titleRectForBounds:] won't work unless the control
+ // has a reasonable frame set. IOW, it's a chicken and egg problem.
+ // These values are as observed in Xcode 9's Interface Builder.
+
+ if (type == Button_PushButton)
+ return QSizeF(-1, pushButtonDefaultHeight[size]);
+
+ if (type == Button_PopupButton
+ || type == Button_PullDown)
+ return QSizeF(-1, popupButtonDefaultHeight[size]);
+
+ if (type == ComboBox)
+ return QSizeF(-1, comboBoxDefaultHeight[size]);
+
+ return QSizeF();
+}
+
+QRectF QMacStylePrivate::CocoaControl::adjustedControlFrame(const QRectF &rect) const
+{
+ QRectF frameRect;
+ const auto frameSize = defaultFrameSize();
+ if (type == QMacStylePrivate::Button_SquareButton) {
+ frameRect = rect.adjusted(3, 1, -3, -1)
+ .adjusted(focusRingWidth, focusRingWidth, -focusRingWidth, -focusRingWidth);
+ } else if (type == QMacStylePrivate::Button_PushButton) {
+ // Start from the style option's top-left corner.
+ frameRect = QRectF(rect.topLeft(),
+ QSizeF(rect.width(), frameSize.height()));
+ if (size == QStyleHelper::SizeSmall)
+ frameRect = frameRect.translated(0, 1.5);
+ else if (size == QStyleHelper::SizeMini)
+ frameRect = frameRect.adjusted(0, 0, -8, 0).translated(4, 4);
+ } else {
+ // Center in the style option's rect.
+ frameRect = QRectF(QPointF(0, (rect.height() - frameSize.height()) / 2.0),
+ QSizeF(rect.width(), frameSize.height()));
+ frameRect = frameRect.translated(rect.topLeft());
+ if (type == QMacStylePrivate::Button_PullDown || type == QMacStylePrivate::Button_PopupButton) {
+ if (size == QStyleHelper::SizeLarge)
+ frameRect = frameRect.adjusted(0, 0, -6, 0).translated(3, 0);
+ else if (size == QStyleHelper::SizeSmall)
+ frameRect = frameRect.adjusted(0, 0, -4, 0).translated(2, 1);
+ else if (size == QStyleHelper::SizeMini)
+ frameRect = frameRect.adjusted(0, 0, -9, 0).translated(5, 0);
+ } else if (type == QMacStylePrivate::ComboBox) {
+ frameRect = frameRect.adjusted(0, 0, -6, 0).translated(4, 0);
+ }
+ }
+
+ return frameRect;
+}
+
+QMarginsF QMacStylePrivate::CocoaControl::titleMargins() const
+{
+ if (type == QMacStylePrivate::Button_PushButton) {
+ if (size == QStyleHelper::SizeLarge)
+ return QMarginsF(12, 5, 12, 9);
+ if (size == QStyleHelper::SizeSmall)
+ return QMarginsF(12, 4, 12, 9);
+ if (size == QStyleHelper::SizeMini)
+ return QMarginsF(10, 1, 10, 2);
+ }
+
+ if (type == QMacStylePrivate::Button_PullDown) {
+ if (size == QStyleHelper::SizeLarge)
+ return QMarginsF(7.5, 2.5, 22.5, 5.5);
+ if (size == QStyleHelper::SizeSmall)
+ return QMarginsF(7.5, 2, 20.5, 4);
+ if (size == QStyleHelper::SizeMini)
+ return QMarginsF(4.5, 0, 16.5, 2);
+ }
+
+ if (type == QMacStylePrivate::Button_SquareButton)
+ return QMarginsF(6, 1, 6, 2);
+
+ return QMarginsF();
+}
+
+bool QMacStylePrivate::CocoaControl::getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const
+{
+ switch (type) {
+ case Button_CheckBox:
+ *buttonType = NSSwitchButton;
+ *bezelStyle = NSRegularSquareBezelStyle;
+ break;
+ case Button_Disclosure:
+ *buttonType = NSOnOffButton;
+ *bezelStyle = NSDisclosureBezelStyle;
+ break;
+ case Button_RadioButton:
+ *buttonType = NSRadioButton;
+ *bezelStyle = NSRegularSquareBezelStyle;
+ break;
+ case Button_SquareButton:
+ *buttonType = NSPushOnPushOffButton;
+ *bezelStyle = NSShadowlessSquareBezelStyle;
+ break;
+ case Button_PushButton:
+ *buttonType = NSPushOnPushOffButton;
+ *bezelStyle = NSRoundedBezelStyle;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+QMacStylePrivate::CocoaControlType cocoaControlType(const QStyleOption *opt)
+{
+ if (const auto *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
+ // When the contents won't fit in a large sized button,
+ // and WA_MacNormalSize is not set, make the button square.
+ // Threshold used to be at 34, not 32.
+ const auto maxNonSquareHeight = pushButtonDefaultHeight[QStyleHelper::SizeLarge];
+ const bool isSquare = (btn->features & QStyleOptionButton::Flat)
+ || (btn->rect.height() > maxNonSquareHeight);
+// && !(w && w->testAttribute(Qt::WA_MacNormalSize)));
+ return (isSquare? QMacStylePrivate::Button_SquareButton :
+ hasMenu ? QMacStylePrivate::Button_PullDown :
+ QMacStylePrivate::Button_PushButton);
+ }
+
+ if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ if (combo->editable)
+ return QMacStylePrivate::ComboBox;
+ // TODO Me may support square, non-editable combo boxes, but not more than that
+ return QMacStylePrivate::Button_PopupButton;
+ }
+
+ return QMacStylePrivate::NoControl;
+}
+
+/**
+ Carbon draws comboboxes (and other views) outside the rect given as argument. Use this function to obtain
+ the corresponding inner rect for drawing the same combobox so that it stays inside the given outerBounds.
+*/
+CGRect QMacStylePrivate::comboboxInnerBounds(const CGRect &outerBounds, const CocoaControl &cocoaWidget)
+{
+ CGRect innerBounds = outerBounds;
+ // Carbon draw parts of the view outside the rect.
+ // So make the rect a bit smaller to compensate
+ // (I wish HIThemeGetButtonBackgroundBounds worked)
+ if (cocoaWidget.type == Button_PopupButton) {
+ switch (cocoaWidget.size) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 7;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 2;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 5;
+ innerBounds.size.height -= 6;
+ }
+ } else if (cocoaWidget.type == ComboBox) {
+ switch (cocoaWidget.size) {
+ case QStyleHelper::SizeSmall:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 7;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeMini:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 3;
+ innerBounds.size.width -= 4;
+ innerBounds.size.height -= 8;
+ break;
+ case QStyleHelper::SizeLarge:
+ case QStyleHelper::SizeDefault:
+ innerBounds.origin.x += 3;
+ innerBounds.origin.y += 2;
+ innerBounds.size.width -= 6;
+ innerBounds.size.height -= 8;
+ }
+ }
+
+ return innerBounds;
+}
+
+/**
+ Inside a combobox Qt places a line edit widget. The size of this widget should depend on the kind
+ of combobox we choose to draw. This function calculates and returns this size.
+*/
+QRectF QMacStylePrivate::comboboxEditBounds(const QRectF &outerBounds, const CocoaControl &cw)
+{
+ QRectF ret = outerBounds;
+ if (cw.type == ComboBox) {
+ switch (cw.size) {
+ case QStyleHelper::SizeLarge:
+ ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5);
+ ret.setHeight(16);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = ret.adjusted(0, 0, -22, 0).translated(2, 3);
+ ret.setHeight(14);
+ break;
+ case QStyleHelper::SizeMini:
+ ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5);
+ ret.setHeight(10.5);
+ break;
+ default:
+ break;
+ }
+ } else if (cw.type == Button_PopupButton) {
+ switch (cw.size) {
+ case QStyleHelper::SizeLarge:
+ ret.adjust(10, 1, -23, -4);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret.adjust(10, 4, -20, -3);
+ break;
+ case QStyleHelper::SizeMini:
+ ret.adjust(9, 0, -19, 0);
+ ret.setHeight(13);
+ break;
+ default:
+ break;
+ }
+ }
+ return ret;
+}
+
+QMacStylePrivate::QMacStylePrivate()
+ : backingStoreNSView(nil)
+{
+ if (auto *ssf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::SmallFont))
+ smallSystemFont = *ssf;
+ if (auto *msf = QGuiApplicationPrivate::platformTheme()->font(QPlatformTheme::MiniFont))
+ miniSystemFont = *msf;
+}
+
+QMacStylePrivate::~QMacStylePrivate()
+{
+ QMacAutoReleasePool pool;
+ for (NSView *b : cocoaControls)
+ [b release];
+ for (NSCell *cell : cocoaCells)
+ [cell release];
+}
+
+NSView *QMacStylePrivate::cocoaControl(CocoaControl cocoaControl) const
+{
+ if (cocoaControl.type == QMacStylePrivate::NoControl
+ || cocoaControl.size == QStyleHelper::SizeDefault)
+ return nil;
+
+ if (cocoaControl.type == Box) {
+ if (__builtin_available(macOS 10.14, *)) {
+ if (qt_mac_applicationIsInDarkMode()) {
+ // See render code in drawPrimitive(PE_FrameTabWidget)
+ cocoaControl.type = Box_Dark;
+ }
+ }
+ }
+
+ NSView *bv = cocoaControls.value(cocoaControl, nil);
+ if (!bv) {
+ switch (cocoaControl.type) {
+ case Box: {
+ NSBox *box = [[NSBox alloc] init];
+ bv = box;
+ box.title = @"";
+ box.titlePosition = NSNoTitle;
+ break;
+ }
+ case Box_Dark:
+ bv = [[QDarkNSBox alloc] init];
+ break;
+ case Button_CheckBox:
+ case Button_Disclosure:
+ case Button_PushButton:
+ case Button_RadioButton:
+ case Button_SquareButton: {
+ NSButton *bc = [[NSButton alloc] init];
+ bc.title = @"";
+ // See below for style and bezel setting.
+ bv = bc;
+ break;
+ }
+ case Button_PopupButton:
+ case Button_PullDown: {
+ NSPopUpButton *bc = [[NSPopUpButton alloc] init];
+ bc.title = @"";
+ if (cocoaControl.type == Button_PullDown)
+ bc.pullsDown = YES;
+ bv = bc;
+ break;
+ }
+ case Button_WindowClose:
+ case Button_WindowMiniaturize:
+ case Button_WindowZoom: {
+ const NSWindowButton button = [=] {
+ switch (cocoaControl.type) {
+ case Button_WindowClose:
+ return NSWindowCloseButton;
+ case Button_WindowMiniaturize:
+ return NSWindowMiniaturizeButton;
+ case Button_WindowZoom:
+ return NSWindowZoomButton;
+ default:
+ break;
+ }
+ Q_UNREACHABLE();
+ } ();
+ const auto styleMask = NSWindowStyleMaskTitled
+ | NSWindowStyleMaskClosable
+ | NSWindowStyleMaskMiniaturizable
+ | NSWindowStyleMaskResizable;
+ bv = [NSWindow standardWindowButton:button forStyleMask:styleMask];
+ [bv retain];
+ break;
+ }
+ case ComboBox:
+ bv = [[NSComboBox alloc] init];
+ break;
+ case ProgressIndicator_Determinate:
+ bv = [[NSProgressIndicator alloc] init];
+ break;
+ case ProgressIndicator_Indeterminate:
+ bv = [[QIndeterminateProgressIndicator alloc] init];
+ break;
+ case Scroller_Horizontal:
+ bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
+ break;
+ case Scroller_Vertical:
+ // Cocoa sets the orientation from the view's frame
+ // at construction time, and it cannot be changed later.
+ bv = [[NSScroller alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
+ break;
+ case Slider_Horizontal:
+ bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)];
+ break;
+ case Slider_Vertical:
+ // Cocoa sets the orientation from the view's frame
+ // at construction time, and it cannot be changed later.
+ bv = [[NSSlider alloc] initWithFrame:NSMakeRect(0, 0, 20, 200)];
+ break;
+ case SplitView_Horizontal:
+ bv = [[NSSplitView alloc] init];
+ break;
+ case SplitView_Vertical:
+ bv = [[QVerticalSplitView alloc] init];
+ break;
+ case TextField:
+ bv = [[NSTextField alloc] init];
+ break;
+ default:
+ break;
+ }
+
+ if ([bv isKindOfClass:[NSControl class]]) {
+ auto *ctrl = static_cast<NSControl *>(bv);
+ switch (cocoaControl.size) {
+ case QStyleHelper::SizeSmall:
+ ctrl.controlSize = NSControlSizeSmall;
+ break;
+ case QStyleHelper::SizeMini:
+ ctrl.controlSize = NSControlSizeMini;
+ break;
+ default:
+ break;
+ }
+ } else if (cocoaControl.type == ProgressIndicator_Determinate ||
+ cocoaControl.type == ProgressIndicator_Indeterminate) {
+ auto *pi = static_cast<NSProgressIndicator *>(bv);
+ pi.indeterminate = (cocoaControl.type == ProgressIndicator_Indeterminate);
+ switch (cocoaControl.size) {
+ case QStyleHelper::SizeSmall:
+ pi.controlSize = NSControlSizeSmall;
+ break;
+ case QStyleHelper::SizeMini:
+ pi.controlSize = NSControlSizeMini;
+ break;
+ default:
+ break;
+ }
+ }
+
+ cocoaControls.insert(cocoaControl, bv);
+ }
+
+ NSButtonType buttonType;
+ NSBezelStyle bezelStyle;
+ if (cocoaControl.getCocoaButtonTypeAndBezelStyle(&buttonType, &bezelStyle)) {
+ // FIXME We need to reset the button's type and
+ // bezel style properties, even when cached.
+ auto *button = static_cast<NSButton *>(bv);
+ button.buttonType = buttonType;
+ button.bezelStyle = bezelStyle;
+ if (cocoaControl.type == Button_CheckBox)
+ button.allowsMixedState = YES;
+ }
+
+ return bv;
+}
+
+NSCell *QMacStylePrivate::cocoaCell(CocoaControl cocoaControl) const
+{
+ NSCell *cell = cocoaCells[cocoaControl];
+ if (!cell) {
+ switch (cocoaControl.type) {
+ case Stepper:
+ cell = [[NSStepperCell alloc] init];
+ break;
+ case Button_Disclosure: {
+ NSButtonCell *bc = [[NSButtonCell alloc] init];
+ bc.buttonType = NSOnOffButton;
+ bc.bezelStyle = NSDisclosureBezelStyle;
+ cell = bc;
+ break;
+ }
+ default:
+ break;
+ }
+
+ switch (cocoaControl.size) {
+ case QStyleHelper::SizeSmall:
+ cell.controlSize = NSControlSizeSmall;
+ break;
+ case QStyleHelper::SizeMini:
+ cell.controlSize = NSControlSizeMini;
+ break;
+ default:
+ break;
+ }
+
+ cocoaCells.insert(cocoaControl, cell);
+ }
+
+ return cell;
+}
+
+void QMacStylePrivate::drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock) const
+{
+ QMacAutoReleasePool pool;
+ QMacCGContext ctx(p);
+ setupNSGraphicsContext(ctx, YES);
+
+ // FIXME: The rect that we get in is relative to the widget that we're drawing
+ // style on behalf of, and doesn't take into account the offset of that widget
+ // to the widget that owns the backingstore, which we are placing the native
+ // view into below. This means most of the views are placed in the upper left
+ // corner of backingStoreNSView, which does not map to where the actual widget
+ // is, and which may cause problems such as triggering a setNeedsDisplay of the
+ // backingStoreNSView for the wrong rect. We work around this by making the view
+ // layer-backed, which prevents triggering display of the backingStoreNSView, but
+ // but there may be other issues lurking here due to the wrong position. QTBUG-68023
+ view.wantsLayer = YES;
+
+ // FIXME: We are also setting the frame of the incoming view a lot at the call
+ // sites of this function, making it unclear who's actually responsible for
+ // maintaining the size and position of the view. In theory the call sites
+ // should ensure the _size_ of the view is correct, and then let this code
+ // take care of _positioning_ the view at the right place inside backingStoreNSView.
+ // For now we pass on the rect as is, to prevent any regressions until this
+ // can be investigated properly.
+ view.frame = rect.toCGRect();
+
+ [backingStoreNSView addSubview:view];
+
+ // FIXME: Based on the code below, this method isn't drawing an NSView into
+ // a rect, it's drawing _part of the NSView_, defined by the incoming clip
+ // or dirty rect, into the current graphics context. We're doing some manual
+ // translations at the call sites that would indicate that this relationship
+ // is a bit fuzzy.
+ const CGRect dirtyRect = rect.toCGRect();
+
+ if (drawRectBlock)
+ drawRectBlock(ctx, dirtyRect);
+ else
+ [view drawRect:dirtyRect];
+
+ [view removeFromSuperviewWithoutNeedingDisplay];
+
+ restoreNSGraphicsContext(ctx);
+}
+
+void QMacStylePrivate::resolveCurrentNSView(QWindow *window) const
+{
+ backingStoreNSView = window ? (NSView *)window->winId() : nil;
+}
+
+QMacStyle::QMacStyle()
+ : QCommonStyle(*new QMacStylePrivate)
+{
+ QMacAutoReleasePool pool;
+
+ static QMacNotificationObserver scrollbarStyleObserver(nil,
+ NSPreferredScrollerStyleDidChangeNotification, []() {
+ // Purge destroyed scroll bars
+ QMacStylePrivate::scrollBars.removeAll(QPointer<QObject>());
+
+ QEvent event(QEvent::StyleChange);
+ for (const auto &o : QMacStylePrivate::scrollBars)
+ QCoreApplication::sendEvent(o, &event);
+ });
+
+#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
+ Q_D(QMacStyle);
+ // FIXME: Tie this logic into theme change, or even polish/unpolish
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) {
+ d->appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] {
+ Q_D(QMacStyle);
+ for (NSView *b : d->cocoaControls)
+ [b release];
+ d->cocoaControls.clear();
+ });
+ }
+#endif
+}
+
+QMacStyle::~QMacStyle()
+{
+}
+
+int QMacStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt) const
+{
+ Q_D(const QMacStyle);
+ const int controlSize = getControlSize(opt);
+ int ret = 0;
+
+ switch (metric) {
+ case PM_TabCloseIndicatorWidth:
+ case PM_TabCloseIndicatorHeight:
+ ret = closeButtonSize;
+ break;
+ case PM_ToolBarIconSize:
+ ret = proxy()->pixelMetric(PM_LargeIconSize);
+ break;
+ case PM_FocusFrameVMargin:
+ case PM_FocusFrameHMargin:
+ ret = qt_mac_aqua_get_metric(FocusRectOutset);
+ break;
+ case PM_DialogButtonsSeparator:
+ ret = -5;
+ break;
+ case PM_DialogButtonsButtonHeight: {
+ QSize sz;
+ ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
+ if (sz == QSize(-1, -1))
+ ret = 32;
+ else
+ ret = sz.height();
+ break; }
+ case PM_DialogButtonsButtonWidth: {
+ QSize sz;
+ ret = d->aquaSizeConstrain(opt, QStyle::CT_PushButton, QSize(-1, -1), &sz);
+ if (sz == QSize(-1, -1))
+ ret = 70;
+ else
+ ret = sz.width();
+ break; }
+
+ case PM_MenuBarHMargin:
+ ret = 8;
+ break;
+
+ case PM_MenuBarVMargin:
+ ret = 0;
+ break;
+
+ case PM_MenuBarPanelWidth:
+ ret = 0;
+ break;
+
+ case PM_MenuButtonIndicator:
+ ret = toolButtonArrowSize;
+ break;
+
+ case QStyle::PM_MenuDesktopFrameWidth:
+ ret = 5;
+ break;
+
+ case PM_CheckBoxLabelSpacing:
+ case PM_RadioButtonLabelSpacing:
+ ret = [=] {
+ if (opt) {
+ if (opt->state & State_Mini)
+ return 4;
+ if (opt->state & State_Small)
+ return 3;
+ }
+ return 2;
+ } ();
+ break;
+ case PM_MenuScrollerHeight:
+ ret = 15; // I hate having magic numbers in here...
+ break;
+ case PM_DefaultFrameWidth:
+//#if QT_CONFIG(mainwindow)
+// if (widget && (widget->isWindow() || !widget->parentWidget()
+// || (qobject_cast<const QMainWindow*>(widget->parentWidget())
+// && static_cast<QMainWindow *>(widget->parentWidget())->centralWidget() == widget))
+// && qobject_cast<const QAbstractScrollArea *>(widget))
+// ret = 0;
+// else
+//#endif
+ // The combo box popup has no frame.
+ if (qstyleoption_cast<const QStyleOptionComboBox *>(opt) != 0)
+ ret = 0;
+ else
+ ret = 1;
+ break;
+ case PM_MaximumDragDistance:
+ ret = -1;
+ break;
+ case PM_ScrollBarSliderMin:
+ ret = 24;
+ break;
+ case PM_SpinBoxFrameWidth:
+ ret = qt_mac_aqua_get_metric(EditTextFrameOutset);
+ break;
+ case PM_ButtonShiftHorizontal:
+ case PM_ButtonShiftVertical:
+ ret = 0;
+ break;
+ case PM_SliderLength:
+ ret = 17;
+ break;
+ // Returns the number of pixels to use for the business part of the
+ // slider (i.e., the non-tickmark portion). The remaining space is shared
+ // equally between the tickmark regions.
+ case PM_SliderControlThickness:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
+ int ticks = sl->tickPosition;
+ int n = 0;
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ ++n;
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ ++n;
+ if (!n) {
+ ret = space;
+ break;
+ }
+
+ int thick = 6; // Magic constant to get 5 + 16 + 5
+ if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
+ thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
+
+ space -= thick;
+ if (space > 0)
+ thick += (space * 2) / (n + 2);
+ ret = thick;
+ } else {
+ ret = 0;
+ }
+ break;
+ case PM_SmallIconSize:
+ ret = int(QStyleHelper::dpiScaled(16., opt));
+ break;
+
+ case PM_LargeIconSize:
+ ret = int(QStyleHelper::dpiScaled(32., opt));
+ break;
+
+ case PM_IconViewIconSize:
+ ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
+ break;
+
+ case PM_ButtonDefaultIndicator:
+ ret = 0;
+ break;
+ case PM_TitleBarHeight: {
+ NSUInteger style = NSWindowStyleMaskTitled;
+// if (widget && ((widget->windowFlags() & Qt::Tool) == Qt::Tool))
+// style |= NSWindowStyleMaskUtilityWindow;
+ ret = int([NSWindow frameRectForContentRect:NSZeroRect
+ styleMask:style].size.height);
+ break; }
+ case QStyle::PM_TabBarTabHSpace:
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeLarge:
+ ret = QCommonStyle::pixelMetric(metric, opt);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = 20;
+ break;
+ case QStyleHelper::SizeMini:
+ ret = 16;
+ break;
+ case QStyleHelper::SizeDefault:
+ const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
+ if (tb && tb->documentMode)
+ ret = 30;
+ else
+ ret = QCommonStyle::pixelMetric(metric, opt);
+ break;
+ }
+ break;
+ case PM_TabBarTabVSpace:
+ ret = 4;
+ break;
+ case PM_TabBarTabShiftHorizontal:
+ case PM_TabBarTabShiftVertical:
+ ret = 0;
+ break;
+ case PM_TabBarBaseHeight:
+ ret = 0;
+ break;
+ case PM_TabBarTabOverlap:
+ ret = 1;
+ break;
+ case PM_TabBarBaseOverlap:
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeDefault:
+ case QStyleHelper::SizeLarge:
+ ret = 11;
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = 8;
+ break;
+ case QStyleHelper::SizeMini:
+ ret = 7;
+ break;
+ }
+ break;
+ case PM_ScrollBarExtent: {
+ const QStyleHelper::WidgetSizePolicy size = d->effectiveAquaSizeConstrain(opt);
+ ret = static_cast<int>([NSScroller
+ scrollerWidthForControlSize:static_cast<NSControlSize>(size)
+ scrollerStyle:[NSScroller preferredScrollerStyle]]);
+ break; }
+ case PM_IndicatorHeight: {
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeDefault:
+ case QStyleHelper::SizeLarge:
+ ret = qt_mac_aqua_get_metric(CheckBoxHeight);
+ break;
+ case QStyleHelper::SizeMini:
+ ret = qt_mac_aqua_get_metric(MiniCheckBoxHeight);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = qt_mac_aqua_get_metric(SmallCheckBoxHeight);
+ break;
+ }
+ break; }
+ case PM_IndicatorWidth: {
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeDefault:
+ case QStyleHelper::SizeLarge:
+ ret = qt_mac_aqua_get_metric(CheckBoxWidth);
+ break;
+ case QStyleHelper::SizeMini:
+ ret = qt_mac_aqua_get_metric(MiniCheckBoxWidth);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = qt_mac_aqua_get_metric(SmallCheckBoxWidth);
+ break;
+ }
+ ++ret;
+ break; }
+ case PM_ExclusiveIndicatorHeight: {
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeDefault:
+ case QStyleHelper::SizeLarge:
+ ret = qt_mac_aqua_get_metric(RadioButtonHeight);
+ break;
+ case QStyleHelper::SizeMini:
+ ret = qt_mac_aqua_get_metric(MiniRadioButtonHeight);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = qt_mac_aqua_get_metric(SmallRadioButtonHeight);
+ break;
+ }
+ break; }
+ case PM_ExclusiveIndicatorWidth: {
+ switch (d->aquaSizeConstrain(opt)) {
+ case QStyleHelper::SizeDefault:
+ case QStyleHelper::SizeLarge:
+ ret = qt_mac_aqua_get_metric(RadioButtonWidth);
+ break;
+ case QStyleHelper::SizeMini:
+ ret = qt_mac_aqua_get_metric(MiniRadioButtonWidth);
+ break;
+ case QStyleHelper::SizeSmall:
+ ret = qt_mac_aqua_get_metric(SmallRadioButtonWidth);
+ break;
+ }
+ ++ret;
+ break; }
+ case PM_MenuVMargin:
+ ret = 4;
+ break;
+ case PM_MenuPanelWidth:
+ ret = 0;
+ break;
+ case PM_ToolTipLabelFrameWidth:
+ ret = 0;
+ break;
+ case PM_SizeGripSize: {
+ QStyleHelper::WidgetSizePolicy aSize;
+// if (widget && widget->window()->windowType() == Qt::Tool)
+// aSize = QStyleHelper::SizeSmall;
+// else
+ aSize = QStyleHelper::SizeLarge;
+ const QSize size = qt_aqua_get_known_size(CT_SizeGrip, opt, QSize(), aSize);
+ ret = size.width();
+ break; }
+ case PM_MdiSubWindowFrameWidth:
+ ret = 1;
+ break;
+ case PM_DockWidgetFrameWidth:
+ ret = 0;
+ break;
+ case PM_DockWidgetTitleMargin:
+ ret = 0;
+ break;
+ case PM_DockWidgetSeparatorExtent:
+ ret = 1;
+ break;
+ case PM_ToolBarHandleExtent:
+ ret = 11;
+ break;
+ case PM_ToolBarItemMargin:
+ ret = 0;
+ break;
+ case PM_ToolBarItemSpacing:
+ ret = 4;
+ break;
+ case PM_SplitterWidth:
+ ret = 7;
+ break;
+ case PM_LayoutLeftMargin:
+ case PM_LayoutTopMargin:
+ case PM_LayoutRightMargin:
+ case PM_LayoutBottomMargin:
+ {
+ if (opt->state & State_Window) {
+ /*
+ AHIG would have (20, 8, 10) here but that makes
+ no sense. It would also have 14 for the top margin
+ but this contradicts both Builder and most
+ applications.
+ */
+ return_SIZE(20, 10, 10); // AHIG
+ } else {
+ // hack to detect QTabWidget
+// if (widget && widget->parentWidget()
+// && widget->parentWidget()->sizePolicy().controlType() == QSizePolicy::TabWidget) {
+// if (metric == PM_LayoutTopMargin) {
+// /*
+// Builder would have 14 (= 20 - 6) instead of 12,
+// but that makes the tab look disproportionate.
+// */
+// return_SIZE(12, 6, 6); // guess
+// } else {
+// return_SIZE(20 /* Builder */, 8 /* guess */, 8 /* guess */);
+// }
+// } else {
+ /*
+ Child margins are highly inconsistent in AHIG and Builder.
+ */
+ return_SIZE(12, 8, 6); // guess
+// }
+ }
+ }
+ case PM_LayoutHorizontalSpacing:
+ case PM_LayoutVerticalSpacing:
+ return -1;
+ case PM_MenuHMargin:
+ ret = 0;
+ break;
+ case PM_ToolBarExtensionExtent:
+ ret = 21;
+ break;
+ case PM_ToolBarFrameWidth:
+ ret = 1;
+ break;
+ case PM_ScrollView_ScrollBarOverlap:
+ ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay ?
+ pixelMetric(PM_ScrollBarExtent, opt) : 0;
+ break;
+ case PM_PushButtonFocusFrameRadius:
+ ret = LargeSmallMini(opt, 8, 7, 5);
+ break;
+ case PM_CheckBoxFocusFrameRadius:
+ ret = LargeSmallMini(opt, 6, 5, 4);
+ break;
+ case PM_ComboBoxFocusFrameRadius:
+ ret = LargeSmallMini(opt, 8, 7, 4);
+ break;
+ case PM_RadioButtonFocusFrameRadius:
+ ret = 10;
+ break;
+ case PM_SliderFocusFrameRadius:
+ // QTBUG-93423: We currently need to skip drawing a focus ring around the handle, since
+ // the handle drawn by the UIKit is not centered inside the rect we get from calling
+ // [cell knobRectFlipped:slider.isFlipped]. So we choose to draw the focus as
+ // a rect instead until we have a better solution available.
+ ret = 0;
+ break;
+ case PM_DialFocusFrameRadius:
+ case PM_SpinBoxFocusFrameRadius:
+ case PM_TextAreaFocusFrameRadius:
+ case PM_TextFieldFocusFrameRadius:
+ ret = 3;
+ break;
+ default:
+ ret = QCommonStyle::pixelMetric(metric, opt);
+ break;
+ }
+ return ret;
+}
+
+//QPalette QMacStyle::standardPalette() const
+//{
+// auto platformTheme = QGuiApplicationPrivate::platformTheme();
+// auto styleNames = platformTheme->themeHint(QPlatformTheme::StyleNames);
+// if (styleNames.toStringList().contains("macintosh"))
+// return QPalette(); // Inherit everything from theme
+// else
+// return QStyle::standardPalette();
+//}
+
+int QMacStyle::styleHint(StyleHint sh, const QStyleOption *opt, QStyleHintReturn *hret) const
+{
+ QMacAutoReleasePool pool;
+
+ int ret = 0;
+ switch (sh) {
+ case SH_Slider_SnapToValue:
+ case SH_PrintDialog_RightAlignButtons:
+ case SH_FontDialog_SelectAssociatedText:
+ case SH_MenuBar_MouseTracking:
+ case SH_Menu_MouseTracking:
+ case SH_ComboBox_ListMouseTracking:
+ case SH_MainWindow_SpaceBelowMenuBar:
+ case SH_ItemView_ChangeHighlightOnFocus:
+ ret = 1;
+ break;
+ case SH_ToolBox_SelectedPageTitleBold:
+ ret = 0;
+ break;
+ case SH_DialogButtonBox_ButtonsHaveIcons:
+ ret = 0;
+ break;
+ case SH_Menu_SelectionWrap:
+ ret = false;
+ break;
+ case SH_Menu_KeyboardSearch:
+ ret = true;
+ break;
+ case SH_Menu_SpaceActivatesItem:
+ ret = true;
+ break;
+ case SH_Slider_AbsoluteSetButtons:
+ ret = Qt::LeftButton|Qt::MiddleButton;
+ break;
+ case SH_Slider_PageSetButtons:
+ ret = 0;
+ break;
+ case SH_ScrollBar_ContextMenu:
+ ret = false;
+ break;
+ case SH_TitleBar_AutoRaise:
+ ret = true;
+ break;
+ case SH_Menu_AllowActiveAndDisabled:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuPopupDelay:
+ ret = 100;
+ break;
+ case SH_Menu_SubMenuUniDirection:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuSloppySelectOtherActions:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuResetWhenReenteringParent:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuDontStartSloppyOnLeave:
+ ret = true;
+ break;
+
+ case SH_ScrollBar_LeftClickAbsolutePosition: {
+ NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+ bool result = [defaults boolForKey:@"AppleScrollerPagingBehavior"];
+// if(QApplication::keyboardModifiers() & Qt::AltModifier)
+// ret = !result;
+// else
+ ret = result;
+ break; }
+ case SH_TabBar_PreferNoArrows:
+ ret = true;
+ break;
+ /*
+ case SH_DialogButtons_DefaultButton:
+ ret = QDialogButtons::Reject;
+ break;
+ */
+ case SH_GroupBox_TextLabelVerticalAlignment:
+ ret = Qt::AlignTop;
+ break;
+ case SH_ScrollView_FrameOnlyAroundContents:
+ ret = QCommonStyle::styleHint(sh, opt, hret);
+ break;
+ case SH_Menu_FillScreenWithScroll:
+ ret = false;
+ break;
+ case SH_Menu_Scrollable:
+ ret = true;
+ break;
+ case SH_RichText_FullWidthSelection:
+ ret = true;
+ break;
+ case SH_BlinkCursorWhenTextSelected:
+ ret = false;
+ break;
+ case SH_Slider_StopMouseOverSlider:
+ ret = true;
+ break;
+ case SH_ListViewExpand_SelectMouseType:
+ ret = QEvent::MouseButtonRelease;
+ break;
+ case SH_TabBar_SelectMouseType:
+ if (const QStyleOptionTabBarBase *opt2 = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
+ ret = opt2->documentMode ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease;
+ } else {
+ ret = QEvent::MouseButtonRelease;
+ }
+ break;
+ case SH_ComboBox_Popup:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt))
+ ret = !cmb->editable;
+ else
+ ret = 0;
+ break;
+ case SH_Workspace_FillSpaceOnMaximize:
+ ret = true;
+ break;
+ case SH_Widget_ShareActivation:
+ ret = true;
+ break;
+ case SH_Header_ArrowAlignment:
+ ret = Qt::AlignRight;
+ break;
+ case SH_TabBar_Alignment: {
+//#if QT_CONFIG(tabwidget)
+// if (const QTabWidget *tab = qobject_cast<const QTabWidget*>(w)) {
+// if (tab->documentMode()) {
+// ret = Qt::AlignLeft;
+// break;
+// }
+// }
+//#endif
+//#if QT_CONFIG(tabbar)
+// if (const QTabBar *tab = qobject_cast<const QTabBar*>(w)) {
+// if (tab->documentMode()) {
+// ret = Qt::AlignLeft;
+// break;
+// }
+// }
+//#endif
+ ret = Qt::AlignCenter;
+ } break;
+ case SH_UnderlineShortcut:
+ ret = false;
+ break;
+ case SH_ToolTipLabel_Opacity:
+ ret = 242; // About 95%
+ break;
+ case SH_Button_FocusPolicy:
+ ret = Qt::TabFocus;
+ break;
+ case SH_EtchDisabledText:
+ ret = false;
+ break;
+ case SH_FocusFrame_Mask: {
+ ret = true;
+ if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
+ const uchar fillR = 192, fillG = 191, fillB = 190;
+ QImage img;
+
+ QSize pixmapSize = opt->rect.size();
+ if (!pixmapSize.isEmpty()) {
+ QPixmap pix(pixmapSize);
+ pix.fill(QColor(fillR, fillG, fillB));
+ QPainter pix_paint(&pix);
+ proxy()->drawControl(CE_FocusFrame, opt, &pix_paint);
+ pix_paint.end();
+ img = pix.toImage();
+ }
+
+ const QRgb *sptr = (QRgb*)img.bits(), *srow;
+ const qsizetype sbpl = img.bytesPerLine();
+ const int w = sbpl/4, h = img.height();
+
+ QImage img_mask(img.width(), img.height(), QImage::Format_ARGB32);
+ QRgb *dptr = (QRgb*)img_mask.bits(), *drow;
+ const qsizetype dbpl = img_mask.bytesPerLine();
+
+ for (int y = 0; y < h; ++y) {
+ srow = sptr+((y*sbpl)/4);
+ drow = dptr+((y*dbpl)/4);
+ for (int x = 0; x < w; ++x) {
+ const int redDiff = qRed(*srow) - fillR;
+ const int greenDiff = qGreen(*srow) - fillG;
+ const int blueDiff = qBlue(*srow) - fillB;
+ const int diff = (redDiff * redDiff) + (greenDiff * greenDiff) + (blueDiff * blueDiff);
+ (*drow++) = (diff < 10) ? 0xffffffff : 0xff000000;
+ ++srow;
+ }
+ }
+ QBitmap qmask = QBitmap::fromImage(img_mask);
+ mask->region = QRegion(qmask);
+ }
+ break; }
+ case SH_TitleBar_NoBorder:
+ ret = 1;
+ break;
+ case SH_RubberBand_Mask:
+ ret = 0;
+ break;
+ case SH_ComboBox_LayoutDirection:
+ ret = Qt::LeftToRight;
+ break;
+ case SH_ItemView_EllipsisLocation:
+ ret = Qt::AlignHCenter;
+ break;
+ case SH_ItemView_ShowDecorationSelected:
+ ret = true;
+ break;
+ case SH_TitleBar_ModifyNotification:
+ ret = false;
+ break;
+ case SH_ScrollBar_RollBetweenButtons:
+ ret = true;
+ break;
+ case SH_WindowFrame_Mask:
+ ret = false;
+ break;
+ case SH_TabBar_ElideMode:
+ ret = Qt::ElideRight;
+ break;
+// case SH_DialogButtonLayout:
+// ret = QDialogButtonBox::MacLayout;
+// break;
+// case SH_FormLayoutWrapPolicy:
+// ret = QFormLayout::DontWrapRows;
+// break;
+// case SH_FormLayoutFieldGrowthPolicy:
+// ret = QFormLayout::FieldsStayAtSizeHint;
+// break;
+ case SH_FormLayoutFormAlignment:
+ ret = Qt::AlignHCenter | Qt::AlignTop;
+ break;
+ case SH_FormLayoutLabelAlignment:
+ ret = Qt::AlignRight;
+ break;
+// case SH_ComboBox_PopupFrameStyle:
+// ret = QFrame::NoFrame;
+// break;
+ case SH_MessageBox_TextInteractionFlags:
+ ret = Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse | Qt::TextSelectableByKeyboard;
+ break;
+ case SH_SpellCheckUnderlineStyle:
+ ret = QTextCharFormat::DashUnderline;
+ break;
+ case SH_MessageBox_CenterButtons:
+ ret = false;
+ break;
+ case SH_MenuBar_AltKeyNavigation:
+ ret = false;
+ break;
+ case SH_ItemView_MovementWithoutUpdatingSelection:
+ ret = false;
+ break;
+ case SH_FocusFrame_AboveWidget:
+ ret = true;
+ break;
+// case SH_WizardStyle:
+// ret = QWizard::MacStyle;
+// break;
+ case SH_ItemView_ArrowKeysNavigateIntoChildren:
+ ret = false;
+ break;
+ case SH_Menu_FlashTriggeredItem:
+ ret = true;
+ break;
+ case SH_Menu_FadeOutOnHide:
+ ret = true;
+ break;
+ case SH_ItemView_PaintAlternatingRowColorsForEmptyArea:
+ ret = true;
+ break;
+ case SH_TabBar_CloseButtonPosition:
+ ret = QStyleOptionTabBarBase::LeftSide;
+ break;
+ case SH_DockWidget_ButtonsHaveFrame:
+ ret = false;
+ break;
+ case SH_ScrollBar_Transient:
+ // For the initial version in QQC2, we don't support transient scrollbars. When the
+ // time comes, consider doing all such animations from QML.
+ // ret = [NSScroller preferredScrollerStyle] == NSScrollerStyleOverlay;
+ ret = false;
+ break;
+ case SH_TitleBar_ShowToolTipsOnButtons:
+ // min/max/close buttons on windows don't show tool tips
+ ret = false;
+ break;
+ case SH_ComboBox_AllowWheelScrolling:
+ ret = false;
+ break;
+ case SH_SpinBox_ButtonsInsideFrame:
+ ret = false;
+ break;
+ case SH_Table_GridLineColor:
+ ret = int(qt_mac_toQColor(NSColor.gridColor).rgba());
+ break;
+ default:
+ ret = QCommonStyle::styleHint(sh, opt, hret);
+ break;
+ }
+ return ret;
+}
+
+QPixmap QMacStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
+ const QStyleOption *opt) const
+{
+ switch (iconMode) {
+ case QIcon::Disabled: {
+ QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ int imgh = img.height();
+ int imgw = img.width();
+ QRgb pixel;
+ for (int y = 0; y < imgh; ++y) {
+ for (int x = 0; x < imgw; ++x) {
+ pixel = img.pixel(x, y);
+ img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel),
+ qAlpha(pixel) / 2));
+ }
+ }
+ return QPixmap::fromImage(img);
+ }
+ default:
+ ;
+ }
+ return QCommonStyle::generatedIconPixmap(iconMode, pixmap, opt);
+}
+
+
+QPixmap QMacStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt) const
+{
+ // The default implementation of QStyle::standardIconImplementation() is to call standardPixmap()
+ // I don't want infinite recursion so if we do get in that situation, just return the Window's
+ // standard pixmap instead (since there is no mac-specific icon then). This should be fine until
+ // someone changes how Windows standard
+ // pixmap works.
+ static bool recursionGuard = false;
+
+ if (recursionGuard)
+ return QCommonStyle::standardPixmap(standardPixmap, opt);
+
+ recursionGuard = true;
+ QIcon icon = proxy()->standardIcon(standardPixmap, opt);
+ recursionGuard = false;
+ int size;
+ switch (standardPixmap) {
+ default:
+ size = 32;
+ break;
+ case SP_MessageBoxCritical:
+ case SP_MessageBoxQuestion:
+ case SP_MessageBoxInformation:
+ case SP_MessageBoxWarning:
+ size = 64;
+ break;
+ }
+ return icon.pixmap(opt->window, QSize(size, size));
+}
+
+void QMacStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const
+{
+ Q_D(const QMacStyle);
+
+ const AppearanceSync appSync;
+ QMacCGContext cg(p);
+ d->resolveCurrentNSView(opt->window);
+
+ switch (pe) {
+ case PE_IndicatorArrowUp:
+ case PE_IndicatorArrowDown:
+ case PE_IndicatorArrowRight:
+ case PE_IndicatorArrowLeft: {
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing);
+ const int xOffset = 1; // FIXME: opt->direction == Qt::LeftToRight ? 2 : -1;
+ qreal halfSize = 0.5 * qMin(opt->rect.width(), opt->rect.height());
+ const qreal penWidth = qMax(halfSize / 3.0, 1.25);
+//#if QT_CONFIG(toolbutton)
+// if (const QToolButton *tb = qobject_cast<const QToolButton *>(w)) {
+// // When stroking the arrow, make sure it fits in the tool button
+// if (tb->arrowType() != Qt::NoArrow
+// || tb->popupMode() == QToolButton::MenuButtonPopup)
+// halfSize -= penWidth;
+// }
+//#endif
+
+ QTransform transform;
+ transform.translate(opt->rect.center().x() + xOffset, opt->rect.center().y() + 2);
+ QPainterPath path;
+ switch(pe) {
+ default:
+ case PE_IndicatorArrowDown:
+ break;
+ case PE_IndicatorArrowUp:
+ transform.rotate(180);
+ break;
+ case PE_IndicatorArrowLeft:
+ transform.rotate(90);
+ break;
+ case PE_IndicatorArrowRight:
+ transform.rotate(-90);
+ break;
+ }
+ p->setTransform(transform);
+
+ path.moveTo(-halfSize, -halfSize * 0.5);
+ path.lineTo(0.0, halfSize * 0.5);
+ path.lineTo(halfSize, -halfSize * 0.5);
+
+ const QPen arrowPen(opt->palette.text(), penWidth,
+ Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
+ p->strokePath(path, arrowPen);
+ p->restore();
+ break; }
+ case PE_FrameTabBarBase:
+ if (const QStyleOptionTabBarBase *tbb
+ = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
+ if (tbb->documentMode) {
+ p->save();
+ drawTabBase(p, tbb);
+ p->restore();
+ return;
+ }
+ QRegion region(tbb->rect);
+ region -= tbb->tabBarRect;
+ p->save();
+ p->setClipRegion(region);
+ QStyleOptionTabWidgetFrame twf;
+ twf.QStyleOption::operator=(*tbb);
+ twf.shape = tbb->shape;
+ switch (QMacStylePrivate::tabDirection(twf.shape)) {
+ case QMacStylePrivate::North:
+ twf.rect = twf.rect.adjusted(0, 0, 0, 10);
+ break;
+ case QMacStylePrivate::South:
+ twf.rect = twf.rect.adjusted(0, -10, 0, 0);
+ break;
+ case QMacStylePrivate::West:
+ twf.rect = twf.rect.adjusted(0, 0, 10, 0);
+ break;
+ case QMacStylePrivate::East:
+ twf.rect = twf.rect.adjusted(0, -10, 0, 0);
+ break;
+ }
+ proxy()->drawPrimitive(PE_FrameTabWidget, &twf, p);
+ p->restore();
+ }
+ break;
+ case PE_PanelTipLabel:
+ p->fillRect(opt->rect, opt->palette.brush(QPalette::ToolTipBase));
+ break;
+ case PE_FrameGroupBox:
+ if (const auto *groupBox = qstyleoption_cast<const QStyleOptionFrame *>(opt))
+ if (groupBox->features & QStyleOptionFrame::Flat) {
+ QCommonStyle::drawPrimitive(pe, groupBox, p);
+ break;
+ }
+ Q_FALLTHROUGH();
+ case PE_FrameTabWidget:
+ {
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Box, QStyleHelper::SizeLarge);
+ auto *box = static_cast<NSBox *>(d->cocoaControl(cw));
+ // FIXME Since macOS 10.14, simply calling drawRect: won't display anything anymore.
+ // The AppKit team is aware of this and has proposed a couple of solutions.
+ // The first solution was to call displayRectIgnoringOpacity:inContext: instead.
+ // However, it doesn't seem to work on 10.13. More importantly, dark mode on 10.14
+ // is extremely slow. Light mode works fine.
+ // The second solution is to subclass NSBox and reimplement a trivial drawRect: which
+ // would only call super. This works without any issue on 10.13, but a double border
+ // shows on 10.14 in both light and dark modes.
+ // The code below picks what works on each version and mode. On 10.13 and earlier, we
+ // simply call drawRect: on a regular NSBox. On 10.14, we call displayRectIgnoringOpacity:
+ // inContext:, but only in light mode. In dark mode, we use a custom NSBox subclass,
+ // QDarkNSBox, of type NSBoxCustom. Its appearance is close enough to the real thing so
+ // we can use this for now.
+ auto adjustedRect = opt->rect;
+ bool needTranslation = false;
+ if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave
+ && !qt_mac_applicationIsInDarkMode()) {
+ // In Aqua theme we have to use the 'default' NSBox (as opposite
+ // to the 'custom' QDarkNSBox we use in dark theme). Since -drawRect:
+ // does nothing in default NSBox, we call -displayRectIgnoringOpaticty:.
+ // Unfortunately, the resulting box is smaller then the actual rect we
+ // wanted. This can be seen, e.g. because tabs (buttons) are misaligned
+ // vertically and even worse, if QTabWidget has autoFillBackground
+ // set, this background overpaints NSBox making it to disappear.
+ // We trick our NSBox to render in a larger rectangle, so that
+ // the actuall result (which is again smaller than requested),
+ // more or less is what we really want. We'll have to adjust CTM
+ // and translate accordingly.
+ adjustedRect.adjust(0, 0, 6, 6);
+ needTranslation = true;
+ }
+ d->drawNSViewInRect(box, adjustedRect, p, ^(CGContextRef ctx, const CGRect &rect) {
+//#if QT_CONFIG(tabwidget)
+// if (QTabWidget *tabWidget = qobject_cast<QTabWidget *>(opt->styleObject))
+// clipTabBarFrame(opt, this, ctx);
+//#endif
+ QMacAutoReleasePool pool;
+ CGContextTranslateCTM(ctx, 0, rect.origin.y + rect.size.height);
+ CGContextScaleCTM(ctx, 1, -1);
+ if (QOperatingSystemVersion::current() < QOperatingSystemVersion::MacOSMojave
+ || [box isMemberOfClass:QDarkNSBox.class]) {
+ [box drawRect:rect];
+ } else {
+ if (needTranslation)
+ CGContextTranslateCTM(ctx, -3.0, 5.0);
+ [box displayRectIgnoringOpacity:box.bounds inContext:NSGraphicsContext.currentContext];
+ }
+ });
+ break;
+ }
+ case PE_IndicatorToolBarSeparator: {
+ QPainterPath path;
+ if (opt->state & State_Horizontal) {
+ int xpoint = opt->rect.center().x();
+ path.moveTo(xpoint + 0.5, opt->rect.top() + 1);
+ path.lineTo(xpoint + 0.5, opt->rect.bottom());
+ } else {
+ int ypoint = opt->rect.center().y();
+ path.moveTo(opt->rect.left() + 2 , ypoint + 0.5);
+ path.lineTo(opt->rect.right() + 1, ypoint + 0.5);
+ }
+ QPainterPathStroker theStroker;
+ theStroker.setCapStyle(Qt::FlatCap);
+ theStroker.setDashPattern(QVector<qreal>() << 1 << 2);
+ path = theStroker.createStroke(path);
+ const auto dark = qt_mac_applicationIsInDarkMode() ? opt->palette.dark().color().darker()
+ : QColor(0, 0, 0, 119);
+ p->fillPath(path, dark);
+ }
+ break;
+ case PE_FrameWindow:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+// if (w && w->inherits("QMdiSubWindow")) {
+// p->save();
+// p->setPen(QPen(frame->palette.dark().color(), frame->lineWidth));
+// p->setBrush(frame->palette.window());
+// p->drawRect(frame->rect);
+// p->restore();
+// }
+ }
+ break;
+ case PE_IndicatorDockWidgetResizeHandle: {
+ // The docwidget resize handle is drawn as a one-pixel wide line.
+ p->save();
+ if (opt->state & State_Horizontal) {
+ p->setPen(QColor(160, 160, 160));
+ p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
+ } else {
+ p->setPen(QColor(145, 145, 145));
+ p->drawLine(opt->rect.topRight(), opt->rect.bottomRight());
+ }
+ p->restore();
+ } break;
+ case PE_IndicatorToolBarHandle: {
+ p->save();
+ QPainterPath path;
+ int x = opt->rect.x() + 6;
+ int y = opt->rect.y() + 7;
+ static const int RectHeight = 2;
+ if (opt->state & State_Horizontal) {
+ while (y < opt->rect.height() - RectHeight - 5) {
+ path.moveTo(x, y);
+ path.addEllipse(x, y, RectHeight, RectHeight);
+ y += 6;
+ }
+ } else {
+ while (x < opt->rect.width() - RectHeight - 5) {
+ path.moveTo(x, y);
+ path.addEllipse(x, y, RectHeight, RectHeight);
+ x += 6;
+ }
+ }
+ p->setPen(Qt::NoPen);
+ QColor dark = opt->palette.dark().color().darker();
+ dark.setAlphaF(0.50);
+ p->fillPath(path, dark);
+ p->restore();
+
+ break;
+ }
+ case PE_IndicatorHeaderArrow:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ // In HITheme, up is down, down is up and hamburgers eat people.
+ if (header->sortIndicator != QStyleOptionHeader::None)
+ proxy()->drawPrimitive(
+ (header->sortIndicator == QStyleOptionHeader::SortDown) ?
+ PE_IndicatorArrowUp : PE_IndicatorArrowDown, header, p);
+ }
+ break;
+ case PE_IndicatorMenuCheckMark: {
+ QColor pc;
+ if (opt->state & State_On)
+ pc = opt->palette.highlightedText().color();
+ else
+ pc = opt->palette.text().color();
+
+ QCFType<CGColorRef> checkmarkColor = CGColorCreateGenericRGB(static_cast<CGFloat>(pc.redF()),
+ static_cast<CGFloat>(pc.greenF()),
+ static_cast<CGFloat>(pc.blueF()),
+ static_cast<CGFloat>(pc.alphaF()));
+ // kCTFontUIFontSystem and others give the same result
+ // as kCTFontUIFontMenuItemMark. However, the latter is
+ // more reminiscent to HITheme's kThemeMenuItemMarkFont.
+ // See also the font for small- and mini-sized widgets,
+ // where we end up using the generic system font type.
+ const CTFontUIFontType fontType = (opt->state & State_Mini) ? kCTFontUIFontMiniSystem :
+ (opt->state & State_Small) ? kCTFontUIFontSmallSystem :
+ kCTFontUIFontMenuItemMark;
+ // Similarly for the font size, where there is a small difference
+ // between regular combobox and item view items, and and menu items.
+ // However, we ignore any difference for small- and mini-sized widgets.
+ const CGFloat fontSize = fontType == kCTFontUIFontMenuItemMark ? opt->fontMetrics.height() : 0.0;
+ QCFType<CTFontRef> checkmarkFont = CTFontCreateUIFontForLanguage(fontType, fontSize, NULL);
+
+ CGContextSaveGState(cg);
+ CGContextSetShouldSmoothFonts(cg, NO); // Same as HITheme and Cocoa menu checkmarks
+
+ // Baseline alignment tweaks for QComboBox and QMenu
+ const CGFloat vOffset = (opt->state & State_Mini) ? 0.0 :
+ (opt->state & State_Small) ? 1.0 :
+ 0.75;
+
+ CGContextTranslateCTM(cg, 0, opt->rect.bottom());
+ CGContextScaleCTM(cg, 1, -1);
+ // Translate back to the original position and add rect origin and offset
+ CGContextTranslateCTM(cg, opt->rect.x(), vOffset);
+
+ // CTFont has severe difficulties finding the checkmark character among its
+ // glyphs. Fortunately, CTLine knows its ways inside the Cocoa labyrinth.
+ static const CFStringRef keys[] = { kCTFontAttributeName, kCTForegroundColorAttributeName };
+ static const int numValues = sizeof(keys) / sizeof(keys[0]);
+ const CFTypeRef values[] = { (CFTypeRef)checkmarkFont, (CFTypeRef)checkmarkColor };
+ Q_STATIC_ASSERT((sizeof(values) / sizeof(values[0])) == numValues);
+ QCFType<CFDictionaryRef> attributes = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values,
+ numValues, NULL, NULL);
+ // U+2713: CHECK MARK
+ QCFType<CFAttributedStringRef> checkmarkString = CFAttributedStringCreate(kCFAllocatorDefault, (CFStringRef)@"\u2713", attributes);
+ QCFType<CTLineRef> line = CTLineCreateWithAttributedString(checkmarkString);
+
+ CTLineDraw((CTLineRef)line, cg);
+ CGContextFlush(cg); // CTLineDraw's documentation says it doesn't flush
+
+ CGContextRestoreGState(cg);
+ break; }
+ case PE_IndicatorItemViewItemCheck:
+ case PE_IndicatorRadioButton:
+ case PE_IndicatorCheckBox: {
+ const bool isEnabled = opt->state & State_Enabled;
+ const bool isPressed = opt->state & State_Sunken;
+ const bool isRadioButton = (pe == PE_IndicatorRadioButton);
+ const auto ct = isRadioButton ? QMacStylePrivate::Button_RadioButton : QMacStylePrivate::Button_CheckBox;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *tb = static_cast<NSButton *>(d->cocoaControl(cw));
+ tb.enabled = isEnabled;
+ tb.state = (opt->state & State_NoChange) ? NSMixedState :
+ (opt->state & State_On) ? NSOnState : NSOffState;
+ [tb highlight:isPressed];
+ const auto vOffset = [=] {
+ // As measured
+ if (cs == QStyleHelper::SizeMini)
+ return ct == QMacStylePrivate::Button_CheckBox ? -0.5 : 0.5;
+
+ return cs == QStyleHelper::SizeSmall ? 0.5 : 0.0;
+ } ();
+ d->drawNSViewInRect(tb, opt->rect, p, ^(CGContextRef ctx, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ CGContextTranslateCTM(ctx, 0, vOffset);
+ [tb.cell drawInteriorWithFrame:rect inView:tb];
+ });
+ break; }
+ case PE_FrameFocusRect:
+ // Use the our own focus widget stuff.
+ break;
+ case PE_IndicatorBranch: {
+ if (!(opt->state & State_Children))
+ break;
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Button_Disclosure, QStyleHelper::SizeLarge);
+ NSButtonCell *triangleCell = static_cast<NSButtonCell *>(d->cocoaCell(cw));
+ [triangleCell setState:(opt->state & State_Open) ? NSOnState : NSOffState];
+// bool viewHasFocus = (w && w->hasFocus()) || (opt->state & State_HasFocus);
+ bool viewHasFocus = false;
+ [triangleCell setBackgroundStyle:((opt->state & State_Selected) && viewHasFocus) ? NSBackgroundStyleEmphasized : NSBackgroundStyleNormal];
+
+ d->setupNSGraphicsContext(cg, NO);
+
+ QRect qtRect = opt->rect.adjusted(DisclosureOffset, 0, -DisclosureOffset, 0);
+ CGRect rect = CGRectMake(qtRect.x() + 1, qtRect.y(), qtRect.width(), qtRect.height());
+ CGContextTranslateCTM(cg, rect.origin.x, rect.origin.y + rect.size.height);
+ CGContextScaleCTM(cg, 1, -1);
+ CGContextTranslateCTM(cg, -rect.origin.x, -rect.origin.y);
+
+ [triangleCell drawBezelWithFrame:NSRectFromCGRect(rect) inView:[triangleCell controlView]];
+
+ d->restoreNSGraphicsContext(cg);
+ break; }
+
+ case PE_Frame: {
+ const QPen oldPen = p->pen();
+ QPen penCpy = p->pen();
+ penCpy.setWidth(2);
+ penCpy.setColor(opt->palette.dark().color());
+ p->setPen(penCpy);
+ p->drawRect(opt->rect);
+ p->setPen(oldPen);
+ break; }
+ case PE_PanelLineEdit:
+ case PE_FrameLineEdit:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ if (frame->state & State_Sunken) {
+ const bool isEnabled = opt->state & State_Enabled;
+ const bool isReadOnly = opt->state & State_ReadOnly;
+ const bool isRounded = frame->features & QStyleOptionFrame::Rounded;
+ const auto cs = d->effectiveAquaSizeConstrain(opt, CT_LineEdit);
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::TextField, cs);
+ auto *tf = static_cast<NSTextField *>(d->cocoaControl(cw));
+ tf.enabled = isEnabled;
+ tf.editable = !isReadOnly;
+ tf.bezeled = YES;
+ static_cast<NSTextFieldCell *>(tf.cell).bezelStyle = isRounded ? NSTextFieldRoundedBezel : NSTextFieldSquareBezel;
+ tf.frame = opt->rect.toCGRect();
+ d->drawNSViewInRect(tf, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ if (!qt_mac_applicationIsInDarkMode()) {
+ // In 'Dark' mode controls are transparent, so we do not
+ // over-paint the (potentially custom) color in the background.
+ // In 'Light' mode we have to care about the correct
+ // background color. See the comments below for PE_PanelLineEdit.
+ CGContextRef cgContext = NSGraphicsContext.currentContext.CGContext;
+ // See QMacCGContext, here we expect bitmap context created with
+ // color space 'kCGColorSpaceSRGB', if it's something else - we
+ // give up.
+ if (cgContext ? bool(CGBitmapContextGetColorSpace(cgContext)) : false) {
+ tf.drawsBackground = YES;
+ const QColor bgColor = frame->palette.brush(QPalette::Base).color();
+ tf.backgroundColor = [NSColor colorWithSRGBRed:bgColor.redF()
+ green:bgColor.greenF()
+ blue:bgColor.blueF()
+ alpha:bgColor.alphaF()];
+ if (bgColor.alpha() != 255) {
+ // No way we can have it bezeled and transparent ...
+ tf.bordered = YES;
+ }
+ }
+ }
+
+ [tf.cell drawWithFrame:rect inView:tf];
+ });
+ } else {
+ QCommonStyle::drawPrimitive(pe, opt, p);
+ }
+ }
+ break;
+ case PE_PanelScrollAreaCorner: {
+ const QBrush brush(opt->palette.brush(QPalette::Base));
+ p->fillRect(opt->rect, brush);
+ p->setPen(QPen(QColor(217, 217, 217)));
+ p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
+ p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
+ } break;
+ case PE_FrameStatusBarItem:
+ break;
+//#if QT_CONFIG(tabbar)
+// case PE_IndicatorTabClose: {
+// // Make close button visible only on the hovered tab.
+// QTabBar *tabBar = qobject_cast<QTabBar*>(w->parentWidget());
+// const QWidget *closeBtn = w;
+// if (!tabBar) {
+// // QStyleSheetStyle instead of CloseButton (which has
+// // a QTabBar as a parent widget) uses the QTabBar itself:
+// tabBar = qobject_cast<QTabBar *>(const_cast<QWidget*>(w));
+// closeBtn = decltype(closeBtn)(property("_q_styleSheetRealCloseButton").value<void *>());
+// }
+// if (tabBar) {
+// const bool documentMode = tabBar->documentMode();
+// const QTabBarPrivate *tabBarPrivate = static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar));
+// const int hoveredTabIndex = tabBarPrivate->hoveredTabIndex();
+// if (!documentMode ||
+// (hoveredTabIndex != -1 && ((closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::LeftSide)) ||
+// (closeBtn == tabBar->tabButton(hoveredTabIndex, QTabBar::RightSide))))) {
+// const bool hover = (opt->state & State_MouseOver);
+// const bool selected = (opt->state & State_Selected);
+// const bool pressed = (opt->state & State_Sunken);
+// drawTabCloseButton(p, hover, selected, pressed, documentMode);
+// }
+// }
+// } break;
+//#endif // QT_CONFIG(tabbar)
+ case PE_PanelStatusBar: {
+ // Fill the status bar with the titlebar gradient.
+ QLinearGradient linearGrad;
+ const bool isMainWindow = qt_macWindowMainWindow(opt->window);
+ if (isMainWindow)
+ linearGrad = titlebarGradientActive();
+ else
+ linearGrad = titlebarGradientInactive();
+
+ linearGrad.setStart(0, opt->rect.top());
+ linearGrad.setFinalStop(0, opt->rect.bottom());
+ p->fillRect(opt->rect, linearGrad);
+
+ // Draw the black separator line at the top of the status bar.
+ if (isMainWindow)
+ p->setPen(titlebarSeparatorLineActive);
+ else
+ p->setPen(titlebarSeparatorLineInactive);
+ p->drawLine(opt->rect.left(), opt->rect.top(), opt->rect.right(), opt->rect.top());
+
+ break;
+ }
+ case PE_PanelMenu: {
+ p->save();
+ p->fillRect(opt->rect, Qt::transparent);
+ p->setPen(Qt::transparent);
+ p->setBrush(opt->palette.window());
+ p->setRenderHint(QPainter::Antialiasing, true);
+ const QPainterPath path = d->windowPanelPath(opt->rect);
+ p->drawPath(path);
+ p->restore();
+ } break;
+
+ default:
+ QCommonStyle::drawPrimitive(pe, opt, p);
+ break;
+ }
+}
+
+static QPixmap darkenPixmap(const QPixmap &pixmap)
+{
+ QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ int imgh = img.height();
+ int imgw = img.width();
+ int h, s, v, a;
+ QRgb pixel;
+ for (int y = 0; y < imgh; ++y) {
+ for (int x = 0; x < imgw; ++x) {
+ pixel = img.pixel(x, y);
+ a = qAlpha(pixel);
+ QColor hsvColor(pixel);
+ hsvColor.getHsv(&h, &s, &v);
+ s = qMin(100, s * 2);
+ v = v / 2;
+ hsvColor.setHsv(h, s, v);
+ pixel = hsvColor.rgb();
+ img.setPixel(x, y, qRgba(qRed(pixel), qGreen(pixel), qBlue(pixel), a));
+ }
+ }
+ return QPixmap::fromImage(img);
+}
+
+void QMacStylePrivate::setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const
+{
+ if (vertical) {
+ CGContextTranslateCTM(cg, rect.size.height, 0);
+ CGContextRotateCTM(cg, M_PI_2);
+ }
+ if (vertical != reverse) {
+ CGContextTranslateCTM(cg, rect.size.width, 0);
+ CGContextScaleCTM(cg, -1, 1);
+ }
+}
+
+void QMacStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p) const
+{
+ Q_D(const QMacStyle);
+
+ const AppearanceSync sync;
+ const QMacAutoReleasePool pool;
+
+ QMacCGContext cg(p);
+ d->resolveCurrentNSView(opt->window);
+
+ switch (ce) {
+ case CE_HeaderSection:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ State flags = header->state;
+ QRect ir = header->rect;
+ const bool pressed = (flags & State_Sunken) && !(flags & State_On);
+ p->fillRect(ir, pressed ? header->palette.dark() : header->palette.button());
+ p->setPen(QPen(header->palette.dark(), 1.0));
+ if (header->orientation == Qt::Horizontal)
+ p->drawLine(QLineF(ir.right() + 0.5, ir.top() + headerSectionSeparatorInset,
+ ir.right() + 0.5, ir.bottom() - headerSectionSeparatorInset));
+ else
+ p->drawLine(QLineF(ir.left() + headerSectionSeparatorInset, ir.bottom(),
+ ir.right() - headerSectionSeparatorInset, ir.bottom()));
+ }
+
+ break;
+ case CE_HeaderLabel:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ p->save();
+ QRect textr = header->rect;
+ if (!header->icon.isNull()) {
+ QIcon::Mode mode = QIcon::Disabled;
+ if (opt->state & State_Enabled)
+ mode = QIcon::Normal;
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ QPixmap pixmap = header->icon.pixmap(opt->window, QSize(iconExtent, iconExtent), mode);
+
+ QRect pixr = header->rect;
+ pixr.setY(header->rect.center().y() - (pixmap.height() / pixmap.devicePixelRatio() - 1) / 2);
+ proxy()->drawItemPixmap(p, pixr, Qt::AlignVCenter, pixmap);
+ textr.translate(pixmap.width() / pixmap.devicePixelRatio() + 2, 0);
+ }
+
+ proxy()->drawItemText(p, textr, header->textAlignment | Qt::AlignVCenter, header->palette,
+ header->state & State_Enabled, header->text, QPalette::ButtonText);
+ p->restore();
+ }
+ break;
+ case CE_ToolButtonLabel:
+ if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+ QStyleOptionToolButton myTb = *tb;
+ myTb.state &= ~State_AutoRaise;
+#ifndef QT_NO_ACCESSIBILITY
+ if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
+ QRect cr = tb->rect;
+ int shiftX = 0;
+ int shiftY = 0;
+ bool needText = false;
+ int alignment = 0;
+ bool down = tb->state & (State_Sunken | State_On);
+ if (down) {
+ shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb);
+ shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, tb);
+ }
+ // The down state is special for QToolButtons in a toolbar on the Mac
+ // The text is a bit bolder and gets a drop shadow and the icons are also darkened.
+ // This doesn't really fit into any particular case in QIcon, so we
+ // do the majority of the work ourselves.
+ if (!(tb->features & QStyleOptionToolButton::Arrow)) {
+ Qt::ToolButtonStyle tbstyle = tb->toolButtonStyle;
+ if (tb->icon.isNull() && !tb->text.isEmpty())
+ tbstyle = Qt::ToolButtonTextOnly;
+
+ switch (tbstyle) {
+ case Qt::ToolButtonTextOnly: {
+ needText = true;
+ alignment = Qt::AlignCenter;
+ break; }
+ case Qt::ToolButtonIconOnly:
+ case Qt::ToolButtonTextBesideIcon:
+ case Qt::ToolButtonTextUnderIcon: {
+ QRect pr = cr;
+ QIcon::Mode iconMode = (tb->state & State_Enabled) ? QIcon::Normal
+ : QIcon::Disabled;
+ QIcon::State iconState = (tb->state & State_On) ? QIcon::On
+ : QIcon::Off;
+ QPixmap pixmap = tb->icon.pixmap(opt->window,
+ tb->rect.size().boundedTo(tb->iconSize),
+ iconMode, iconState);
+
+ // Draw the text if it's needed.
+ if (tb->toolButtonStyle != Qt::ToolButtonIconOnly) {
+ needText = true;
+ if (tb->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+ pr.setHeight(pixmap.size().height() / pixmap.devicePixelRatio() + 6);
+ cr.adjust(0, pr.bottom(), 0, -3);
+ alignment |= Qt::AlignCenter;
+ } else {
+ pr.setWidth(pixmap.width() / pixmap.devicePixelRatio() + 8);
+ cr.adjust(pr.right(), 0, 0, 0);
+ alignment |= Qt::AlignLeft | Qt::AlignVCenter;
+ }
+ }
+ if (opt->state & State_Sunken) {
+ pr.translate(shiftX, shiftY);
+ pixmap = darkenPixmap(pixmap);
+ }
+ proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pixmap);
+ break; }
+ default:
+ Q_ASSERT(false);
+ break;
+ }
+
+ if (needText) {
+ QPalette pal = tb->palette;
+ QPalette::ColorRole role = QPalette::NoRole;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, tb))
+ alignment |= Qt::TextHideMnemonic;
+ if (down)
+ cr.translate(shiftX, shiftY);
+ if (tbstyle == Qt::ToolButtonTextOnly
+ || (tbstyle != Qt::ToolButtonTextOnly && !down)) {
+ QPen pen = p->pen();
+ QColor light = down || isDarkMode() ? Qt::black : Qt::white;
+ light.setAlphaF(0.375f);
+ p->setPen(light);
+ p->drawText(cr.adjusted(0, 1, 0, 1), alignment, tb->text);
+ p->setPen(pen);
+ if (down && tbstyle == Qt::ToolButtonTextOnly) {
+// pal = QApplication::palette("QMenu");
+ pal.setCurrentColorGroup(tb->palette.currentColorGroup());
+ role = QPalette::HighlightedText;
+ }
+ }
+ proxy()->drawItemText(p, cr, alignment, pal,
+ tb->state & State_Enabled, tb->text, role);
+ }
+ } else {
+ QCommonStyle::drawControl(ce, &myTb, p);
+ }
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
+ QCommonStyle::drawControl(ce, &myTb, p);
+ }
+ }
+ break;
+ case CE_ToolBoxTabShape:
+ QCommonStyle::drawControl(ce, opt, p);
+ break;
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ if (!(btn->state & (State_Raised | State_Sunken | State_On)))
+ break;
+
+ if (btn->features & QStyleOptionButton::CommandLinkButton) {
+ QCommonStyle::drawControl(ce, opt, p);
+ break;
+ }
+
+ const bool hasFocus = btn->state & State_HasFocus;
+ const bool isActive = btn->state & State_Active;
+
+ // a focused auto-default button within an active window
+ // takes precedence over a normal default button
+ if ((btn->features & QStyleOptionButton::AutoDefaultButton)
+ && isActive && hasFocus)
+ d->autoDefaultButton = btn->styleObject;
+ else if (d->autoDefaultButton == btn->styleObject)
+ d->autoDefaultButton = nullptr;
+
+ const bool isEnabled = btn->state & State_Enabled;
+ const bool isPressed = btn->state & State_Sunken;
+ const bool isHighlighted = isActive &&
+ ((btn->state & State_On)
+ || (btn->features & QStyleOptionButton::DefaultButton)
+ || (btn->features & QStyleOptionButton::AutoDefaultButton
+ && d->autoDefaultButton == btn->styleObject));
+ const bool hasMenu = btn->features & QStyleOptionButton::HasMenu;
+ const auto ct = cocoaControlType(btn);
+ const auto cs = d->effectiveAquaSizeConstrain(btn);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
+ // Ensure same size and location as we used to have with HITheme.
+ // This is more convoluted than we initialy thought. See for example
+ // differences between plain and menu button frames.
+ const QRectF frameRect = cw.adjustedControlFrame(btn->rect);
+ pb.frame = frameRect.toCGRect();
+
+ pb.enabled = isEnabled;
+ [pb highlight:isPressed];
+ pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
+ d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
+ QMacAutoReleasePool pool;
+ [pb.cell drawBezelWithFrame:r inView:pb.superview];
+ });
+ [pb highlight:NO];
+
+ if (hasMenu && cw.type == QMacStylePrivate::Button_SquareButton) {
+ // Using -[NSPopuButtonCell drawWithFrame:inView:] above won't do
+ // it right because we don't set the text in the native button.
+ const int mbi = proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator, btn);
+ const auto ir = frameRect.toRect();
+ int arrowYOffset = 0;
+ const auto ar = visualRect(btn->direction, ir, QRect(ir.right() - mbi - 6, ir.height() / 2 - arrowYOffset, mbi, mbi));
+
+ QStyleOption arrowOpt = *opt;
+ arrowOpt.rect = ar;
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
+ }
+ }
+ break;
+ case CE_PushButtonLabel:
+ if (const QStyleOptionButton *b = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ QStyleOptionButton btn(*b);
+ // We really don't want the label to be drawn the same as on
+ // windows style if it has an icon and text, then it should be more like a
+ // tab. So, cheat a little here. However, if it *is* only an icon
+ // the windows style works great, so just use that implementation.
+ const bool isEnabled = btn.state & State_Enabled;
+ const bool hasMenu = btn.features & QStyleOptionButton::HasMenu;
+ const bool hasIcon = !btn.icon.isNull();
+ const bool hasText = !btn.text.isEmpty();
+ const bool isActive = btn.state & State_Active;
+ const bool isPressed = btn.state & State_Sunken;
+
+ const auto ct = cocoaControlType(&btn);
+
+ if (!hasMenu && ct != QMacStylePrivate::Button_SquareButton) {
+ if (isPressed
+ || (isActive && isEnabled
+ && ((btn.state & State_On)
+ || ((btn.features & QStyleOptionButton::DefaultButton) && !d->autoDefaultButton)
+ || d->autoDefaultButton == btn.styleObject)))
+ btn.palette.setColor(QPalette::ButtonText, Qt::white);
+ }
+
+ if ((!hasIcon && !hasMenu) || (hasIcon && !hasText)) {
+ QCommonStyle::drawControl(ce, &btn, p);
+ } else {
+ QRect freeContentRect = btn.rect;
+ QRect textRect = itemTextRect(
+ btn.fontMetrics, freeContentRect, Qt::AlignCenter, isEnabled, btn.text);
+ if (hasMenu) {
+ textRect.moveTo(11, textRect.top());
+ }
+ // Draw the icon:
+ if (hasIcon) {
+ int contentW = textRect.width();
+ if (hasMenu)
+ contentW += proxy()->pixelMetric(PM_MenuButtonIndicator) + 4;
+ QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled;
+ if (mode == QIcon::Normal && btn.state & State_HasFocus)
+ mode = QIcon::Active;
+ // Decide if the icon is should be on or off:
+ QIcon::State state = QIcon::Off;
+ if (btn.state & State_On)
+ state = QIcon::On;
+ QPixmap pixmap = btn.icon.pixmap(opt->window, btn.iconSize, mode, state);
+ int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
+ int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
+ contentW += pixmapWidth + QMacStylePrivate::PushButtonContentPadding;
+ int iconLeftOffset = freeContentRect.x() + (freeContentRect.width() - contentW) / 2;
+ int iconTopOffset = freeContentRect.y() + (freeContentRect.height() - pixmapHeight) / 2;
+ QRect iconDestRect(iconLeftOffset, iconTopOffset, pixmapWidth, pixmapHeight);
+ QRect visualIconDestRect = visualRect(btn.direction, freeContentRect, iconDestRect);
+ proxy()->drawItemPixmap(p, visualIconDestRect, Qt::AlignLeft | Qt::AlignVCenter, pixmap);
+ int newOffset = iconDestRect.x() + iconDestRect.width()
+ + QMacStylePrivate::PushButtonContentPadding - textRect.x();
+ textRect.adjust(newOffset, 0, newOffset, 0);
+ }
+ // Draw the text:
+ if (hasText) {
+ textRect = visualRect(btn.direction, freeContentRect, textRect);
+ proxy()->drawItemText(p, textRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, btn.palette,
+ isEnabled, btn.text, QPalette::ButtonText);
+ }
+ }
+ }
+ break;
+ case CE_ComboBoxLabel:
+ if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ auto comboCopy = *cb;
+ comboCopy.direction = Qt::LeftToRight;
+ // The rectangle will be adjusted to SC_ComboBoxEditField with comboboxEditBounds()
+ QCommonStyle::drawControl(CE_ComboBoxLabel, &comboCopy, p);
+ }
+ break;
+ case CE_TabBarTabShape:
+ if (const auto *tabOpt = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ if (tabOpt->documentMode) {
+ p->save();
+ bool isUnified = false;
+// if (w) {
+// QRect tabRect = tabOpt->rect;
+// QPoint windowTabStart = w->mapTo(w->window(), tabRect.topLeft());
+// isUnified = isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowTabStart.y());
+// }
+
+ const int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
+ drawTabShape(p, tabOpt, isUnified, tabOverlap);
+
+ p->restore();
+ return;
+ }
+
+ const bool isActive = tabOpt->state & State_Active;
+ const bool isEnabled = tabOpt->state & State_Enabled;
+ const bool isPressed = tabOpt->state & State_Sunken;
+ const bool isSelected = tabOpt->state & State_Selected;
+ const auto tabDirection = QMacStylePrivate::tabDirection(tabOpt->shape);
+ const bool verticalTabs = tabDirection == QMacStylePrivate::East
+ || tabDirection == QMacStylePrivate::West;
+
+ QStyleOptionTab::TabPosition tp = tabOpt->position;
+ QStyleOptionTab::SelectedPosition sp = tabOpt->selectedPosition;
+ if (tabOpt->direction == Qt::RightToLeft && !verticalTabs) {
+ if (tp == QStyleOptionTab::Beginning)
+ tp = QStyleOptionTab::End;
+ else if (tp == QStyleOptionTab::End)
+ tp = QStyleOptionTab::Beginning;
+
+ if (sp == QStyleOptionTab::NextIsSelected)
+ sp = QStyleOptionTab::PreviousIsSelected;
+ else if (sp == QStyleOptionTab::PreviousIsSelected)
+ sp = QStyleOptionTab::NextIsSelected;
+ }
+
+ // Alas, NSSegmentedControl and NSSegmentedCell are letting us down.
+ // We're not able to draw it at will, either calling -[drawSegment:
+ // inFrame:withView:], -[drawRect:] or anything in between. Besides,
+ // there's no public API do draw the pressed state, AFAICS. We'll use
+ // a push NSButton instead and clip the CGContext.
+ // NOTE/TODO: this is not true. On 10.13 NSSegmentedControl works with
+ // some (black?) magic/magic dances, on 10.14 it simply works (was
+ // it fixed in AppKit?). But, indeed, we cannot make a tab 'pressed'
+ // with NSSegmentedControl (only selected), so we stay with buttons
+ // (mixing buttons and NSSegmentedControl for such a simple thing
+ // is too much work).
+
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ // Extra hacks to get the proper pressed appreance when not selected or selected and inactive
+ const bool needsInactiveHack = (!isActive && isSelected);
+ const auto ct = !needsInactiveHack && (isSelected || tp == QStyleOptionTab::OnlyOneTab) ?
+ QMacStylePrivate::Button_PushButton :
+ QMacStylePrivate::Button_PopupButton;
+ const bool isPopupButton = ct == QMacStylePrivate::Button_PopupButton;
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
+
+ auto vOffset = isPopupButton ? 1 : 2;
+ if (tabDirection == QMacStylePrivate::East)
+ vOffset -= 1;
+ const auto outerAdjust = isPopupButton ? 1 : 4;
+ const auto innerAdjust = isPopupButton ? 20 : 10;
+ QRectF frameRect = tabOpt->rect;
+ if (verticalTabs)
+ frameRect = QRectF(frameRect.y(), frameRect.x(), frameRect.height(), frameRect.width());
+ // Adjust before clipping
+ frameRect = frameRect.translated(0, vOffset);
+ switch (tp) {
+ case QStyleOptionTab::Beginning:
+ // Pressed state hack: tweak adjustments in preparation for flip below
+ if (!isSelected && tabDirection == QMacStylePrivate::West)
+ frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
+ else
+ frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
+ break;
+ case QStyleOptionTab::Middle:
+ frameRect = frameRect.adjusted(-innerAdjust, 0, innerAdjust, 0);
+ break;
+ case QStyleOptionTab::End:
+ // Pressed state hack: tweak adjustments in preparation for flip below
+ if (isSelected || tabDirection == QMacStylePrivate::West)
+ frameRect = frameRect.adjusted(-innerAdjust, 0, outerAdjust, 0);
+ else
+ frameRect = frameRect.adjusted(-outerAdjust, 0, innerAdjust, 0);
+ break;
+ case QStyleOptionTab::OnlyOneTab:
+ frameRect = frameRect.adjusted(-outerAdjust, 0, outerAdjust, 0);
+ break;
+ }
+ pb.frame = frameRect.toCGRect();
+
+ pb.enabled = isEnabled;
+ [pb highlight:isPressed];
+ // Set off state when inactive. See needsInactiveHack for when it's selected
+ pb.state = (isActive && isSelected && !isPressed) ? NSOnState : NSOffState;
+
+ const auto drawBezelBlock = ^(CGContextRef ctx, const CGRect &r) {
+ QMacAutoReleasePool pool;
+ CGContextClipToRect(ctx, opt->rect.toCGRect());
+ if (!isSelected || needsInactiveHack) {
+ // Final stage of the pressed state hack: flip NSPopupButton rendering
+ if (!verticalTabs && tp == QStyleOptionTab::End) {
+ CGContextTranslateCTM(ctx, opt->rect.right(), 0);
+ CGContextScaleCTM(ctx, -1, 1);
+ CGContextTranslateCTM(ctx, -frameRect.left(), 0);
+ } else if (tabDirection == QMacStylePrivate::West && tp == QStyleOptionTab::Beginning) {
+ CGContextTranslateCTM(ctx, 0, opt->rect.top());
+ CGContextScaleCTM(ctx, 1, -1);
+ CGContextTranslateCTM(ctx, 0, -frameRect.right());
+ } else if (tabDirection == QMacStylePrivate::East && tp == QStyleOptionTab::End) {
+ CGContextTranslateCTM(ctx, 0, opt->rect.bottom());
+ CGContextScaleCTM(ctx, 1, -1);
+ CGContextTranslateCTM(ctx, 0, -frameRect.left());
+ }
+ }
+
+ // Rotate and translate CTM when vertical
+ // On macOS: positive angle is CW, negative is CCW
+ if (tabDirection == QMacStylePrivate::West) {
+ CGContextTranslateCTM(ctx, 0, frameRect.right());
+ CGContextRotateCTM(ctx, -M_PI_2);
+ CGContextTranslateCTM(ctx, -frameRect.left(), 0);
+ } else if (tabDirection == QMacStylePrivate::East) {
+ CGContextTranslateCTM(ctx, opt->rect.right(), 0);
+ CGContextRotateCTM(ctx, M_PI_2);
+ }
+
+ // Now, if it's a trick with a popup button, it has an arrow
+ // which makes no sense on tabs.
+ NSPopUpArrowPosition oldPosition = NSPopUpArrowAtCenter;
+ NSPopUpButtonCell *pbCell = nil;
+ if (isPopupButton) {
+ pbCell = static_cast<NSPopUpButtonCell *>(pb.cell);
+ oldPosition = pbCell.arrowPosition;
+ pbCell.arrowPosition = NSPopUpNoArrow;
+ }
+
+ [pb.cell drawBezelWithFrame:r inView:pb.superview];
+
+ if (pbCell) // Restore, we may reuse it for a ComboBox.
+ pbCell.arrowPosition = oldPosition;
+ };
+
+ if (needsInactiveHack) {
+ // First, render tab as non-selected tab on a pixamp
+ const qreal pixelRatio = p->device()->devicePixelRatioF();
+ QImage tabPixmap(opt->rect.size() * pixelRatio, QImage::Format_ARGB32_Premultiplied);
+ tabPixmap.setDevicePixelRatio(pixelRatio);
+ tabPixmap.fill(Qt::transparent);
+ QPainter tabPainter(&tabPixmap);
+ d->drawNSViewInRect(pb, frameRect, &tabPainter, ^(CGContextRef ctx, const CGRect &r) {
+ QMacAutoReleasePool pool;
+ CGContextTranslateCTM(ctx, -opt->rect.left(), -opt->rect.top());
+ drawBezelBlock(ctx, r);
+ });
+ tabPainter.end();
+
+ // Then, darken it with the proper shade of gray
+ const qreal inactiveGray = 0.898; // As measured
+ const int inactiveGray8 = qRound(inactiveGray * 255.0);
+ const QRgb inactiveGrayRGB = qRgb(inactiveGray8, inactiveGray8, inactiveGray8);
+ for (int l = 0; l < tabPixmap.height(); ++l) {
+ auto *line = reinterpret_cast<QRgb*>(tabPixmap.scanLine(l));
+ for (int i = 0; i < tabPixmap.width(); ++i) {
+ if (qAlpha(line[i]) == 255) {
+ line[i] = inactiveGrayRGB;
+ } else if (qAlpha(line[i]) > 128) {
+ const int g = qRound(inactiveGray * qRed(line[i]));
+ line[i] = qRgba(g, g, g, qAlpha(line[i]));
+ }
+ }
+ }
+
+ // Finally, draw the tab pixmap on the current painter
+ p->drawImage(opt->rect, tabPixmap);
+ } else {
+ d->drawNSViewInRect(pb, frameRect, p, drawBezelBlock);
+ }
+
+ if (!isSelected && sp != QStyleOptionTab::NextIsSelected
+ && tp != QStyleOptionTab::End
+ && tp != QStyleOptionTab::OnlyOneTab) {
+ static const QPen separatorPen(Qt::black, 1.0);
+ p->save();
+ p->setOpacity(isEnabled ? 0.105 : 0.06); // As measured
+ p->setPen(separatorPen);
+ if (tabDirection == QMacStylePrivate::West) {
+ p->drawLine(QLineF(opt->rect.left() + 1.5, opt->rect.bottom(),
+ opt->rect.right() - 0.5, opt->rect.bottom()));
+ } else if (tabDirection == QMacStylePrivate::East) {
+ p->drawLine(QLineF(opt->rect.left(), opt->rect.bottom(),
+ opt->rect.right() - 0.5, opt->rect.bottom()));
+ } else {
+ p->drawLine(QLineF(opt->rect.right(), opt->rect.top() + 1.0,
+ opt->rect.right(), opt->rect.bottom() - 0.5));
+ }
+ p->restore();
+ }
+ }
+ break;
+ case CE_TabBarTabLabel:
+ if (const auto *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ QStyleOptionTab myTab = *tab;
+ const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
+ const bool verticalTabs = tabDirection == QMacStylePrivate::East
+ || tabDirection == QMacStylePrivate::West;
+
+ // Check to see if we use have the same as the system font
+ // (QComboMenuItem is internal and should never be seen by the
+ // outside world, unless they read the source, in which case, it's
+ // their own fault).
+// const bool nonDefaultFont = p->font() != qt_app_fonts_hash()->value("QComboMenuItem");
+ const bool nonDefaultFont = false;
+
+// if (!myTab.documentMode && (myTab.state & State_Selected) && (myTab.state & State_Active))
+// if (const auto *tabBar = qobject_cast<const QTabBar *>(w))
+// if (!tabBar->tabTextColor(tabBar->currentIndex()).isValid())
+// myTab.palette.setColor(QPalette::WindowText, Qt::white);
+
+ if (myTab.documentMode && isDarkMode()) {
+ bool active = (myTab.state & State_Selected) && (myTab.state & State_Active);
+ myTab.palette.setColor(QPalette::WindowText, active ? Qt::white : Qt::gray);
+ }
+
+ int heightOffset = 0;
+ if (verticalTabs) {
+ heightOffset = -1;
+ } else if (nonDefaultFont) {
+ if (p->fontMetrics().height() == myTab.rect.height())
+ heightOffset = 2;
+ }
+ myTab.rect.setHeight(myTab.rect.height() + heightOffset);
+
+ QCommonStyle::drawControl(ce, &myTab, p);
+ }
+ break;
+ case CE_DockWidgetTitle:
+ if (const auto *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
+ const bool isVertical = dwOpt->verticalTitleBar;
+ const auto effectiveRect = isVertical ? opt->rect.transposed() : opt->rect;
+ p->save();
+ if (isVertical) {
+ p->translate(effectiveRect.left(), effectiveRect.top() + effectiveRect.width());
+ p->rotate(-90);
+ p->translate(-effectiveRect.left(), -effectiveRect.top());
+ }
+
+ // fill title bar background
+ QLinearGradient linearGrad;
+ linearGrad.setStart(QPointF(0, 0));
+ linearGrad.setFinalStop(QPointF(0, 2 * effectiveRect.height()));
+ linearGrad.setColorAt(0, opt->palette.button().color());
+ linearGrad.setColorAt(1, opt->palette.dark().color());
+ p->fillRect(effectiveRect, linearGrad);
+
+ // draw horizontal line at bottom
+ p->setPen(opt->palette.dark().color());
+ p->drawLine(effectiveRect.bottomLeft(), effectiveRect.bottomRight());
+
+ if (!dwOpt->title.isEmpty()) {
+ auto titleRect = proxy()->subElementRect(SE_DockWidgetTitleBarText, opt);
+ if (isVertical)
+ titleRect = QRect(effectiveRect.left() + opt->rect.bottom() - titleRect.bottom(),
+ effectiveRect.top() + titleRect.left() - opt->rect.left(),
+ titleRect.height(),
+ titleRect.width());
+
+ const auto text = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
+ proxy()->drawItemText(p, titleRect, Qt::AlignCenter, dwOpt->palette,
+ dwOpt->state & State_Enabled, text, QPalette::WindowText);
+ }
+ p->restore();
+ }
+ break;
+ case CE_FocusFrame: {
+// const auto *ff = qobject_cast<const QFocusFrame *>(w);
+// const auto *ffw = ff ? ff->widget() : nullptr;
+// const auto ct = [=] {
+// if (ffw) {
+// if (ffw->inherits("QCheckBox"))
+// return QMacStylePrivate::Button_CheckBox;
+// if (ffw->inherits("QRadioButton"))
+// return QMacStylePrivate::Button_RadioButton;
+// if (ffw->inherits("QLineEdit") || ffw->inherits("QTextEdit"))
+// return QMacStylePrivate::TextField;
+// }
+//
+// return QMacStylePrivate::Box; // Not really, just make it the default
+// } ();
+// const auto cs = ffw ? (ffw->testAttribute(Qt::WA_MacMiniSize) ? QStyleHelper::SizeMini :
+// ffw->testAttribute(Qt::WA_MacSmallSize) ? QStyleHelper::SizeSmall :
+// QStyleHelper::SizeLarge) :
+// QStyleHelper::SizeLarge;
+// const int hMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameHMargin, opt);
+// const int vMargin = proxy()->pixelMetric(QStyle::PM_FocusFrameVMargin, opt);
+// d->drawFocusRing(p, opt->rect, hMargin, vMargin, QMacStylePrivate::CocoaControl(ct, cs));
+ break; }
+ case CE_MenuEmptyArea:
+ // Skip: PE_PanelMenu fills in everything
+ break;
+ case CE_MenuItem:
+ case CE_MenuHMargin:
+ case CE_MenuVMargin:
+ case CE_MenuTearoff:
+ case CE_MenuScroller:
+ if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ const bool active = mi->state & State_Selected;
+ if (active)
+ p->fillRect(mi->rect, mi->palette.highlight());
+
+ const QStyleHelper::WidgetSizePolicy widgetSize = d->aquaSizeConstrain(opt);
+
+ if (ce == CE_MenuTearoff) {
+ p->setPen(QPen(mi->palette.dark().color(), 1, Qt::DashLine));
+ p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2 - 1,
+ mi->rect.x() + mi->rect.width() - 4,
+ mi->rect.y() + mi->rect.height() / 2 - 1);
+ p->setPen(QPen(mi->palette.light().color(), 1, Qt::DashLine));
+ p->drawLine(mi->rect.x() + 2, mi->rect.y() + mi->rect.height() / 2,
+ mi->rect.x() + mi->rect.width() - 4,
+ mi->rect.y() + mi->rect.height() / 2);
+ } else if (ce == CE_MenuScroller) {
+ const QSize scrollerSize = QSize(10, 8);
+ const int scrollerVOffset = 5;
+ const int left = mi->rect.x() + (mi->rect.width() - scrollerSize.width()) / 2;
+ const int right = left + scrollerSize.width();
+ int top;
+ int bottom;
+ if (opt->state & State_DownArrow) {
+ bottom = mi->rect.y() + scrollerVOffset;
+ top = bottom + scrollerSize.height();
+ } else {
+ bottom = mi->rect.bottom() - scrollerVOffset;
+ top = bottom - scrollerSize.height();
+ }
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing);
+ QPainterPath path;
+ path.moveTo(left, bottom);
+ path.lineTo(right, bottom);
+ path.lineTo((left + right) / 2, top);
+ p->fillPath(path, opt->palette.buttonText());
+ p->restore();
+ } else if (ce != CE_MenuItem) {
+ break;
+ }
+
+ if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
+ CGColorRef separatorColor = [NSColor quaternaryLabelColor].CGColor;
+ const QRect separatorRect = QRect(mi->rect.left(), mi->rect.center().y(), mi->rect.width(), 2);
+ p->fillRect(separatorRect, qt_mac_toQColor(separatorColor));
+ break;
+ }
+
+ const int maxpmw = mi->maxIconWidth;
+ const bool enabled = mi->state & State_Enabled;
+
+ int xpos = mi->rect.x() + 18;
+ int checkcol = maxpmw;
+ if (!enabled)
+ p->setPen(mi->palette.text().color());
+ else if (active)
+ p->setPen(mi->palette.highlightedText().color());
+ else
+ p->setPen(mi->palette.buttonText().color());
+
+ if (mi->checked) {
+ QStyleOption checkmarkOpt;
+// checkmarkOpt.initFrom(w);
+
+ const int mw = checkcol + macItemFrame;
+ const int mh = mi->rect.height() + macItemFrame;
+ const int xp = mi->rect.x() + macItemFrame;
+ checkmarkOpt.rect = QRect(xp, mi->rect.y() - checkmarkOpt.fontMetrics.descent(), mw, mh);
+
+ checkmarkOpt.state.setFlag(State_On, active);
+ checkmarkOpt.state.setFlag(State_Enabled, enabled);
+ if (widgetSize == QStyleHelper::SizeMini)
+ checkmarkOpt.state |= State_Mini;
+ else if (widgetSize == QStyleHelper::SizeSmall)
+ checkmarkOpt.state |= State_Small;
+
+ // We let drawPrimitive(PE_IndicatorMenuCheckMark) pick the right color
+ checkmarkOpt.palette.setColor(QPalette::HighlightedText, p->pen().color());
+ checkmarkOpt.palette.setColor(QPalette::Text, p->pen().color());
+
+ proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &checkmarkOpt, p);
+ }
+ if (!mi->icon.isNull()) {
+ QIcon::Mode mode = (mi->state & State_Enabled) ? QIcon::Normal
+ : QIcon::Disabled;
+ // Always be normal or disabled to follow the Mac style.
+ int smallIconSize = proxy()->pixelMetric(PM_SmallIconSize);
+ QSize iconSize(smallIconSize, smallIconSize);
+//#if QT_CONFIG(combobox)
+// if (const QComboBox *comboBox = qobject_cast<const QComboBox *>(w)) {
+// iconSize = comboBox->iconSize();
+// }
+//#endif
+ QPixmap pixmap = mi->icon.pixmap(opt->window, iconSize, mode);
+ int pixw = pixmap.width() / pixmap.devicePixelRatio();
+ int pixh = pixmap.height() / pixmap.devicePixelRatio();
+ QRect cr(xpos, mi->rect.y(), checkcol, mi->rect.height());
+ QRect pmr(0, 0, pixw, pixh);
+ pmr.moveCenter(cr.center());
+ p->drawPixmap(pmr.topLeft(), pixmap);
+ xpos += pixw + 6;
+ }
+
+ QString s = mi->text;
+ const auto text_flags = Qt::AlignVCenter | Qt::TextHideMnemonic
+ | Qt::TextSingleLine | Qt::AlignAbsolute;
+ int yPos = mi->rect.y();
+ if (widgetSize == QStyleHelper::SizeMini)
+ yPos += 1;
+
+ const bool isSubMenu = mi->menuItemType == QStyleOptionMenuItem::SubMenu;
+ const int tabwidth = isSubMenu ? 9 : mi->tabWidth;
+
+ QString rightMarginText;
+ if (isSubMenu)
+ rightMarginText = QStringLiteral("\u25b6\ufe0e"); // U+25B6 U+FE0E: BLACK RIGHT-POINTING TRIANGLE
+
+ // If present, save and remove embedded shorcut from text
+ const int tabIndex = s.indexOf(QLatin1Char('\t'));
+ if (tabIndex >= 0) {
+ if (!isSubMenu) // ... but ignore it if it's a submenu.
+ rightMarginText = s.mid(tabIndex + 1);
+ s = s.left(tabIndex);
+ }
+
+ p->save();
+ if (!rightMarginText.isEmpty()) {
+// p->setFont(qt_app_fonts_hash()->value("QMenuItem", p->font()));
+ int xp = mi->rect.right() - tabwidth - macRightBorder + 2;
+ if (!isSubMenu)
+ xp -= macItemHMargin + macItemFrame + 3; // Adjust for shortcut
+ p->drawText(xp, yPos, tabwidth, mi->rect.height(), text_flags | Qt::AlignRight, rightMarginText);
+ }
+
+ if (!s.isEmpty()) {
+ const int xm = macItemFrame + maxpmw + macItemHMargin;
+ QFont myFont = mi->font;
+ // myFont may not have any "hard" flags set. We override
+ // the point size so that when it is resolved against the device, this font will win.
+ // This is mainly to handle cases where someone sets the font on the window
+ // and then the combo inherits it and passes it onward. At that point the resolve mask
+ // is very, very weak. This makes it stonger.
+ myFont.setPointSizeF(QFontInfo(mi->font).pointSizeF());
+
+ // QTBUG-65653: Our own text rendering doesn't look good enough, especially on non-retina
+ // displays. Worked around here while waiting for a proper fix in QCoreTextFontEngine.
+ // Only if we're not using QCoreTextFontEngine we do fallback to our own text rendering.
+ const auto *fontEngine = QFontPrivate::get(myFont)->engineForScript(QChar::Script_Common);
+ Q_ASSERT(fontEngine);
+ if (fontEngine->type() == QFontEngine::Multi) {
+ fontEngine = static_cast<const QFontEngineMulti *>(fontEngine)->engine(0);
+ Q_ASSERT(fontEngine);
+ }
+ if (fontEngine->type() == QFontEngine::Mac) {
+ NSFont *f = (NSFont *)(CTFontRef)fontEngine->handle();
+
+ // Respect the menu item palette as set in the style option.
+ const auto pc = p->pen().color();
+ NSColor *c = [NSColor colorWithSRGBRed:pc.redF()
+ green:pc.greenF()
+ blue:pc.blueF()
+ alpha:pc.alphaF()];
+
+ s = qt_mac_removeMnemonics(s);
+
+ QMacCGContext cgCtx(p);
+ d->setupNSGraphicsContext(cgCtx, YES);
+
+ // Draw at point instead of in rect, as the rect we've computed for the menu item
+ // is based on the font metrics we got from HarfBuzz, so we may risk having CoreText
+ // line-break the string if it doesn't fit the given rect. It's better to draw outside
+ // the rect and possibly overlap something than to have part of the text disappear.
+ [s.toNSString() drawAtPoint:CGPointMake(xpos, yPos)
+ withAttributes:@{ NSFontAttributeName:f, NSForegroundColorAttributeName:c,
+ NSObliquenessAttributeName: [NSNumber numberWithDouble: myFont.italic() ? 0.3 : 0.0]}];
+
+ d->restoreNSGraphicsContext(cgCtx);
+ } else {
+ p->setFont(myFont);
+ p->drawText(xpos, yPos, mi->rect.width() - xm - tabwidth + 1,
+ mi->rect.height(), text_flags, s);
+ }
+ }
+ p->restore();
+ }
+ break;
+ case CE_MenuBarItem:
+ case CE_MenuBarEmptyArea:
+ if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ const bool selected = (opt->state & State_Selected) && (opt->state & State_Enabled) && (opt->state & State_Sunken);
+ const QBrush bg = selected ? mi->palette.highlight() : mi->palette.window();
+ p->fillRect(mi->rect, bg);
+
+ if (ce != CE_MenuBarItem)
+ break;
+
+ if (!mi->icon.isNull()) {
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ drawItemPixmap(p, mi->rect,
+ Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
+ | Qt::TextSingleLine,
+ mi->icon.pixmap(opt->window, QSize(iconExtent, iconExtent),
+ (mi->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled));
+ } else {
+ drawItemText(p, mi->rect,
+ Qt::AlignCenter | Qt::TextHideMnemonic | Qt::TextDontClip
+ | Qt::TextSingleLine,
+ mi->palette, mi->state & State_Enabled,
+ mi->text, selected ? QPalette::HighlightedText : QPalette::ButtonText);
+ }
+ }
+ break;
+ case CE_ProgressBarLabel:
+ case CE_ProgressBarContents:
+ break;
+ case CE_ProgressBarGroove:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
+ const bool inverted = pb->invertedAppearance;
+ bool reverse = pb->direction == Qt::RightToLeft;
+ if (inverted)
+ reverse = !reverse;
+
+ QRect rect = pb->rect;
+ const CGRect cgRect = rect.toCGRect();
+
+ const auto aquaSize = d->aquaSizeConstrain(opt);
+
+// const QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject));
+ QIndeterminateProgressIndicator *ipi = nil;
+// if (isIndeterminate || animation)
+ ipi = static_cast<QIndeterminateProgressIndicator *>(d->cocoaControl({ QMacStylePrivate::ProgressIndicator_Indeterminate, aquaSize }));
+ if (isIndeterminate) {
+ // QIndeterminateProgressIndicator derives from NSProgressIndicator. We use a single
+ // instance that we start animating as soon as one of the progress bars is indeterminate.
+ // Since they will be in sync (as it's the case in Cocoa), we just need to draw it with
+ // the right geometry when the animation triggers an update. However, we can't hide it
+ // entirely between frames since that would stop the animation, so we just set its alpha
+ // value to 0. Same if we remove it from its superview. See QIndeterminateProgressIndicator
+ // implementation for details.
+ //
+ // Quick: consider implementing this animation by using Quick/QML instead.
+ //
+// if (!animation && opt->styleObject) {
+// auto *animation = new QProgressStyleAnimation(d->animateSpeed(QMacStylePrivate::AquaProgressBar), opt->styleObject);
+// // NSProgressIndicator is heavier to draw than the HITheme API, so we reduce the frame rate a couple notches.
+// animation->setFrameRate(QStyleAnimation::FifteenFps);
+// d->startAnimation(animation);
+// [ipi startAnimation];
+// }
+
+ d->setupNSGraphicsContext(cg, NO);
+ d->setupVerticalInvertedXform(cg, reverse, false, cgRect);
+ [ipi drawWithFrame:cgRect inView:d->backingStoreNSView];
+ d->restoreNSGraphicsContext(cg);
+ } else {
+// if (animation) {
+// d->stopAnimation(opt->styleObject);
+// [ipi stopAnimation];
+// }
+
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::ProgressIndicator_Determinate, aquaSize);
+ auto *pi = static_cast<NSProgressIndicator *>(d->cocoaControl(cw));
+ d->drawNSViewInRect(pi, rect, p, ^(CGContextRef ctx, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ d->setupVerticalInvertedXform(ctx, reverse, false, rect);
+ pi.minValue = pb->minimum;
+ pi.maxValue = pb->maximum;
+ pi.doubleValue = pb->progress;
+ [pi drawRect:rect];
+ });
+ }
+ }
+ break;
+ case CE_SizeGrip: {
+ // This is not HIG kosher: Fall back to the old stuff until we decide what to do.
+//#ifndef QT_NO_MDIAREA
+// if (!w || !qobject_cast<QMdiSubWindow *>(w->parentWidget()))
+//#endif
+// break;
+
+// if (w->testAttribute(Qt::WA_MacOpaqueSizeGrip))
+// p->fillRect(opt->rect, opt->palette.window());
+
+// QPen lineColor = QColor(82, 82, 82, 192);
+// lineColor.setWidth(1);
+// p->save();
+// p->setRenderHint(QPainter::Antialiasing);
+// p->setPen(lineColor);
+// const Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : qApp->layoutDirection();
+// const int NumLines = 3;
+// for (int l = 0; l < NumLines; ++l) {
+// const int offset = (l * 4 + 3);
+// QPoint start, end;
+// if (layoutDirection == Qt::LeftToRight) {
+// start = QPoint(opt->rect.width() - offset, opt->rect.height() - 1);
+// end = QPoint(opt->rect.width() - 1, opt->rect.height() - offset);
+// } else {
+// start = QPoint(offset, opt->rect.height() - 1);
+// end = QPoint(1, opt->rect.height() - offset);
+// }
+// p->drawLine(start, end);
+// }
+// p->restore();
+ break;
+ }
+ case CE_Splitter:
+ if (opt->rect.width() > 1 && opt->rect.height() > 1) {
+ const bool isVertical = !(opt->state & QStyle::State_Horizontal);
+ // Qt refers to the layout orientation, while Cocoa refers to the divider's.
+ const auto ct = isVertical ? QMacStylePrivate::SplitView_Horizontal : QMacStylePrivate::SplitView_Vertical;
+ const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
+ auto *sv = static_cast<NSSplitView *>(d->cocoaControl(cw));
+ sv.frame = opt->rect.toCGRect();
+ d->drawNSViewInRect(sv, opt->rect, p, ^(CGContextRef, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ [sv drawDividerInRect:rect];
+ });
+ } else {
+ QPen oldPen = p->pen();
+ p->setPen(opt->palette.dark().color());
+ if (opt->state & QStyle::State_Horizontal)
+ p->drawLine(opt->rect.topLeft(), opt->rect.bottomLeft());
+ else
+ p->drawLine(opt->rect.topLeft(), opt->rect.topRight());
+ p->setPen(oldPen);
+ }
+ break;
+ case CE_RubberBand:
+ if (const QStyleOptionRubberBand *rubber = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
+ QColor fillColor(opt->palette.color(QPalette::Disabled, QPalette::Highlight));
+ if (!rubber->opaque) {
+ QColor strokeColor;
+ // I retrieved these colors from the Carbon-Dev mailing list
+ strokeColor.setHsvF(0, 0, 0.86, 1.0);
+ fillColor.setHsvF(0, 0, 0.53, 0.25);
+ if (opt->rect.width() * opt->rect.height() <= 3) {
+ p->fillRect(opt->rect, strokeColor);
+ } else {
+ QPen oldPen = p->pen();
+ QBrush oldBrush = p->brush();
+ QPen pen(strokeColor);
+ p->setPen(pen);
+ p->setBrush(fillColor);
+ QRect adjusted = opt->rect.adjusted(1, 1, -1, -1);
+ if (adjusted.isValid())
+ p->drawRect(adjusted);
+ p->setPen(oldPen);
+ p->setBrush(oldBrush);
+ }
+ } else {
+ p->fillRect(opt->rect, fillColor);
+ }
+ }
+ break;
+ case CE_ToolBar: {
+ const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt);
+ const bool isDarkMode = qt_mac_applicationIsInDarkMode();
+
+ // Unified title and toolbar drawing. In this mode the cocoa platform plugin will
+ // fill the top toolbar area part with a background gradient that "unifies" with
+ // the title bar. The following code fills the toolBar area with transparent pixels
+ // to make that gradient visible.
+// if (w) {
+//#if QT_CONFIG(mainwindow)
+// if (QMainWindow * mainWindow = qobject_cast<QMainWindow *>(w->window())) {
+// if (toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && mainWindow->unifiedTitleAndToolBarOnMac()) {
+// // fill with transparent pixels.
+// p->save();
+// p->setCompositionMode(QPainter::CompositionMode_Source);
+// p->fillRect(opt->rect, Qt::transparent);
+// p->restore();
+
+// // Draw a horizontal separator line at the toolBar bottom if the "unified" area ends here.
+// // There might be additional toolbars or other widgets such as tab bars in document
+// // mode below. Determine this by making a unified toolbar area test for the row below
+// // this toolbar.
+// const QPoint windowToolbarEnd = w->mapTo(w->window(), opt->rect.bottomLeft());
+// const bool isEndOfUnifiedArea = !isInMacUnifiedToolbarArea(w->window()->windowHandle(), windowToolbarEnd.y() + 1);
+// if (isEndOfUnifiedArea) {
+// const int margin = qt_mac_aqua_get_metric(SeparatorSize);
+// const auto separatorRect = QRect(opt->rect.left(), opt->rect.bottom(), opt->rect.width(), margin);
+// p->fillRect(separatorRect, isDarkMode ? darkModeSeparatorLine : opt->palette.dark().color());
+// }
+// break;
+// }
+// }
+//#endif
+// }
+
+ // draw background gradient
+ QLinearGradient linearGrad;
+ if (opt->state & State_Horizontal)
+ linearGrad = QLinearGradient(0, opt->rect.top(), 0, opt->rect.bottom());
+ else
+ linearGrad = QLinearGradient(opt->rect.left(), 0, opt->rect.right(), 0);
+
+ QColor mainWindowGradientBegin = isDarkMode ? darkMainWindowGradientBegin : lightMainWindowGradientBegin;
+ QColor mainWindowGradientEnd = isDarkMode ? darkMainWindowGradientEnd : lightMainWindowGradientEnd;
+
+ linearGrad.setColorAt(0, mainWindowGradientBegin);
+ linearGrad.setColorAt(1, mainWindowGradientEnd);
+ p->fillRect(opt->rect, linearGrad);
+
+ p->save();
+ QRect toolbarRect = isDarkMode ? opt->rect.adjusted(0, 0, 0, 1) : opt->rect;
+ if (opt->state & State_Horizontal) {
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
+ p->drawLine(toolbarRect.topLeft(), toolbarRect.topRight());
+ p->setPen(isDarkMode ? darkModeSeparatorLine :mainWindowGradientEnd.darker(114));
+ p->drawLine(toolbarRect.bottomLeft(), toolbarRect.bottomRight());
+ } else {
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientBegin.lighter(114));
+ p->drawLine(toolbarRect.topLeft(), toolbarRect.bottomLeft());
+ p->setPen(isDarkMode ? darkModeSeparatorLine : mainWindowGradientEnd.darker(114));
+ p->drawLine(toolbarRect.topRight(), toolbarRect.bottomRight());
+ }
+ p->restore();
+
+ break; }
+ default:
+ QCommonStyle::drawControl(ce, opt, p);
+ break;
+ }
+}
+
+static void setLayoutItemMargins(int left, int top, int right, int bottom, QRect *rect, Qt::LayoutDirection dir)
+{
+ if (dir == Qt::RightToLeft) {
+ rect->adjust(-right, top, -left, bottom);
+ } else {
+ rect->adjust(left, top, right, bottom);
+ }
+}
+
+QRect QMacStyle::subElementRect(SubElement sr, const QStyleOption *opt) const
+{
+ Q_D(const QMacStyle);
+ QRect rect;
+ const int controlSize = getControlSize(opt);
+
+ switch (sr) {
+ case SE_ItemViewItemText:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ int fw = proxy()->pixelMetric(PM_FocusFrameHMargin, opt);
+ // We add the focusframeargin between icon and text in commonstyle
+ rect = QCommonStyle::subElementRect(sr, opt);
+ if (vopt->features & QStyleOptionViewItem::HasDecoration)
+ rect.adjust(-fw, 0, 0, 0);
+ }
+ break;
+ case SE_ToolBoxTabContents:
+ rect = QCommonStyle::subElementRect(sr, opt);
+ break;
+ case SE_PushButtonContents:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ // Comment from the old HITheme days:
+ // "Unlike Carbon, we want the button to always be drawn inside its bounds.
+ // Therefore, the button is a bit smaller, so that even if it got focus,
+ // the focus 'shadow' will be inside. Adjust the content rect likewise."
+ // In the future, we should consider using -[NSCell titleRectForBounds:].
+ // Since it requires configuring the NSButton fully, i.e. frame, image,
+ // title and font, we keep things more manual until we are more familiar
+ // with side effects when changing NSButton state.
+ const auto ct = cocoaControlType(btn);
+ const auto cs = d->effectiveAquaSizeConstrain(btn);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto frameRect = cw.adjustedControlFrame(btn->rect);
+ frameRect -= cw.titleMargins();
+ rect = frameRect.toRect();
+ }
+ break;
+ case SE_HeaderLabel: {
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
+ rect.setRect(opt->rect.x() + margin, opt->rect.y(),
+ opt->rect.width() - margin * 2, opt->rect.height() - 2);
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ // Subtract width needed for arrow, if there is one
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ if (opt->state & State_Horizontal)
+ rect.setWidth(rect.width() - (headerSectionArrowHeight) - (margin * 2));
+ else
+ rect.setHeight(rect.height() - (headerSectionArrowHeight) - (margin * 2));
+ }
+ }
+ rect = visualRect(opt->direction, opt->rect, rect);
+ break;
+ }
+ case SE_HeaderArrow: {
+ int h = opt->rect.height();
+ int w = opt->rect.width();
+ int x = opt->rect.x();
+ int y = opt->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
+
+ if (opt->state & State_Horizontal) {
+ rect.setRect(x + w - margin * 2 - headerSectionArrowHeight, y + 5,
+ headerSectionArrowHeight, h - margin * 2 - 5);
+ } else {
+ rect.setRect(x + 5, y + h - margin * 2 - headerSectionArrowHeight,
+ w - margin * 2 - 5, headerSectionArrowHeight);
+ }
+ rect = visualRect(opt->direction, opt->rect, rect);
+ break;
+ }
+ case SE_ProgressBarGroove:
+ // Wrong in the secondary dimension, but accurate enough in the main dimension.
+ rect = opt->rect;
+ break;
+ case SE_ProgressBarLabel:
+ break;
+ case SE_ProgressBarContents:
+ rect = opt->rect;
+ break;
+ case SE_TreeViewDisclosureItem: {
+ rect = opt->rect;
+ // As previously returned by HIThemeGetButtonContentBounds
+ rect.setLeft(rect.left() + 2 + DisclosureOffset);
+ break;
+ }
+ case SE_TabWidgetLeftCorner:
+ if (const QStyleOptionTabWidgetFrame *twf
+ = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ rect = QRect(QPoint(0, 0), twf->leftCornerWidgetSize);
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ rect = QRect(QPoint(0, twf->rect.height() - twf->leftCornerWidgetSize.height()),
+ twf->leftCornerWidgetSize);
+ break;
+ default:
+ break;
+ }
+ rect = visualRect(twf->direction, twf->rect, rect);
+ }
+ break;
+ case SE_TabWidgetRightCorner:
+ if (const QStyleOptionTabWidgetFrame *twf
+ = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(), 0),
+ twf->rightCornerWidgetSize);
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ rect = QRect(QPoint(twf->rect.width() - twf->rightCornerWidgetSize.width(),
+ twf->rect.height() - twf->rightCornerWidgetSize.height()),
+ twf->rightCornerWidgetSize);
+ break;
+ default:
+ break;
+ }
+ rect = visualRect(twf->direction, twf->rect, rect);
+ }
+ break;
+ case SE_TabWidgetTabContents:
+ rect = QCommonStyle::subElementRect(sr, opt);
+ if (const auto *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ if (twf->lineWidth != 0) {
+ switch (QMacStylePrivate::tabDirection(twf->shape)) {
+ case QMacStylePrivate::North:
+ rect.adjust(+1, +14, -1, -1);
+ break;
+ case QMacStylePrivate::South:
+ rect.adjust(+1, +1, -1, -14);
+ break;
+ case QMacStylePrivate::West:
+ rect.adjust(+14, +1, -1, -1);
+ break;
+ case QMacStylePrivate::East:
+ rect.adjust(+1, +1, -14, -1);
+ }
+ }
+ }
+ break;
+ case SE_TabBarTabText:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ QRect dummyIconRect;
+ d->tabLayout(tab, &rect, &dummyIconRect);
+ }
+ break;
+ case SE_TabBarTabLeftButton:
+ case SE_TabBarTabRightButton:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ bool selected = tab->state & State_Selected;
+ int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
+ int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
+ int hpadding = 5;
+
+ bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
+ || tab->shape == QStyleOptionTab::RoundedWest
+ || tab->shape == QStyleOptionTab::TriangularEast
+ || tab->shape == QStyleOptionTab::TriangularWest;
+
+ QRect tr = tab->rect;
+ if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
+ verticalShift = -verticalShift;
+ if (verticalTabs) {
+ qSwap(horizontalShift, verticalShift);
+ horizontalShift *= -1;
+ verticalShift *= -1;
+ }
+ if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
+ horizontalShift = -horizontalShift;
+
+ tr.adjust(0, 0, horizontalShift, verticalShift);
+ if (selected)
+ {
+ tr.setBottom(tr.bottom() - verticalShift);
+ tr.setRight(tr.right() - horizontalShift);
+ }
+
+ QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
+ int w = size.width();
+ int h = size.height();
+ int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2));
+ int midWidth = ((tr.width() - w) / 2);
+
+ bool atTheTop = true;
+ switch (tab->shape) {
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ atTheTop = (sr == SE_TabBarTabLeftButton);
+ break;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ atTheTop = (sr == SE_TabBarTabRightButton);
+ break;
+ default:
+ if (sr == SE_TabBarTabLeftButton)
+ rect = QRect(tab->rect.x() + hpadding, midHeight, w, h);
+ else
+ rect = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
+ rect = visualRect(tab->direction, tab->rect, rect);
+ }
+ if (verticalTabs) {
+ if (atTheTop)
+ rect = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
+ else
+ rect = QRect(midWidth, tr.y() + hpadding, w, h);
+ }
+ }
+ break;
+ case SE_LineEditContents: {
+ // From using pixelTool with XCode/NSTextTextField
+ int leftPadding = 4;
+ int rightPadding = 4;
+ int topPadding = 4;
+ int bottomPadding = 0;
+
+ if (opt->state & QStyle::State_Small) {
+ topPadding = 3;
+ } else if (opt->state & QStyle::State_Mini) {
+ topPadding = 2;
+ }
+
+ rect = QRect(leftPadding, topPadding, opt->rect.width() - leftPadding - rightPadding,
+ opt->rect.height() - topPadding - bottomPadding);
+ break; }
+ case SE_CheckBoxLayoutItem:
+ rect = opt->rect;
+ if (controlSize == QStyleHelper::SizeLarge) {
+ setLayoutItemMargins(+2, +2, -3, -2, &rect, opt->direction);
+ } else if (controlSize == QStyleHelper::SizeSmall) {
+ setLayoutItemMargins(+1, +2, -2, -1, &rect, opt->direction);
+ } else {
+ setLayoutItemMargins(-0, +0, -1, -0, &rect, opt->direction);
+ }
+ break;
+ case SE_ComboBoxLayoutItem:
+ if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ //#ifndef QT_NO_TOOLBAR
+ // if (widget && qobject_cast<QToolBar *>(widget->parentWidget())) {
+ // // Do nothing, because QToolbar needs the entire widget rect.
+ // // Otherwise it will be clipped. Equivalent to
+ // // widget->setAttribute(Qt::WA_LayoutUsesWidgetRect), but without
+ // // all the hassle.
+ // } else
+ //#endif
+ if (combo->editable)
+ rect = LargeSmallMini(opt,
+ opt->rect.adjusted(5, 6, -6, -7),
+ opt->rect.adjusted(4, 4, -5, -7),
+ opt->rect.adjusted(5, 4, -4, -6));
+ else
+ rect = LargeSmallMini(opt,
+ opt->rect.adjusted(6, 4, -7, -7),
+ opt->rect.adjusted(6, 7, -6, -5),
+ opt->rect.adjusted(9, 5, -5, -7));
+ }
+ break;
+ case SE_LabelLayoutItem:
+ rect = opt->rect;
+ setLayoutItemMargins(+1, 0 /* SHOULD be -1, done for alignment */, 0, 0 /* SHOULD be -1, done for alignment */, &rect, opt->direction);
+ break;
+ case SE_ProgressBarLayoutItem:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ const bool isIndeterminate = (pb->minimum == 0 && pb->maximum == 0);
+ rect = opt->rect;
+
+ if (isIndeterminate) {
+ rect.adjust(1, 2, -1, -2);
+ } else {
+ rect.adjust(1, 1, -1, -2);
+ }
+ }
+ break;
+ case SE_PushButtonLayoutItem:
+ rect = opt->rect;
+ if (const QStyleOptionButton *buttonOpt = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ if ((buttonOpt->features & QStyleOptionButton::Flat))
+ break;
+ }
+ rect = LargeSmallMini(opt,
+ opt->rect.adjusted(7, 5, -7, -7),
+ opt->rect.adjusted(6, 6, -6, -6),
+ opt->rect.adjusted(6, 5, -6, -6));
+ break;
+ case SE_SpinBoxLayoutItem:
+ rect = LargeSmallMini(opt,
+ opt->rect.adjusted(2, 3, -2, -2),
+ opt->rect.adjusted(2, 3, -2, -2),
+ opt->rect.adjusted(2, 3, -2, -2));
+ break;
+ case SE_RadioButtonLayoutItem:
+ rect = LargeSmallMini(opt,
+ opt->rect.adjusted(2, 2, -3, -2),
+ opt->rect.adjusted(2, 2, -3, -2),
+ opt->rect.adjusted(1, 2, -3, -2));
+ break;
+ case SE_SliderLayoutItem:
+ if (const QStyleOptionSlider *sliderOpt
+ = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ rect = opt->rect;
+ if (sliderOpt->subControls & QStyle::SC_SliderHandle) {
+ if (sliderOpt->tickPosition == QStyleOptionSlider::NoTicks)
+ rect.adjust(3, 3, -3, -3);
+ } else {
+ rect.adjust(3, 0, -3, 0);
+ }
+ }
+ break;
+ case SE_ScrollBarLayoutItem:
+ if (const QStyleOptionSlider *sliderOpt = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ rect = opt->rect;
+ }
+ case SE_FrameLayoutItem:
+ // hack because QStyleOptionFrame doesn't have a frameStyle member
+// if (const QFrame *frame = qobject_cast<const QFrame *>(widget)) {
+// rect = opt->rect;
+// switch (frame->frameStyle() & QFrame::Shape_Mask) {
+// case QFrame::HLine:
+// rect.adjust(0, +1, 0, -1);
+// break;
+// case QFrame::VLine:
+// rect.adjust(+1, 0, -1, 0);
+// break;
+// default:
+// ;
+// }
+// }
+ break;
+ case SE_GroupBoxLayoutItem:
+ rect = opt->rect;
+ if (const QStyleOptionGroupBox *groupBoxOpt =
+ qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ /*
+ AHIG is very inconsistent when it comes to group boxes.
+ Basically, we make sure that (non-checkable) group boxes
+ and tab widgets look good when laid out side by side.
+ */
+ if (groupBoxOpt->subControls & (QStyle::SC_GroupBoxCheckBox
+ | QStyle::SC_GroupBoxLabel)) {
+ int delta;
+ if (groupBoxOpt->subControls & QStyle::SC_GroupBoxCheckBox) {
+ delta = SIZE(8, 4, 4); // guess
+ } else {
+ delta = SIZE(15, 12, 12); // guess
+ }
+ rect.setTop(rect.top() + delta);
+ }
+ }
+ rect.setBottom(rect.bottom() - 1);
+ break;
+ case SE_TabWidgetLayoutItem:
+ if (const QStyleOptionTabWidgetFrame *tabWidgetOpt =
+ qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ /*
+ AHIG specifies "12 or 14" as the distance from the window
+ edge. We choose 14 and since the default top margin is 20,
+ the overlap is 6.
+ */
+ rect = tabWidgetOpt->rect;
+ if (tabWidgetOpt->shape == QStyleOptionTab::RoundedNorth)
+ rect.setTop(rect.top() + SIZE(6 /* AHIG */, 3 /* guess */, 2 /* AHIG */));
+ }
+ break;
+ case SE_DockWidgetCloseButton:
+ case SE_DockWidgetFloatButton:
+ case SE_DockWidgetTitleBarText:
+ case SE_DockWidgetIcon: {
+ int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
+ QRect srect = opt->rect;
+
+ const QStyleOptionDockWidget *dwOpt
+ = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
+ bool canClose = dwOpt == 0 ? true : dwOpt->closable;
+ bool canFloat = dwOpt == 0 ? false : dwOpt->floatable;
+
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ // If this is a vertical titlebar, we transpose and work as if it was
+ // horizontal, then transpose again.
+ if (verticalTitleBar)
+ srect = srect.transposed();
+
+ do {
+ int right = srect.right();
+ int left = srect.left();
+
+ QRect closeRect;
+ if (canClose) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
+ opt).actualSize(QSize(iconSize, iconSize));
+ sz += QSize(buttonMargin, buttonMargin);
+ if (verticalTitleBar)
+ sz = sz.transposed();
+ closeRect = QRect(left,
+ srect.center().y() - sz.height()/2,
+ sz.width(), sz.height());
+ left = closeRect.right() + 1;
+ }
+ if (sr == SE_DockWidgetCloseButton) {
+ rect = closeRect;
+ break;
+ }
+
+ QRect floatRect;
+ if (canFloat) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
+ opt).actualSize(QSize(iconSize, iconSize));
+ sz += QSize(buttonMargin, buttonMargin);
+ if (verticalTitleBar)
+ sz = sz.transposed();
+ floatRect = QRect(left,
+ srect.center().y() - sz.height()/2,
+ sz.width(), sz.height());
+ left = floatRect.right() + 1;
+ }
+ if (sr == SE_DockWidgetFloatButton) {
+ rect = floatRect;
+ break;
+ }
+
+ QRect iconRect;
+// if (const QDockWidget *dw = qobject_cast<const QDockWidget*>(widget)) {
+// QIcon icon;
+// if (dw->isFloating())
+// icon = dw->windowIcon();
+// if (!icon.isNull()
+// && icon.cacheKey() != QApplication::windowIcon().cacheKey()) {
+// QSize sz = icon.actualSize(QSize(rect.height(), rect.height()));
+// if (verticalTitleBar)
+// sz = sz.transposed();
+// iconRect = QRect(right - sz.width(), srect.center().y() - sz.height()/2,
+// sz.width(), sz.height());
+// right = iconRect.left() - 1;
+// }
+// }
+ if (sr == SE_DockWidgetIcon) {
+ rect = iconRect;
+ break;
+ }
+
+ QRect textRect = QRect(left, srect.top(),
+ right - left, srect.height());
+ if (sr == SE_DockWidgetTitleBarText) {
+ rect = textRect;
+ break;
+ }
+ } while (false);
+
+ if (verticalTitleBar) {
+ rect = QRect(srect.left() + rect.top() - srect.top(),
+ srect.top() + srect.right() - rect.right(),
+ rect.height(), rect.width());
+ } else {
+ rect = visualRect(opt->direction, srect, rect);
+ }
+ break;
+ }
+ default:
+ rect = QCommonStyle::subElementRect(sr, opt);
+ break;
+ }
+ return rect;
+}
+
+void QMacStylePrivate::drawToolbarButtonArrow(const QStyleOption *opt, QPainter *p) const
+{
+ Q_Q(const QMacStyle);
+ QStyleOption arrowOpt = *opt;
+ arrowOpt.rect = QRect(opt->rect.right() - (toolButtonArrowSize + toolButtonArrowMargin),
+ opt->rect.bottom() - (toolButtonArrowSize + toolButtonArrowMargin),
+ toolButtonArrowSize,
+ toolButtonArrowSize);
+ q->proxy()->drawPrimitive(QStyle::PE_IndicatorArrowDown, &arrowOpt, p);
+}
+
+void QMacStylePrivate::setupNSGraphicsContext(CGContextRef cg, bool flipped) const
+{
+ CGContextSaveGState(cg);
+ [NSGraphicsContext saveGraphicsState];
+
+ [NSGraphicsContext setCurrentContext:
+ [NSGraphicsContext graphicsContextWithCGContext:cg flipped:flipped]];
+}
+
+void QMacStylePrivate::restoreNSGraphicsContext(CGContextRef cg) const
+{
+ [NSGraphicsContext restoreGraphicsState];
+ CGContextRestoreGState(cg);
+}
+
+void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const
+{
+ Q_D(const QMacStyle);
+ const AppearanceSync sync;
+
+ QMacCGContext cg(p);
+ d->resolveCurrentNSView(opt->window);
+
+ switch (cc) {
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+
+ const bool drawTrack = sb->subControls & SC_ScrollBarGroove;
+ const bool drawKnob = sb->subControls & SC_ScrollBarSlider;
+ if (!drawTrack && !drawKnob)
+ break;
+
+ const bool isHorizontal = sb->orientation == Qt::Horizontal;
+
+ if (opt && opt->styleObject && !QMacStylePrivate::scrollBars.contains(opt->styleObject))
+ QMacStylePrivate::scrollBars.append(QPointer<QObject>(opt->styleObject));
+
+ static const CGFloat knobWidths[] = { 7.0, 5.0, 5.0 };
+ static const CGFloat expandedKnobWidths[] = { 11.0, 9.0, 9.0 };
+ const auto cocoaSize = d->effectiveAquaSizeConstrain(opt);
+ const CGFloat maxExpandScale = expandedKnobWidths[cocoaSize] / knobWidths[cocoaSize];
+
+ const bool isTransient = proxy()->styleHint(SH_ScrollBar_Transient, opt);
+// if (!isTransient)
+// d->stopAnimation(opt->styleObject);
+ bool wasActive = false;
+ CGFloat opacity = 0.0;
+ CGFloat expandScale = 1.0;
+ CGFloat expandOffset = 0.0;
+ bool shouldExpand = false;
+
+ if (QObject *styleObject = opt->styleObject) {
+ const int oldPos = styleObject->property("_q_stylepos").toInt();
+ const int oldMin = styleObject->property("_q_stylemin").toInt();
+ const int oldMax = styleObject->property("_q_stylemax").toInt();
+ const QRect oldRect = styleObject->property("_q_stylerect").toRect();
+ const QStyle::State oldState = static_cast<QStyle::State>(styleObject->property("_q_stylestate").value<QStyle::State::Int>());
+ const uint oldActiveControls = styleObject->property("_q_stylecontrols").toUInt();
+
+ // a scrollbar is transient when the scrollbar itself and
+ // its sibling are both inactive (ie. not pressed/hovered/moved)
+ const bool transient = isTransient && !opt->activeSubControls && !(sb->state & State_On);
+
+ if (!transient ||
+ oldPos != sb->sliderPosition ||
+ oldMin != sb->minimum ||
+ oldMax != sb->maximum ||
+ oldRect != sb->rect ||
+ oldState != sb->state ||
+ oldActiveControls != sb->activeSubControls) {
+
+ // if the scrollbar is transient or its attributes, geometry or
+ // state has changed, the opacity is reset back to 100% opaque
+ opacity = 1.0;
+
+ styleObject->setProperty("_q_stylepos", sb->sliderPosition);
+ styleObject->setProperty("_q_stylemin", sb->minimum);
+ styleObject->setProperty("_q_stylemax", sb->maximum);
+ styleObject->setProperty("_q_stylerect", sb->rect);
+ styleObject->setProperty("_q_stylestate", static_cast<QStyle::State::Int>(sb->state));
+ styleObject->setProperty("_q_stylecontrols", static_cast<uint>(sb->activeSubControls));
+
+// QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
+// if (transient) {
+// if (!anim) {
+// anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Deactivating, styleObject);
+// d->startAnimation(anim);
+// } else if (anim->mode() == QScrollbarStyleAnimation::Deactivating) {
+// // the scrollbar was already fading out while the
+// // state changed -> restart the fade out animation
+// anim->setCurrentTime(0);
+// }
+// } else if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
+// d->stopAnimation(styleObject);
+// }
+ }
+
+// QScrollbarStyleAnimation *anim = qobject_cast<QScrollbarStyleAnimation *>(d->animation(styleObject));
+// if (anim && anim->mode() == QScrollbarStyleAnimation::Deactivating) {
+// // once a scrollbar was active (hovered/pressed), it retains
+// // the active look even if it's no longer active while fading out
+// if (oldActiveControls)
+// anim->setActive(true);
+
+// wasActive = anim->wasActive();
+// opacity = anim->currentValue();
+// }
+
+ shouldExpand = isTransient && (opt->activeSubControls || wasActive);
+ if (shouldExpand) {
+// if (!anim && !oldActiveControls) {
+// // Start expand animation only once and when entering
+// anim = new QScrollbarStyleAnimation(QScrollbarStyleAnimation::Activating, styleObject);
+// d->startAnimation(anim);
+// }
+// if (anim && anim->mode() == QScrollbarStyleAnimation::Activating) {
+// expandScale = 1.0 + (maxExpandScale - 1.0) * anim->currentValue();
+// expandOffset = 5.5 * (1.0 - anim->currentValue());
+// } else {
+// // Keep expanded state after the animation ends, and when fading out
+// expandScale = maxExpandScale;
+// expandOffset = 0.0;
+// }
+ }
+ }
+
+ d->setupNSGraphicsContext(cg, NO /* flipped */);
+
+ const auto controlType = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cw = QMacStylePrivate::CocoaControl(controlType, cocoaSize);
+ NSScroller *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
+
+ const QColor bgColor = QStyleHelper::backgroundColor(opt->palette);
+ const bool hasDarkBg = bgColor.red() < 128 && bgColor.green() < 128 && bgColor.blue() < 128;
+ if (isTransient) {
+ // macOS behavior: as soon as one color channel is >= 128,
+ // the background is considered bright, scroller is dark.
+ scroller.knobStyle = hasDarkBg? NSScrollerKnobStyleLight : NSScrollerKnobStyleDark;
+ } else {
+ scroller.knobStyle = NSScrollerKnobStyleDefault;
+ }
+
+ scroller.scrollerStyle = isTransient ? NSScrollerStyleOverlay : NSScrollerStyleLegacy;
+
+ if (!setupScroller(scroller, sb))
+ break;
+
+ if (isTransient) {
+ CGContextBeginTransparencyLayerWithRect(cg, scroller.frame, nullptr);
+ CGContextSetAlpha(cg, opacity);
+ }
+
+ if (drawTrack) {
+ // Draw the track when hovering. Expand by shifting the track rect.
+ if (!isTransient || opt->activeSubControls || wasActive) {
+ CGRect trackRect = scroller.bounds;
+ if (isHorizontal)
+ trackRect.origin.y += expandOffset;
+ else
+ trackRect.origin.x += expandOffset;
+ [scroller drawKnobSlotInRect:trackRect highlight:NO];
+ }
+ }
+
+ if (drawKnob) {
+ if (shouldExpand) {
+ // -[NSScroller drawKnob] is not useful here because any scaling applied
+ // will only be used to draw the hi-DPI artwork. And even if did scale,
+ // the stretched knob would look wrong, actually. So we need to draw the
+ // scroller manually when it's being hovered.
+ const CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:scroller.controlSize scrollerStyle:scroller.scrollerStyle];
+ const CGFloat knobWidth = knobWidths[cocoaSize] * expandScale;
+ // Cocoa can help get the exact knob length in the current orientation
+ const CGRect scrollerKnobRect = CGRectInset([scroller rectForPart:NSScrollerKnob], 1, 1);
+ const CGFloat knobLength = isHorizontal ? scrollerKnobRect.size.width : scrollerKnobRect.size.height;
+ const CGFloat knobPos = isHorizontal ? scrollerKnobRect.origin.x : scrollerKnobRect.origin.y;
+ const CGFloat knobOffset = qRound((scrollerWidth + expandOffset - knobWidth) / 2.0);
+ const CGFloat knobRadius = knobWidth / 2.0;
+ CGRect knobRect;
+ if (isHorizontal)
+ knobRect = CGRectMake(knobPos, knobOffset, knobLength, knobWidth);
+ else
+ knobRect = CGRectMake(knobOffset, knobPos, knobWidth, knobLength);
+ QCFType<CGPathRef> knobPath = CGPathCreateWithRoundedRect(knobRect, knobRadius, knobRadius, nullptr);
+ CGContextAddPath(cg, knobPath);
+ CGContextSetAlpha(cg, 0.5);
+ CGColorRef knobColor = hasDarkBg ? NSColor.whiteColor.CGColor : NSColor.blackColor.CGColor;
+ CGContextSetFillColorWithColor(cg, knobColor);
+ CGContextFillPath(cg);
+ } else {
+ [scroller drawKnob];
+
+ if (!isTransient && opt->state & State_Sunken) {
+ // The knob should appear darker (going from 0.76 down to 0.49).
+ // But no blending mode can help darken enough in a single pass,
+ // so we resort to drawing the knob twice with a small help from
+ // blending. This brings the gray level to a close enough 0.53.
+ CGContextSetBlendMode(cg, kCGBlendModePlusDarker);
+ [scroller drawKnob];
+ }
+ }
+ }
+
+ if (isTransient)
+ CGContextEndTransparencyLayer(cg);
+
+ d->restoreNSGraphicsContext(cg);
+ }
+ break;
+ case CC_Slider:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
+ if (!setupSlider(slider, sl))
+ break;
+
+ const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
+ const bool hasDoubleTicks = sl->tickPosition == QStyleOptionSlider::TicksBothSides;
+ const bool drawKnob = sl->subControls & SC_SliderHandle;
+ const bool drawBar = sl->subControls & SC_SliderGroove;
+ const bool drawTicks = sl->subControls & SC_SliderTickmarks;
+ const bool isPressed = sl->state & State_Sunken;
+
+ CGPoint pressPoint;
+ if (isPressed && drawKnob) {
+ const CGRect knobRect = [slider.cell knobRectFlipped:slider.isFlipped];
+ pressPoint.x = CGRectGetMidX(knobRect);
+ pressPoint.y = CGRectGetMidY(knobRect);
+ [slider.cell startTrackingAt:pressPoint inView:slider];
+ }
+
+ d->drawNSViewInRect(slider, opt->rect, p, ^(CGContextRef, const CGRect &) {
+ // Note that we don't support drawing the slider upside down. When this
+ // is needed, simply set scale = -1 on the QML control / style item instead.
+ NSSliderCell *cell = slider.cell;
+
+ if (drawBar) {
+ const CGRect barRect = [cell barRectFlipped:slider.isFlipped];
+ // "flipped" will only make a difference when NSSliderCell is vertical. And then
+ // flipped means fill the groove from bottom-to-top instead of top-to-bottom.
+ // Bottom-to-top is QSlider's normal mode, which means that we always need to flip
+ // in vertical mode. (In case NSSlider can also be flipped horizontally in the future,
+ // we stay on the safe side, and only flip when in vertical mode).
+ [cell drawBarInside:barRect flipped:!isHorizontal];
+ }
+
+ if (drawBar && hasTicks && drawTicks) {
+ if (!hasDoubleTicks) {
+ [cell drawTickMarks];
+ } else {
+ if (sl->orientation == Qt::Horizontal) {
+ slider.tickMarkPosition = NSTickMarkPositionAbove;
+ [slider layoutSubtreeIfNeeded];
+ [cell drawTickMarks];
+ slider.tickMarkPosition = NSTickMarkPositionBelow;
+ [slider layoutSubtreeIfNeeded];
+ [cell drawTickMarks];
+ } else {
+ slider.tickMarkPosition = NSTickMarkPositionLeading;
+ [slider layoutSubtreeIfNeeded];
+ [cell drawTickMarks];
+ slider.tickMarkPosition = NSTickMarkPositionTrailing;
+ [slider layoutSubtreeIfNeeded];
+ [cell drawTickMarks];
+ }
+ }
+ }
+
+ if (drawKnob)
+ [cell drawKnob];
+ });
+
+ if (isPressed && drawKnob)
+ [slider.cell stopTracking:pressPoint at:pressPoint inView:slider mouseIsUp:NO];
+ }
+ break;
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
+ const auto lineEditRect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxEditField);
+ QStyleOptionFrame frame;
+ static_cast<QStyleOption &>(frame) = *opt;
+ frame.rect = lineEditRect;
+ frame.state |= State_Sunken;
+ frame.lineWidth = 1;
+ frame.midLineWidth = 0;
+ frame.features = QStyleOptionFrame::None;
+ frame.frameShape = QStyleOptionFrame::Box;
+ drawPrimitive(PE_FrameLineEdit, &frame, p);
+ }
+ if (sb->subControls & (SC_SpinBoxUp | SC_SpinBoxDown)) {
+ const QRect updown = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp)
+ | proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
+
+ d->setupNSGraphicsContext(cg, NO);
+
+ const auto aquaSize = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
+ cell.enabled = (sb->state & State_Enabled);
+
+ const CGRect newRect = [cell drawingRectForBounds:updown.toCGRect()];
+
+ const bool upPressed = sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken);
+ const bool downPressed = sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken);
+ const CGFloat x = CGRectGetMidX(newRect);
+ const CGFloat y = upPressed ? -3 : 3; // Weird coordinate shift going on. Verified with Hopper
+ const CGPoint pressPoint = CGPointMake(x, y);
+ // Pretend we're pressing the mouse on the right button. Unfortunately, NSStepperCell has no
+ // API to highlight a specific button. The highlighted property works only on the down button.
+ if (upPressed || downPressed)
+ [cell startTrackingAt:pressPoint inView:d->backingStoreNSView];
+
+ [cell drawWithFrame:newRect inView:d->backingStoreNSView];
+
+ if (upPressed || downPressed)
+ [cell stopTracking:pressPoint at:pressPoint inView:d->backingStoreNSView mouseIsUp:NO];
+
+ d->restoreNSGraphicsContext(cg);
+ }
+ }
+ break;
+ case CC_ComboBox:
+ if (const auto *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ const bool isEnabled = combo->state & State_Enabled;
+ const bool isPressed = combo->state & State_Sunken;
+
+ const auto ct = cocoaControlType(combo);
+ const auto cs = d->effectiveAquaSizeConstrain(combo);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *cc = static_cast<NSControl *>(d->cocoaControl(cw));
+ cc.enabled = isEnabled;
+ QRectF frameRect = cw.adjustedControlFrame(combo->rect);;
+ if (cw.type == QMacStylePrivate::Button_PopupButton) {
+ // Non-editable QComboBox
+ auto *pb = static_cast<NSPopUpButton *>(cc);
+ // FIXME Old offsets. Try to move to adjustedControlFrame()
+ if (cw.size == QStyleHelper::SizeSmall) {
+ frameRect = frameRect.translated(0, 1);
+ } else if (cw.size == QStyleHelper::SizeMini) {
+ // Same 0.5 pt misalignment as AppKit and fit the focus ring
+ frameRect = frameRect.translated(2, -0.5);
+ }
+ pb.frame = frameRect.toCGRect();
+ [pb highlight:isPressed];
+ d->drawNSViewInRect(pb, frameRect, p, ^(CGContextRef, const CGRect &r) {
+ QMacAutoReleasePool pool;
+ [pb.cell drawBezelWithFrame:r inView:pb.superview];
+ });
+ } else if (cw.type == QMacStylePrivate::ComboBox) {
+ // Editable QComboBox
+ auto *cb = static_cast<NSComboBox *>(cc);
+ const auto frameRect = cw.adjustedControlFrame(combo->rect);
+ cb.frame = frameRect.toCGRect();
+
+ // This API was requested to Apple in rdar #36197888. We know it's safe to use up to macOS 10.13.3
+ if (NSButtonCell *cell = static_cast<NSButtonCell *>([cc.cell qt_valueForPrivateKey:@"_buttonCell"])) {
+ cell.highlighted = isPressed;
+ } else {
+ // TODO Render to pixmap and darken the button manually
+ }
+
+ d->drawNSViewInRect(cb, frameRect, p, ^(CGContextRef, const CGRect &r) {
+ // FIXME This is usually drawn in the control's superview, but we wouldn't get inactive look in this case
+ QMacAutoReleasePool pool;
+ [cb.cell drawWithFrame:r inView:cb];
+ });
+ }
+ }
+ break;
+ case CC_TitleBar:
+ if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ const bool isActive = (titlebar->state & State_Active)
+ && (titlebar->titleBarState & State_Active);
+
+ p->fillRect(opt->rect, Qt::transparent);
+ p->setRenderHint(QPainter::Antialiasing);
+ p->setClipRect(opt->rect, Qt::IntersectClip);
+
+ // FIXME A single drawPath() with 0-sized pen
+ // doesn't look as good as this double fillPath().
+ const auto outerFrameRect = QRectF(opt->rect.adjusted(0, 0, 0, opt->rect.height()));
+ QPainterPath outerFramePath = d->windowPanelPath(outerFrameRect);
+ p->fillPath(outerFramePath, opt->palette.dark());
+
+ const auto frameAdjust = 1.0 / p->device()->devicePixelRatioF();
+ const auto innerFrameRect = outerFrameRect.adjusted(frameAdjust, frameAdjust, -frameAdjust, 0);
+ QPainterPath innerFramePath = d->windowPanelPath(innerFrameRect);
+ if (isActive) {
+ QLinearGradient g;
+ g.setStart(QPointF(0, 0));
+ g.setFinalStop(QPointF(0, 2 * opt->rect.height()));
+ g.setColorAt(0, opt->palette.button().color());
+ g.setColorAt(1, opt->palette.dark().color());
+ p->fillPath(innerFramePath, g);
+ } else {
+ p->fillPath(innerFramePath, opt->palette.button());
+ }
+
+ if (titlebar->subControls & (SC_TitleBarCloseButton
+ | SC_TitleBarMaxButton
+ | SC_TitleBarMinButton
+ | SC_TitleBarNormalButton)) {
+ const bool isHovered = (titlebar->state & State_MouseOver);
+ static const SubControl buttons[] = {
+ SC_TitleBarCloseButton, SC_TitleBarMinButton, SC_TitleBarMaxButton
+ };
+ for (const auto sc : buttons) {
+ const auto ct = d->windowButtonCocoaControl(sc);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, QStyleHelper::SizeLarge);
+ auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
+ wb.enabled = (sc & titlebar->subControls) && isActive;
+ [wb highlight:(titlebar->state & State_Sunken) && (sc & titlebar->activeSubControls)];
+ Q_UNUSED(isHovered); // FIXME No public API for this
+
+ const auto buttonRect = proxy()->subControlRect(CC_TitleBar, titlebar, sc);
+ d->drawNSViewInRect(wb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ auto *wbCell = static_cast<NSButtonCell *>(wb.cell);
+ [wbCell drawWithFrame:rect inView:wb];
+ });
+ }
+ }
+
+ if (titlebar->subControls & SC_TitleBarLabel) {
+ const auto tr = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarLabel);
+ if (!titlebar->icon.isNull()) {
+ const auto iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ const auto iconSize = QSize(iconExtent, iconExtent);
+ const auto iconPos = tr.x() - titlebar->icon.actualSize(iconSize).width() - qRound(titleBarIconTitleSpacing);
+ // Only render the icon if it'll be fully visible
+ if (iconPos < tr.right() - titleBarIconTitleSpacing)
+ p->drawPixmap(iconPos, tr.y(), titlebar->icon.pixmap(opt->window, iconSize, QIcon::Normal));
+ }
+
+ if (!titlebar->text.isEmpty())
+ drawItemText(p, tr, Qt::AlignCenter, opt->palette, isActive, titlebar->text, QPalette::Text);
+ }
+ }
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *gb
+ = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+
+ QStyleOptionGroupBox groupBox(*gb);
+ const bool flat = groupBox.features & QStyleOptionFrame::Flat;
+ if (!flat)
+ groupBox.state |= QStyle::State_Mini; // Force mini-sized checkbox to go with small-sized label
+ else
+ groupBox.subControls = groupBox.subControls & ~SC_GroupBoxFrame; // We don't like frames and ugly lines
+
+// const bool didSetFont = widget && widget->testAttribute(Qt::WA_SetFont);
+// const bool didModifySubControls = !didSetFont && QApplication::desktopSettingsAware();
+// if (didModifySubControls)
+// groupBox.subControls = groupBox.subControls & ~SC_GroupBoxLabel;
+ QCommonStyle::drawComplexControl(cc, &groupBox, p);
+// if (didModifySubControls) {
+// const QRect rect = proxy()->subControlRect(CC_GroupBox, &groupBox, SC_GroupBoxLabel);
+// const bool rtl = groupBox.direction == Qt::RightToLeft;
+// const int alignment = Qt::TextHideMnemonic | (rtl ? Qt::AlignRight : Qt::AlignLeft);
+// const QFont savedFont = p->font();
+// if (!flat)
+// p->setFont(d->smallSystemFont);
+// proxy()->drawItemText(p, rect, alignment, groupBox.palette, groupBox.state & State_Enabled, groupBox.text, QPalette::WindowText);
+// if (!flat)
+// p->setFont(savedFont);
+// }
+ }
+ break;
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *tb
+ = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) {
+ if (tb->subControls & SC_ToolButtonMenu) {
+ QStyleOption arrowOpt = *tb;
+ arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
+ arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2);
+ arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
+ } else if ((tb->features & QStyleOptionToolButton::HasMenu)
+ && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) {
+ d->drawToolbarButtonArrow(tb, p);
+ }
+ if (tb->state & State_On) {
+ NSView *view = reinterpret_cast<NSView *>(opt->window->winId());
+ bool isKey = false;
+ if (view)
+ isKey = [view.window isKeyWindow];
+
+ QBrush brush(brushForToolButton(isKey));
+ QPainterPath path;
+ path.addRoundedRect(QRectF(tb->rect.x(), tb->rect.y(), tb->rect.width(), tb->rect.height() + 4), 4, 4);
+ p->setRenderHint(QPainter::Antialiasing);
+ p->fillPath(path, brush);
+ }
+ proxy()->drawControl(CE_ToolButtonLabel, opt, p);
+ } else
+#endif // QT_NO_ACCESSIBILITY
+ {
+ auto bflags = tb->state;
+ if (tb->subControls & SC_ToolButton)
+ bflags |= State_Sunken;
+ auto mflags = tb->state;
+ if (tb->subControls & SC_ToolButtonMenu)
+ mflags |= State_Sunken;
+
+ if (tb->subControls & SC_ToolButton) {
+ if (bflags & (State_Sunken | State_On | State_Raised)) {
+ const bool isEnabled = tb->state & State_Enabled;
+ const bool isPressed = tb->state & State_Sunken;
+ const bool isHighlighted = (tb->state & State_Active) && (tb->state & State_On);
+ const auto ct = QMacStylePrivate::Button_PushButton;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *pb = static_cast<NSButton *>(d->cocoaControl(cw));
+ pb.bezelStyle = NSShadowlessSquareBezelStyle; // TODO Use NSTexturedRoundedBezelStyle in the future.
+ pb.frame = opt->rect.toCGRect();
+ pb.buttonType = NSPushOnPushOffButton;
+ pb.enabled = isEnabled;
+ [pb highlight:isPressed];
+ pb.state = isHighlighted && !isPressed ? NSOnState : NSOffState;
+ const auto buttonRect = proxy()->subControlRect(cc, tb, SC_ToolButton);
+ d->drawNSViewInRect(pb, buttonRect, p, ^(CGContextRef, const CGRect &rect) {
+ QMacAutoReleasePool pool;
+ [pb.cell drawBezelWithFrame:rect inView:pb];
+ });
+ }
+ }
+
+ if (tb->subControls & SC_ToolButtonMenu) {
+ const auto menuRect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu);
+ QStyleOption arrowOpt = *tb;
+ arrowOpt.rect = QRect(menuRect.x() + ((menuRect.width() - toolButtonArrowSize) / 2),
+ menuRect.height() - (toolButtonArrowSize + toolButtonArrowMargin),
+ toolButtonArrowSize,
+ toolButtonArrowSize);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p);
+ } else if (tb->features & QStyleOptionToolButton::HasMenu) {
+ d->drawToolbarButtonArrow(tb, p);
+ }
+ QRect buttonRect = proxy()->subControlRect(CC_ToolButton, tb, SC_ToolButton);
+ int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ QStyleOptionToolButton label = *tb;
+ label.rect = buttonRect.adjusted(fw, fw, -fw, -fw);
+ proxy()->drawControl(CE_ToolButtonLabel, &label, p);
+ }
+ }
+ break;
+ case CC_Dial:
+ if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt))
+ QStyleHelper::drawDial(dial, p);
+ break;
+ default:
+ QCommonStyle::drawComplexControl(cc, opt, p);
+ break;
+ }
+}
+
+QStyle::SubControl QMacStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const
+{
+ Q_D(const QMacStyle);
+
+ SubControl sc = QStyle::SC_None;
+
+ switch (cc) {
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ sc = QCommonStyle::hitTestComplexControl(cc, cmb, pt);
+ if (!cmb->editable && sc != QStyle::SC_None)
+ sc = SC_ComboBoxArrow; // A bit of a lie, but what we want
+ }
+ break;
+ case CC_Slider:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ if (!sl->rect.contains(pt))
+ break;
+
+ const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
+ const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
+ if (!setupSlider(slider, sl))
+ break;
+
+ NSSliderCell *cell = slider.cell;
+ const auto barRect = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]);
+ const auto knobRect = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]);
+ if (knobRect.contains(pt)) {
+ sc = SC_SliderHandle;
+ } else if (barRect.contains(pt)) {
+ sc = SC_SliderGroove;
+ } else if (hasTicks) {
+ sc = SC_SliderTickmarks;
+ }
+ }
+ break;
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ if (!sb->rect.contains(pt)) {
+ sc = SC_None;
+ break;
+ }
+
+ const bool isHorizontal = sb->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
+ if (!setupScroller(scroller, sb)) {
+ sc = SC_None;
+ break;
+ }
+
+ // Since -[NSScroller testPart:] doesn't want to cooperate, we do it the
+ // straightforward way. In any case, macOS doesn't return line-sized changes
+ // with NSScroller since 10.7, according to the aforementioned method's doc.
+ const auto knobRect = QRectF::fromCGRect([scroller rectForPart:NSScrollerKnob]);
+ if (isHorizontal) {
+ const bool isReverse = sb->direction == Qt::RightToLeft;
+ if (pt.x() < knobRect.left())
+ sc = isReverse ? SC_ScrollBarAddPage : SC_ScrollBarSubPage;
+ else if (pt.x() > knobRect.right())
+ sc = isReverse ? SC_ScrollBarSubPage : SC_ScrollBarAddPage;
+ else
+ sc = SC_ScrollBarSlider;
+ } else {
+ if (pt.y() < knobRect.top())
+ sc = SC_ScrollBarSubPage;
+ else if (pt.y() > knobRect.bottom())
+ sc = SC_ScrollBarAddPage;
+ else
+ sc = SC_ScrollBarSlider;
+ }
+ }
+ break;
+ default:
+ sc = QCommonStyle::hitTestComplexControl(cc, opt, pt);
+ break;
+ }
+ return sc;
+}
+
+QRect QMacStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc) const
+{
+ Q_D(const QMacStyle);
+
+ QRect ret;
+
+ switch (cc) {
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *sb = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ const bool isHorizontal = sb->orientation == Qt::Horizontal;
+ const bool isReverseHorizontal = isHorizontal && (sb->direction == Qt::RightToLeft);
+
+ NSScrollerPart part = NSScrollerNoPart;
+ if (sc == SC_ScrollBarSlider) {
+ part = NSScrollerKnob;
+ } else if (sc == SC_ScrollBarGroove) {
+ part = NSScrollerKnobSlot;
+ } else if (sc == SC_ScrollBarSubPage || sc == SC_ScrollBarAddPage) {
+ if ((!isReverseHorizontal && sc == SC_ScrollBarSubPage)
+ || (isReverseHorizontal && sc == SC_ScrollBarAddPage))
+ part = NSScrollerDecrementPage;
+ else
+ part = NSScrollerIncrementPage;
+ }
+ // And nothing else since 10.7
+
+ if (part != NSScrollerNoPart) {
+ const auto ct = isHorizontal ? QMacStylePrivate::Scroller_Horizontal : QMacStylePrivate::Scroller_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *scroller = static_cast<NSScroller *>(d->cocoaControl(cw));
+ if (setupScroller(scroller, sb))
+ ret = QRectF::fromCGRect([scroller rectForPart:part]).toRect();
+ }
+ }
+ break;
+ case CC_Slider:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ const bool hasTicks = sl->tickPosition != QStyleOptionSlider::NoTicks;
+ const bool isHorizontal = sl->orientation == Qt::Horizontal;
+ const auto ct = isHorizontal ? QMacStylePrivate::Slider_Horizontal : QMacStylePrivate::Slider_Vertical;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+ auto *slider = static_cast<NSSlider *>(d->cocoaControl(cw));
+ if (!setupSlider(slider, sl))
+ break;
+
+ NSSliderCell *cell = slider.cell;
+ if (sc == SC_SliderHandle) {
+ ret = QRectF::fromCGRect([cell knobRectFlipped:slider.isFlipped]).toRect();
+ } else if (sc == SC_SliderGroove) {
+ ret = QRectF::fromCGRect([cell barRectFlipped:slider.isFlipped]).toRect();
+ } else if (hasTicks && sc == SC_SliderTickmarks) {
+ const auto tickMarkRect = QRectF::fromCGRect([cell rectOfTickMarkAtIndex:0]);
+ if (isHorizontal)
+ ret = QRect(sl->rect.left(), tickMarkRect.top(), sl->rect.width(), tickMarkRect.height());
+ else
+ ret = QRect(tickMarkRect.left(), sl->rect.top(), tickMarkRect.width(), sl->rect.height());
+ }
+
+// if (sl->upsideDown) {
+// if isHorizontal) {
+// } else {
+// }
+// }
+ }
+ break;
+ case CC_TitleBar:
+ if (const auto *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ // The title bar layout is as follows: close, min, zoom, icon, title
+ // [ x _ + @ Window Title ]
+ // Center the icon and title until it starts to overlap with the buttons.
+ // The icon doesn't count towards SC_TitleBarLabel, but it's still rendered
+ // next to the title text. See drawComplexControl().
+ if (sc == SC_TitleBarLabel) {
+ qreal labelWidth = titlebar->fontMetrics.horizontalAdvance(titlebar->text) + 1; // FIXME Rounding error?
+ qreal labelHeight = titlebar->fontMetrics.height();
+
+ const auto lastButtonRect = proxy()->subControlRect(CC_TitleBar, titlebar, SC_TitleBarMaxButton);
+ qreal controlsSpacing = lastButtonRect.right() + titleBarButtonSpacing;
+ if (!titlebar->icon.isNull()) {
+ const auto iconSize = proxy()->pixelMetric(PM_SmallIconSize);
+ const auto actualIconSize = titlebar->icon.actualSize(QSize(iconSize, iconSize)).width();;
+ controlsSpacing += actualIconSize + titleBarIconTitleSpacing;
+ }
+
+ const qreal labelPos = qMax(controlsSpacing, (opt->rect.width() - labelWidth) / 2.0);
+ labelWidth = qMin(labelWidth, opt->rect.width() - (labelPos + titleBarTitleRightMargin));
+ ret = QRect(labelPos, (opt->rect.height() - labelHeight) / 2,
+ labelWidth, labelHeight);
+ } else {
+ const auto currentButton = d->windowButtonCocoaControl(sc);
+ if (currentButton == QMacStylePrivate::NoControl)
+ break;
+
+ QPointF buttonPos = titlebar->rect.topLeft() + QPointF(titleBarButtonSpacing, 0);
+ QSizeF buttonSize;
+ for (int ct = QMacStylePrivate::Button_WindowClose; ct <= currentButton; ct++) {
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::CocoaControlType(ct),
+ QStyleHelper::SizeLarge);
+ auto *wb = static_cast<NSButton *>(d->cocoaControl(cw));
+ if (ct == currentButton)
+ buttonSize = QSizeF::fromCGSize(wb.frame.size);
+ else
+ buttonPos.rx() += wb.frame.size.width + titleBarButtonSpacing;
+ }
+
+ const auto vOffset = (opt->rect.height() - buttonSize.height()) / 2.0;
+ ret = QRectF(buttonPos, buttonSize).translated(0, vOffset).toRect();
+ }
+ }
+ break;
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ const auto ct = cocoaControlType(combo);
+ const auto cs = d->effectiveAquaSizeConstrain(combo);
+ const auto cw = QMacStylePrivate::CocoaControl(ct, cs);
+
+ // Old widget path. Current not understood why it's needed:
+ //const auto editRect = QMacStylePrivate::comboboxEditBounds(cw.adjustedControlFrame(combo->rect), cw);
+
+ // New path:
+ QRectF editRect;
+ switch (cs) {
+ case QStyleHelper::SizeLarge:
+ editRect = combo->rect.adjusted(15, 7, -25, -9);
+ break;
+ case QStyleHelper::SizeSmall:
+ if (combo->editable)
+ editRect = combo->rect.adjusted(15, 6, -22, -9);
+ else
+ editRect = combo->rect.adjusted(15, 8, -22, -6);
+ break;
+ default:
+ if (combo->editable)
+ editRect = combo->rect.adjusted(15, 6, -20, -7);
+ else
+ editRect = combo->rect.adjusted(15, 5, -22, -6);
+ break;
+ }
+
+ switch (sc) {
+ case SC_ComboBoxEditField:{
+ ret = editRect.toAlignedRect();
+ break; }
+ case SC_ComboBoxArrow:{
+ ret = editRect.toAlignedRect();
+ ret.setX(ret.x() + ret.width());
+ ret.setWidth(combo->rect.right() - ret.right());
+ break; }
+ case SC_ComboBoxListBoxPopup:{
+ if (combo->editable) {
+ const CGRect inner = QMacStylePrivate::comboboxInnerBounds(combo->rect.toCGRect(), cw);
+ const int comboTop = combo->rect.top();
+ ret = QRect(qRound(inner.origin.x),
+ comboTop,
+ qRound(inner.origin.x - combo->rect.left() + inner.size.width),
+ editRect.bottom() - comboTop + 2);
+ } else {
+ ret = QRect(combo->rect.x() + 4 - 11,
+ combo->rect.y() + 1,
+ editRect.width() + 10 + 11,
+ 1);
+ }
+ break; }
+ default:
+ break;
+ }
+ }
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
+ const bool flat = groupBox->features & QStyleOptionFrame::Flat;
+ bool hasNoText = !checkable && groupBox->text.isEmpty();
+ switch (sc) {
+ case SC_GroupBoxLabel:
+ case SC_GroupBoxCheckBox: {
+ // Cheat and use the smaller font if we need to
+ const bool checkable = groupBox->subControls & SC_GroupBoxCheckBox;
+ const bool fontIsSet = false;
+// const bool fontIsSet = (widget && widget->testAttribute(Qt::WA_SetFont))
+// || !QApplication::desktopSettingsAware();
+ const int margin = flat || hasNoText ? 0 : 9;
+ ret = groupBox->rect.adjusted(margin, 0, -margin, 0);
+
+ const QFontMetricsF fm = flat || fontIsSet ? QFontMetricsF(groupBox->fontMetrics) : QFontMetricsF(d->smallSystemFont);
+ const QSizeF s = fm.size(Qt::AlignHCenter | Qt::AlignVCenter, qt_mac_removeMnemonics(groupBox->text), 0, nullptr);
+ const int tw = qCeil(s.width());
+ const int h = qCeil(fm.height());
+ ret.setHeight(h);
+
+ QRect labelRect = alignedRect(groupBox->direction, groupBox->textAlignment,
+ QSize(tw, h), ret);
+ if (flat && checkable)
+ labelRect.moveLeft(labelRect.left() + 4);
+ int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
+ bool rtl = groupBox->direction == Qt::RightToLeft;
+ if (sc == SC_GroupBoxLabel) {
+ if (checkable) {
+ int newSum = indicatorWidth + 1;
+ int newLeft = labelRect.left() + (rtl ? -newSum : newSum);
+ labelRect.moveLeft(newLeft);
+ if (flat)
+ labelRect.moveTop(labelRect.top() + 3);
+ else
+ labelRect.moveTop(labelRect.top() + 4);
+ } else if (flat) {
+ int newLeft = labelRect.left() - (rtl ? 3 : -3);
+ labelRect.moveLeft(newLeft);
+ labelRect.moveTop(labelRect.top() + 3);
+ } else {
+ int newLeft = labelRect.left() - (rtl ? 3 : 2);
+ labelRect.moveLeft(newLeft);
+ labelRect.moveTop(labelRect.top() + 4);
+ }
+ ret = labelRect;
+ }
+
+ if (sc == SC_GroupBoxCheckBox) {
+ int left = rtl ? labelRect.right() - indicatorWidth : labelRect.left() - 1;
+ int top = flat ? ret.top() + 1 : ret.top() + 5;
+ ret.setRect(left, top,
+ indicatorWidth, proxy()->pixelMetric(PM_IndicatorHeight, opt));
+ }
+ break;
+ }
+ case SC_GroupBoxContents:
+ case SC_GroupBoxFrame: {
+ QFontMetrics fm = groupBox->fontMetrics;
+ int yOffset = 3;
+ if (!flat)
+ yOffset = 5;
+
+ if (hasNoText)
+ yOffset = -qCeil(QFontMetricsF(fm).height());
+ ret = opt->rect.adjusted(0, qCeil(QFontMetricsF(fm).height()) + yOffset, 0, 0);
+ if (sc == SC_GroupBoxContents) {
+ if (flat)
+ ret.adjust(3, -5, -3, -4); // guess too
+ else
+ ret.adjust(3, 3, -3, -4); // guess
+ }
+ }
+ break;
+ default:
+ ret = QCommonStyle::subControlRect(cc, groupBox, sc);
+ break;
+ }
+ }
+ break;
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *spin = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ QStyleHelper::WidgetSizePolicy aquaSize = d->effectiveAquaSizeConstrain(spin);
+ const auto fw = proxy()->pixelMetric(PM_SpinBoxFrameWidth, spin);
+ int spinner_w;
+ int spinner_h;
+ int adjust_y;
+ int spinBoxSep;
+ switch (aquaSize) {
+ case QStyleHelper::SizeLarge:
+ spinner_w = 14;
+ spinner_h = 24;
+ adjust_y = -1;
+ spinBoxSep = 2;
+ break;
+ case QStyleHelper::SizeSmall:
+ spinner_w = 12;
+ spinner_h = 20;
+ adjust_y = -1;
+ spinBoxSep = 2;
+ break;
+ case QStyleHelper::SizeMini:
+ spinner_w = 10;
+ spinner_h = 16;
+ adjust_y = -1;
+ spinBoxSep = 1;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ switch (sc) {
+ case SC_SpinBoxUp:
+ case SC_SpinBoxDown: {
+ if (spin->buttonSymbols == QStyleOptionSpinBox::NoButtons)
+ break;
+
+ const int y = fw;
+ const int x = spin->rect.width() - spinner_w;
+ ret.setRect(x + spin->rect.x(), y + spin->rect.y(), spinner_w, spinner_h);
+
+ const auto cw = QMacStylePrivate::CocoaControl(QMacStylePrivate::Stepper, aquaSize);
+ NSStepperCell *cell = static_cast<NSStepperCell *>(d->cocoaCell(cw));
+ const CGRect outRect = [cell drawingRectForBounds:ret.toCGRect()];
+ ret = QRectF::fromCGRect(outRect).toRect();
+
+ switch (sc) {
+ case SC_SpinBoxUp:
+ ret.setHeight(ret.height() / 2);
+ break;
+ case SC_SpinBoxDown:
+ ret.setY(ret.y() + ret.height() / 2);
+ break;
+ default:
+ Q_ASSERT(0);
+ break;
+ }
+ // The buttons are drawn with a top-margin (for some reason) into
+ // the rect. So undo that margin here:
+ ret.translate(0, adjust_y);
+ ret = visualRect(spin->direction, spin->rect, ret);
+ break;
+ }
+ case SC_SpinBoxEditField:
+ ret = spin->rect.adjusted(fw, fw, -fw, -fw);
+ if (spin->subControls & SC_SpinBoxUp || spin->subControls & SC_SpinBoxDown) {
+ ret.setWidth(spin->rect.width() - spinBoxSep - spinner_w);
+ ret = visualRect(spin->direction, spin->rect, ret);
+ }
+ break;
+ default:
+ ret = QCommonStyle::subControlRect(cc, spin, sc);
+ break;
+ }
+ }
+ break;
+ case CC_ToolButton:
+ ret = QCommonStyle::subControlRect(cc, opt, sc);
+ if (sc == SC_ToolButtonMenu) {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar))
+ ret.adjust(-toolButtonArrowMargin, 0, 0, 0);
+#endif
+ ret.adjust(-1, 0, 0, 0);
+ }
+ break;
+ default:
+ ret = QCommonStyle::subControlRect(cc, opt, sc);
+ break;
+ }
+ return ret;
+}
+
+QSize QMacStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz) const
+{
+ Q_D(const QMacStyle);
+
+ QSize sz(csz);
+ bool useAquaGuideline = true;
+
+ switch (ct) {
+ case CT_SpinBox:
+ if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ if (vopt->subControls == SC_SpinBoxFrame) {
+ const QSize minimumSize(20, 24);
+ if (sz.width() < minimumSize.width())
+ sz.setWidth(minimumSize.width());
+ if (sz.height() < minimumSize.height())
+ sz.setHeight(minimumSize.height());
+ } else {
+ const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
+ const int upAndDownTogetherHeight = buttonSize.height() * 2;
+ sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
+ }
+ }
+ break;
+ case QStyle::CT_TabWidget:
+ // the size between the pane and the "contentsRect" (+4,+4)
+ // (the "contentsRect" is on the inside of the pane)
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz);
+ /**
+ This is supposed to show the relationship between the tabBar and
+ the stack widget of a QTabWidget.
+ Unfortunately ascii is not a good way of representing graphics.....
+ PS: The '=' line is the painted frame.
+
+ top ---+
+ |
+ |
+ |
+ | vvv just outside the painted frame is the "pane"
+ - -|- - - - - - - - - - <-+
+ TAB BAR +=====^============ | +2 pixels
+ - - -|- - -|- - - - - - - <-+
+ | | ^ ^^^ just inside the painted frame is the "contentsRect"
+ | | |
+ | overlap |
+ | | |
+ bottom ------+ <-+ +14 pixels
+ |
+ v
+ ------------------------------ <- top of stack widget
+
+
+ To summarize:
+ * 2 is the distance between the pane and the contentsRect
+ * The 14 and the 1's are the distance from the contentsRect to the stack widget.
+ (same value as used in SE_TabWidgetTabContents)
+ * overlap is how much the pane should overlap the tab bar
+ */
+ // then add the size between the stackwidget and the "contentsRect"
+ if (const QStyleOptionTabWidgetFrame *twf
+ = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ QSize extra(0,0);
+ const int overlap = pixelMetric(PM_TabBarBaseOverlap, opt);
+ const int gapBetweenTabbarAndStackWidget = 2 + 14 - overlap;
+
+ const auto tabDirection = QMacStylePrivate::tabDirection(twf->shape);
+ if (tabDirection == QMacStylePrivate::North
+ || tabDirection == QMacStylePrivate::South) {
+ extra = QSize(2, gapBetweenTabbarAndStackWidget + 1);
+ } else {
+ extra = QSize(gapBetweenTabbarAndStackWidget + 1, 2);
+ }
+ sz+= extra;
+ }
+ break;
+ case QStyle::CT_TabBarTab:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+// const bool differentFont = (widget && widget->testAttribute(Qt::WA_SetFont))
+// || !QApplication::desktopSettingsAware();
+ const bool differentFont = false;
+ const auto tabDirection = QMacStylePrivate::tabDirection(tab->shape);
+ const bool verticalTabs = tabDirection == QMacStylePrivate::East
+ || tabDirection == QMacStylePrivate::West;
+ if (verticalTabs)
+ sz = sz.transposed();
+
+ int defaultTabHeight;
+ const auto cs = d->effectiveAquaSizeConstrain(opt);
+ switch (cs) {
+ case QStyleHelper::SizeLarge:
+ if (tab->documentMode)
+ defaultTabHeight = 24;
+ else
+ defaultTabHeight = 21;
+ break;
+ case QStyleHelper::SizeSmall:
+ defaultTabHeight = 18;
+ break;
+ case QStyleHelper::SizeMini:
+ defaultTabHeight = 16;
+ break;
+ default:
+ break;
+ }
+
+ const bool widthSet = !differentFont && tab->icon.isNull();
+ if (widthSet) {
+ const auto textSize = opt->fontMetrics.size(Qt::TextShowMnemonic, tab->text);
+ sz.rwidth() = textSize.width();
+ sz.rheight() = qMax(defaultTabHeight, textSize.height());
+ } else {
+ sz.rheight() = qMax(defaultTabHeight, sz.height());
+ }
+ sz.rwidth() += proxy()->pixelMetric(PM_TabBarTabHSpace, tab);
+
+ if (verticalTabs)
+ sz = sz.transposed();
+
+ int maxWidgetHeight = qMax(tab->leftButtonSize.height(), tab->rightButtonSize.height());
+ int maxWidgetWidth = qMax(tab->leftButtonSize.width(), tab->rightButtonSize.width());
+
+ int widgetWidth = 0;
+ int widgetHeight = 0;
+ int padding = 0;
+ if (tab->leftButtonSize.isValid()) {
+ padding += 8;
+ widgetWidth += tab->leftButtonSize.width();
+ widgetHeight += tab->leftButtonSize.height();
+ }
+ if (tab->rightButtonSize.isValid()) {
+ padding += 8;
+ widgetWidth += tab->rightButtonSize.width();
+ widgetHeight += tab->rightButtonSize.height();
+ }
+
+ if (verticalTabs) {
+ sz.setWidth(qMax(sz.width(), maxWidgetWidth));
+ sz.setHeight(sz.height() + widgetHeight + padding);
+ } else {
+ if (widthSet)
+ sz.setWidth(sz.width() + widgetWidth + padding);
+ sz.setHeight(qMax(sz.height(), maxWidgetHeight));
+ }
+ }
+ break;
+ case CT_LineEdit:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ if (sz.isEmpty()) {
+ // Minimum size (with padding: 18x24)
+ sz.rwidth() = 10;
+ sz.rheight() = 20;
+ }
+ // From using pixelTool with XCode/NSTextTextField
+ int leftPadding = 4;
+ int rightPadding = 4;
+ int topPadding = 4;
+ int bottomPadding = 0;
+
+ if (opt->state & QStyle::State_Small) {
+ topPadding = 3;
+ } else if (opt->state & QStyle::State_Mini) {
+ topPadding = 2;
+ }
+
+ sz.rwidth() += leftPadding + rightPadding;
+ sz.rheight() += topPadding + bottomPadding;
+ }
+ break;
+ case QStyle::CT_PushButton: {
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt))
+ if (btn->features & QStyleOptionButton::CommandLinkButton)
+ return QCommonStyle::sizeFromContents(ct, opt, sz);
+
+ // By default, we fit the contents inside a normal rounded push button.
+ // Do this by add enough space around the contents so that rounded
+ // borders (including highlighting when active) will show.
+ // TODO Use QFocusFrame and get rid of these horrors.
+ QSize macsz;
+ const auto controlSize = d->effectiveAquaSizeConstrain(opt, CT_PushButton, sz, &macsz);
+ // FIXME See comment in CT_PushButton case in qt_aqua_get_known_size().
+ if (macsz.width() != -1)
+ sz.setWidth(macsz.width());
+ else
+ sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset + 12;
+ // All values as measured from HIThemeGetButtonBackgroundBounds()
+ if (controlSize != QStyleHelper::SizeMini)
+ sz.rwidth() += 12; // We like 12 over here.
+ if (controlSize == QStyleHelper::SizeLarge && sz.height() > 16)
+ sz.rheight() += pushButtonDefaultHeight[QStyleHelper::SizeLarge] - 16;
+ else if (controlSize == QStyleHelper::SizeMini)
+ sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this.
+ else
+ sz.setHeight(pushButtonDefaultHeight[controlSize]);
+ break;
+ }
+ case QStyle::CT_MenuItem:
+ if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ int maxpmw = mi->maxIconWidth;
+ int w = sz.width();
+ int h = sz.height();
+
+//#if QT_CONFIG(combobox)
+// const QComboBox *comboBox = qobject_cast<const QComboBox *>(widget);
+//#endif
+
+ if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
+ w = 10;
+ h = qt_mac_aqua_get_metric(MenuSeparatorHeight);
+ } else {
+ h = mi->fontMetrics.height() + 2;
+ if (!mi->icon.isNull()) {
+//#if QT_CONFIG(combobox)
+// if (comboBox) {
+// const QSize &iconSize = comboBox->iconSize();
+// h = qMax(h, iconSize.height() + 4);
+// maxpmw = qMax(maxpmw, iconSize.width());
+// } else
+//#endif
+ {
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
+ }
+ }
+ }
+ if (mi->text.contains(QLatin1Char('\t')))
+ w += 12;
+ else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
+ w += 35; // Not quite exactly as it seems to depend on other factors
+ if (maxpmw)
+ w += maxpmw + 6;
+ // add space for a check. All items have place for a check too.
+ w += 20;
+// if (comboBox && comboBox->isVisible()) {
+// QStyleOptionComboBox cmb;
+// cmb.initFrom(comboBox);
+// cmb.editable = false;
+// cmb.subControls = QStyle::SC_ComboBoxEditField;
+// cmb.activeSubControls = QStyle::SC_None;
+// w = qMax(w, subControlRect(QStyle::CC_ComboBox, &cmb,
+// QStyle::SC_ComboBoxEditField,
+// comboBox).width());
+// } else {
+// w += 12;
+ sz = QSize(w, h);
+ } break;
+ case CT_MenuBarItem:
+ if (!sz.isEmpty())
+ sz += QSize(12, 4); // Constants from QWindowsStyle
+ break;
+ case CT_ToolButton:
+ sz.rwidth() += 10;
+ sz.rheight() += 10;
+ if (const auto *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt))
+ if (tb->features & QStyleOptionToolButton::Menu)
+ sz.rwidth() += toolButtonArrowMargin;
+ return sz;
+ case CT_ComboBox:
+ if (const auto *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ const int controlSize = getControlSize(opt);
+
+ if (!cb->editable) {
+ if (sz.width() < 10) {
+ // minimumSize (to ensure a nice nine patch image)
+ sz.rwidth() += 10;
+ }
+ // Same as CT_PushButton, because we have to fit the focus
+ // ring and a non-editable combo box is a NSPopUpButton.
+ sz.rwidth() += QMacStylePrivate::PushButtonLeftOffset + QMacStylePrivate::PushButtonRightOffset;
+
+ if (controlSize == QStyleHelper::SizeLarge) {
+ sz.rwidth() += 30;
+ } else if (controlSize == QStyleHelper::SizeSmall) {
+ sz.rwidth() += 26;
+ } else {
+ sz.rwidth() += 21;
+ }
+ } else {
+ sz.rwidth() += 50; // FIXME Double check this
+ }
+
+ // This should be enough to fit the focus ring
+ if (controlSize == QStyleHelper::SizeMini)
+ sz.setHeight(24); // FIXME Our previous HITheme-based logic returned this for CT_PushButton.
+ else
+ sz.setHeight(pushButtonDefaultHeight[controlSize]);
+
+ return sz;
+ }
+ break;
+ case CT_Menu: {
+ if (proxy() == this) {
+ sz = csz;
+ } else {
+ QStyleHintReturnMask menuMask;
+ QStyleOption myOption = *opt;
+ myOption.rect.setSize(sz);
+ if (proxy()->styleHint(SH_Menu_Mask, &myOption, &menuMask))
+ sz = menuMask.region.boundingRect().size();
+ }
+ break; }
+ case CT_HeaderSection:{
+ const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt);
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz);
+ if (header->text.contains(QLatin1Char('\n')))
+ useAquaGuideline = false;
+ break; }
+ case CT_ScrollBar :
+ // Make sure that the scroll bar is large enough to display the thumb indicator.
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ const int minimumWidth = 24;
+ const int absoluteHeight = 14;
+ if (slider->orientation == Qt::Horizontal) {
+ sz = sz.expandedTo(QSize(minimumWidth, sz.height()));
+ sz.setHeight(absoluteHeight);
+ } else {
+ sz = sz.expandedTo(QSize(sz.width(), minimumWidth));
+ sz.setWidth(absoluteHeight);
+ }
+ }
+ break;
+ case CT_ItemViewItem:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ sz = QCommonStyle::sizeFromContents(ct, vopt, csz);
+ sz.setHeight(sz.height() + 2);
+ }
+ break;
+ default:
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz);
+ }
+
+ if (useAquaGuideline && ct != CT_PushButton) {
+ // TODO Probably going away at some point
+ QSize macsz;
+ if (d->aquaSizeConstrain(opt, ct, sz, &macsz) != QStyleHelper::SizeDefault) {
+ if (macsz.width() != -1)
+ sz.setWidth(macsz.width());
+ if (macsz.height() != -1)
+ sz.setHeight(macsz.height());
+ }
+ }
+
+ // The sizes that Carbon and the guidelines gives us excludes the focus frame.
+ // We compensate for this by adding some extra space here to make room for the frame when drawing:
+ if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt)){
+ if (combo->editable) {
+ const auto widgetSize = d->aquaSizeConstrain(opt);
+ QMacStylePrivate::CocoaControl cw;
+ cw.type = combo->editable ? QMacStylePrivate::ComboBox : QMacStylePrivate::Button_PopupButton;
+ cw.size = widgetSize;
+ const CGRect diffRect = QMacStylePrivate::comboboxInnerBounds(CGRectZero, cw);
+ sz.rwidth() -= qRound(diffRect.size.width);
+ sz.rheight() -= qRound(diffRect.size.height);
+ }
+ }
+ return sz;
+}
+
+QFont QMacStyle::font(QStyle::ControlElement element, const QStyle::State state) const
+{
+ QFont font = QCommonStyle::font(element, state);
+
+ if (state & QStyle::State_Small) {
+ font.setPixelSize(11);
+ } else if (state & QStyle::State_Mini) {
+ font.setPixelSize(9);
+ }
+
+ return font;
+}
+
+QMargins QMacStyle::ninePatchMargins(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const
+{
+ QMargins margins;
+
+ switch (cc) {
+ case CC_ComboBox: {
+ const QRect arrow = subControlRect(CC_ComboBox, opt, SC_ComboBoxArrow);
+ margins = QMargins(10, 0, arrow.width() + 1, -1);
+ break; }
+ default:
+ margins = QCommonStyle::ninePatchMargins(cc, opt, imageSize);
+ break;
+ }
+
+ return margins;
+}
+
+void QMacStyle::drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
+ bool enabled, const QString &text, QPalette::ColorRole textRole) const
+{
+ if(flags & Qt::TextShowMnemonic)
+ flags |= Qt::TextHideMnemonic;
+ QCommonStyle::drawItemText(p, r, flags, pal, enabled, text, textRole);
+}
+
+QIcon QMacStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *opt) const
+{
+ switch (standardIcon) {
+ default:
+ return QCommonStyle::standardIcon(standardIcon, opt);
+ case SP_ToolBarHorizontalExtensionButton:
+ case SP_ToolBarVerticalExtensionButton: {
+ QPixmap pixmap(QLatin1String(":/qt-project.org/styles/macstyle/images/toolbar-ext.png"));
+ if (standardIcon == SP_ToolBarVerticalExtensionButton) {
+ QPixmap pix2(pixmap.height(), pixmap.width());
+ pix2.setDevicePixelRatio(pixmap.devicePixelRatio());
+ pix2.fill(Qt::transparent);
+ QPainter p(&pix2);
+ p.translate(pix2.width(), 0);
+ p.rotate(90);
+ p.drawPixmap(0, 0, pixmap);
+ return pix2;
+ }
+ return pixmap;
+ }
+ }
+}
+
+} // QQC2_NAMESPACE
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p.h b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p.h
new file mode 100644
index 0000000000..b9e1c5f341
--- /dev/null
+++ b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMACSTYLE_MAC_P_H
+#define QMACSTYLE_MAC_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 "qquickcommonstyle.h"
+
+#define QQC2_NAMESPACE QQC2
+
+QT_BEGIN_NAMESPACE
+
+class QPalette;
+
+namespace QQC2_NAMESPACE {
+
+class QStyleOptionButton;
+class QMacStylePrivate;
+
+class QMacStyle : public QCommonStyle
+{
+ Q_OBJECT
+public:
+ QMacStyle();
+ ~QMacStyle();
+
+ void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const override;
+ void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p) const override;
+ void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const override;
+
+ QRect subElementRect(SubElement r, const QStyleOption *opt) const override;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc) const override;
+ SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const override;
+
+ QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const override;
+ QFont font(ControlElement element, const QStyle::State state) const override;
+ QMargins ninePatchMargins(ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const override;
+
+ int pixelMetric(PixelMetric pm, const QStyleOption *opt = 0) const override;
+ int styleHint(StyleHint sh, const QStyleOption *opt = 0, QStyleHintReturn *shret = 0) const override;
+
+ QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt) const override;
+ QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const override;
+
+ void drawItemText(QPainter *p, const QRect &r, int flags, const QPalette &pal,
+ bool enabled, const QString &text,
+ QPalette::ColorRole textRole = QPalette::NoRole) const override;
+
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = 0) const override;
+
+private:
+ Q_DISABLE_COPY_MOVE(QMacStyle)
+ Q_DECLARE_PRIVATE(QMacStyle)
+};
+
+} // QQC2_NAMESPACE
+
+QT_END_NAMESPACE
+
+#endif // QMACSTYLE_MAC_P_H
diff --git a/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p_p.h b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p_p.h
new file mode 100644
index 0000000000..a0c67bfb6b
--- /dev/null
+++ b/src/quicknativestyle/qstyle/mac/qquickmacstyle_mac_p_p.h
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QMACSTYLE_MAC_P_P_H
+#define QMACSTYLE_MAC_P_P_H
+
+#include "qquickmacstyle_mac_p.h"
+#include "qquickcommonstyle_p.h"
+#include "qquickstylehelper_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qhash.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qmath.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qpointer.h>
+#include <QtCore/qtextstream.h>
+#include <QtCore/qvector.h>
+
+#include <QtGui/qbitmap.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qpaintdevice.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmapcache.h>
+
+#include <QtQuick/qquickitem.h>
+
+#include <QtCore/private/qcore_mac_p.h>
+#include <QtGui/private/qpainter_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.
+//
+
+Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(CGContext);
+
+Q_FORWARD_DECLARE_OBJC_CLASS(NSView);
+Q_FORWARD_DECLARE_OBJC_CLASS(NSCell);
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+/*
+ AHIG:
+ macOS Human Interface Guidelines
+ https://developer.apple.com/macos/human-interface-guidelines/overview/themes/
+
+ Builder:
+ Interface Builder in Xcode 8 or later
+*/
+
+// this works as long as we have at most 16 different control types
+#define CT1(c) CT2(c, c)
+#define CT2(c1, c2) ((uint(c1) << 16) | uint(c2))
+
+#define SIZE(large, small, mini) \
+ (controlSize == QStyleHelper::SizeLarge ? (large) : controlSize == QStyleHelper::SizeSmall ? (small) : (mini))
+
+// same as return SIZE(...) but optimized
+#define return_SIZE(large, small, mini) \
+ do { \
+ static const int sizes[] = { (large), (small), (mini) }; \
+ return sizes[controlSize]; \
+ } while (false)
+
+class QMacStylePrivate : public QCommonStylePrivate
+{
+ Q_DECLARE_PUBLIC(QMacStyle)
+
+public:
+ enum Direction {
+ North, South, East, West
+ };
+
+ enum CocoaControlType {
+ NoControl, // For when there's no such a control in Cocoa
+ Box, // QGroupBox
+ Box_Dark, // FIXME See render code in drawPrimitive(PE_FrameTabWidget)
+ Button_CheckBox,
+ Button_Disclosure, // Disclosure triangle, like in QTreeView
+ Button_PopupButton, // Non-editable QComboBox
+ Button_PullDown, // QPushButton with menu
+ Button_PushButton, // Plain QPushButton and QTabBar buttons
+ Button_RadioButton,
+ Button_SquareButton, // Oversized QPushButton
+ Button_WindowClose,
+ Button_WindowMiniaturize,
+ Button_WindowZoom,
+ ComboBox, // Editable QComboBox
+ ProgressIndicator_Determinate,
+ ProgressIndicator_Indeterminate,
+ Scroller_Horizontal,
+ Scroller_Vertical,
+ SegmentedControl_First, // QTabBar buttons focus ring
+ SegmentedControl_Middle,
+ SegmentedControl_Last,
+ SegmentedControl_Single,
+ Slider_Horizontal,
+ Slider_Vertical,
+ SplitView_Horizontal,
+ SplitView_Vertical,
+ Stepper, // QSpinBox buttons
+ TextField
+ };
+
+ struct CocoaControl {
+ CocoaControl();
+ CocoaControl(CocoaControlType t, QStyleHelper::WidgetSizePolicy s);
+
+ CocoaControlType type;
+ QStyleHelper::WidgetSizePolicy size;
+
+ bool operator==(const CocoaControl &other) const;
+
+ QSizeF defaultFrameSize() const;
+ QRectF adjustedControlFrame(const QRectF &rect) const;
+ QMarginsF titleMargins() const;
+
+ bool getCocoaButtonTypeAndBezelStyle(NSButtonType *buttonType, NSBezelStyle *bezelStyle) const;
+ };
+
+ typedef void (^DrawRectBlock)(CGContextRef, const CGRect &);
+
+ QMacStylePrivate();
+ ~QMacStylePrivate();
+
+ // Ideally these wouldn't exist, but since they already exist we need some accessors.
+ static const int PushButtonLeftOffset;
+ static const int PushButtonRightOffset;
+ static const int PushButtonContentPadding;
+
+ enum Animates { AquaPushButton, AquaProgressBar, AquaListViewItemOpen, AquaScrollBar };
+ QStyleHelper::WidgetSizePolicy aquaSizeConstrain(const QStyleOption *option,
+ QStyle::ContentsType ct = QStyle::CT_CustomBase,
+ QSize szHint=QSize(-1, -1), QSize *insz = 0) const;
+ QStyleHelper::WidgetSizePolicy effectiveAquaSizeConstrain(const QStyleOption *option,
+ QStyle::ContentsType ct = QStyle::CT_CustomBase,
+ QSize szHint=QSize(-1, -1), QSize *insz = 0) const;
+ inline int animateSpeed(Animates) const { return 33; }
+
+ // Utility functions
+ static CGRect comboboxInnerBounds(const CGRect &outterBounds, const CocoaControl &cocoaWidget);
+
+ static QRectF comboboxEditBounds(const QRectF &outterBounds, const CocoaControl &cw);
+
+ void setAutoDefaultButton(QObject *button) const;
+
+ NSView *cocoaControl(CocoaControl cocoaControl) const;
+ NSCell *cocoaCell(CocoaControl cocoaControl) const;
+
+ void setupNSGraphicsContext(CGContextRef cg, bool flipped) const;
+ void restoreNSGraphicsContext(CGContextRef cg) const;
+
+ void setupVerticalInvertedXform(CGContextRef cg, bool reverse, bool vertical, const CGRect &rect) const;
+
+ void drawNSViewInRect(NSView *view, const QRectF &rect, QPainter *p, DrawRectBlock drawRectBlock = nil) const;
+ void resolveCurrentNSView(QWindow *window) const;
+
+ void drawToolbarButtonArrow(const QStyleOption *opt, QPainter *p) const;
+
+ QPainterPath windowPanelPath(const QRectF &r) const;
+
+ CocoaControlType windowButtonCocoaControl(QStyle::SubControl sc) const;
+
+ void tabLayout(const QStyleOptionTab *opt, QRect *textRect, QRect *iconRect) const override;
+ static Direction tabDirection(QStyleOptionTab::Shape shape);
+ static bool verticalTabs(QMacStylePrivate::Direction tabDirection);
+
+public:
+ mutable QPointer<QObject> autoDefaultButton;
+ static QVector<QPointer<QObject> > scrollBars;
+
+ mutable QPointer<QQuickItem> focusWidget; // TODO: rename to focusItem
+ mutable NSView *backingStoreNSView;
+ mutable QHash<CocoaControl, NSView *> cocoaControls;
+ mutable QHash<CocoaControl, NSCell *> cocoaCells;
+
+ QFont smallSystemFont;
+ QFont miniSystemFont;
+
+ QMacKeyValueObserver appearanceObserver;
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QMACSTYLE_MAC_P_P_H
diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.cpp b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
new file mode 100644
index 0000000000..81bd57d4aa
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickcommonstyle.cpp
@@ -0,0 +1,6083 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcommonstyle.h"
+#include "qquickcommonstyle_p.h"
+#include "qquickcommonstylepixmaps_p.h"
+
+#include "qquickstyleoption.h"
+#include "qquickdrawutil.h"
+#include "qquickstylehelper_p.h"
+
+#include <QtGui/QWindow>
+#include <qfile.h>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformtheme.h>
+#include <qbitmap.h>
+#include <qcache.h>
+#include <qmath.h>
+#include <qpainter.h>
+#include <qpaintengine.h>
+#include <qpainterpath.h>
+#include <private/qmath_p.h>
+#include <qdebug.h>
+#include <qtextformat.h>
+#include <qfileinfo.h>
+#include <qdir.h>
+#include <qsettings.h>
+#include <qvariant.h>
+#include <qpixmapcache.h>
+#include <qmatrix4x4.h>
+
+#include <limits.h>
+
+#include <private/qtextengine_p.h>
+#include <QtGui/private/qhexstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static inline qreal dpr(const QWindow *w)
+{
+ return w != nullptr ? w->devicePixelRatio() : qApp->devicePixelRatio();
+}
+
+/*!
+ \class QCommonStyle
+ \brief The QCommonStyle class encapsulates the common Look and Feel of a GUI.
+
+ \ingroup appearance
+ \inmodule QtWidgets
+
+ This abstract class implements some of the widget's look and feel
+ that is common to all GUI styles provided and shipped as part of
+ Qt.
+
+ Since QCommonStyle inherits QStyle, all of its functions are fully documented
+ in the QStyle documentation.
+ \omit
+ , although the
+ extra functions that QCommonStyle provides, e.g.
+ drawComplexControl(), drawControl(), drawPrimitive(),
+ hitTestComplexControl(), subControlRect(), sizeFromContents(), and
+ subElementRect() are documented here.
+ \endomit
+
+ \sa QStyle, QProxyStyle
+*/
+
+namespace QQC2 {
+
+QCommonStyle::QCommonStyle()
+ : QStyle(*new QCommonStylePrivate)
+{ }
+
+QCommonStyle::QCommonStyle(QCommonStylePrivate &dd)
+ : QStyle(dd)
+{ }
+
+QCommonStyle::~QCommonStyle()
+{ }
+
+void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const
+{
+ Q_D(const QCommonStyle);
+ switch (pe) {
+ case PE_FrameButtonBevel:
+ case PE_FrameButtonTool:
+ qDrawShadeRect(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), 1, 0);
+ break;
+ case PE_PanelButtonCommand:
+ case PE_PanelButtonBevel:
+ case PE_PanelButtonTool:
+ case PE_IndicatorButtonDropDown:
+ qDrawShadePanel(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), 1,
+ &opt->palette.brush(QPalette::Button));
+ break;
+ case PE_IndicatorItemViewItemCheck:
+ proxy()->drawPrimitive(PE_IndicatorCheckBox, opt, p);
+ break;
+ case PE_IndicatorCheckBox:
+ if (opt->state & State_NoChange) {
+ p->setPen(opt->palette.windowText().color());
+ p->fillRect(opt->rect, opt->palette.brush(QPalette::Button));
+ p->drawRect(opt->rect);
+ p->drawLine(opt->rect.topLeft(), opt->rect.bottomRight());
+ } else {
+ qDrawShadePanel(p, opt->rect.x(), opt->rect.y(), opt->rect.width(), opt->rect.height(),
+ opt->palette, opt->state & (State_Sunken | State_On), 1,
+ &opt->palette.brush(QPalette::Button));
+ }
+ break;
+ case PE_IndicatorRadioButton: {
+ QRect ir = opt->rect;
+ p->setPen(opt->palette.dark().color());
+ p->drawArc(opt->rect, 0, 5760);
+ if (opt->state & (State_Sunken | State_On)) {
+ ir.adjust(2, 2, -2, -2);
+ p->setBrush(opt->palette.windowText());
+ p->drawEllipse(ir);
+ }
+ break; }
+ case PE_FrameFocusRect:
+ if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
+ QColor bg = fropt->backgroundColor;
+ QPen oldPen = p->pen();
+ if (bg.isValid()) {
+ int h, s, v;
+ bg.getHsv(&h, &s, &v);
+ if (v >= 128)
+ p->setPen(Qt::black);
+ else
+ p->setPen(Qt::white);
+ } else {
+ p->setPen(opt->palette.windowText().color());
+ }
+ QRect focusRect = opt->rect.adjusted(1, 1, -1, -1);
+ p->drawRect(focusRect.adjusted(0, 0, -1, -1)); //draw pen inclusive
+ p->setPen(oldPen);
+ }
+ break;
+ case PE_IndicatorMenuCheckMark: {
+ const int markW = opt->rect.width() > 7 ? 7 : opt->rect.width();
+ const int markH = markW;
+ int posX = opt->rect.x() + (opt->rect.width() - markW)/2 + 1;
+ int posY = opt->rect.y() + (opt->rect.height() - markH)/2;
+
+ QVector<QLineF> a;
+ a.reserve(markH);
+
+ int i, xx, yy;
+ xx = posX;
+ yy = 3 + posY;
+ for (i = 0; i < markW/2; ++i) {
+ a << QLineF(xx, yy, xx, yy + 2);
+ ++xx;
+ ++yy;
+ }
+ yy -= 2;
+ for (; i < markH; ++i) {
+ a << QLineF(xx, yy, xx, yy + 2);
+ ++xx;
+ --yy;
+ }
+ if (!(opt->state & State_Enabled) && !(opt->state & State_On)) {
+ p->save();
+ p->translate(1, 1);
+ p->setPen(opt->palette.light().color());
+ p->drawLines(a);
+ p->restore();
+ }
+ p->setPen((opt->state & State_On) ? opt->palette.highlightedText().color() : opt->palette.text().color());
+ p->drawLines(a);
+ break; }
+ case PE_Frame:
+ case PE_FrameMenu:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ if (pe == PE_FrameMenu || (frame->state & State_Sunken) || (frame->state & State_Raised)) {
+ qDrawShadePanel(p, frame->rect, frame->palette, frame->state & State_Sunken,
+ frame->lineWidth);
+ } else {
+ qDrawPlainRect(p, frame->rect, frame->palette.windowText().color(), frame->lineWidth);
+ }
+ }
+ break;
+ case PE_PanelMenuBar:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)){
+ qDrawShadePanel(p, frame->rect, frame->palette, false, frame->lineWidth,
+ &frame->palette.brush(QPalette::Button));
+
+ }
+ else if (const QStyleOptionToolBar *frame = qstyleoption_cast<const QStyleOptionToolBar *>(opt)){
+ qDrawShadePanel(p, frame->rect, frame->palette, false, frame->lineWidth,
+ &frame->palette.brush(QPalette::Button));
+ }
+
+ break;
+ case PE_PanelMenu:
+ break;
+ case PE_PanelToolBar:
+ break;
+ case PE_IndicatorProgressChunk:
+ {
+ p->fillRect(opt->rect.x(), opt->rect.y() + 3, opt->rect.width() -2, opt->rect.height() - 6,
+ opt->palette.brush(QPalette::Highlight));
+ }
+ break;
+ case PE_IndicatorBranch: {
+ static const int decoration_size = 9;
+ int mid_h = opt->rect.x() + opt->rect.width() / 2;
+ int mid_v = opt->rect.y() + opt->rect.height() / 2;
+ int bef_h = mid_h;
+ int bef_v = mid_v;
+ int aft_h = mid_h;
+ int aft_v = mid_v;
+ if (opt->state & State_Children) {
+ int delta = decoration_size / 2;
+ bef_h -= delta;
+ bef_v -= delta;
+ aft_h += delta;
+ aft_v += delta;
+ p->drawLine(bef_h + 2, bef_v + 4, bef_h + 6, bef_v + 4);
+ if (!(opt->state & State_Open))
+ p->drawLine(bef_h + 4, bef_v + 2, bef_h + 4, bef_v + 6);
+ QPen oldPen = p->pen();
+ p->setPen(opt->palette.dark().color());
+ p->drawRect(bef_h, bef_v, decoration_size - 1, decoration_size - 1);
+ p->setPen(oldPen);
+ }
+ QBrush brush(opt->palette.dark().color(), Qt::Dense4Pattern);
+ if (opt->state & State_Item) {
+ if (opt->direction == Qt::RightToLeft)
+ p->fillRect(opt->rect.left(), mid_v, bef_h - opt->rect.left(), 1, brush);
+ else
+ p->fillRect(aft_h, mid_v, opt->rect.right() - aft_h + 1, 1, brush);
+ }
+ if (opt->state & State_Sibling)
+ p->fillRect(mid_h, aft_v, 1, opt->rect.bottom() - aft_v + 1, brush);
+ if (opt->state & (State_Open | State_Children | State_Item | State_Sibling))
+ p->fillRect(mid_h, opt->rect.y(), 1, bef_v - opt->rect.y(), brush);
+ break; }
+ case PE_FrameStatusBarItem:
+ qDrawShadeRect(p, opt->rect, opt->palette, true, 1, 0, nullptr);
+ break;
+ case PE_IndicatorHeaderArrow:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ QPen oldPen = p->pen();
+ if (header->sortIndicator & QStyleOptionHeader::SortUp) {
+ p->setPen(QPen(opt->palette.light(), 0));
+ p->drawLine(opt->rect.x() + opt->rect.width(), opt->rect.y(),
+ opt->rect.x() + opt->rect.width() / 2, opt->rect.y() + opt->rect.height());
+ p->setPen(QPen(opt->palette.dark(), 0));
+ const QPoint points[] = {
+ QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y() + opt->rect.height()),
+ QPoint(opt->rect.x(), opt->rect.y()),
+ QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y()),
+ };
+ p->drawPolyline(points, sizeof points / sizeof *points);
+ } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
+ p->setPen(QPen(opt->palette.light(), 0));
+ const QPoint points[] = {
+ QPoint(opt->rect.x(), opt->rect.y() + opt->rect.height()),
+ QPoint(opt->rect.x() + opt->rect.width(), opt->rect.y() + opt->rect.height()),
+ QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y()),
+ };
+ p->drawPolyline(points, sizeof points / sizeof *points);
+ p->setPen(QPen(opt->palette.dark(), 0));
+ p->drawLine(opt->rect.x(), opt->rect.y() + opt->rect.height(),
+ opt->rect.x() + opt->rect.width() / 2, opt->rect.y());
+ }
+ p->setPen(oldPen);
+ }
+ break;
+ case PE_FrameTabBarBase:
+ if (const QStyleOptionTabBarBase *tbb
+ = qstyleoption_cast<const QStyleOptionTabBarBase *>(opt)) {
+ p->save();
+ switch (tbb->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ p->setPen(QPen(tbb->palette.light(), 0));
+ p->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
+ break;
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ p->setPen(QPen(tbb->palette.light(), 0));
+ p->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ p->setPen(QPen(tbb->palette.shadow(), 0));
+ p->drawLine(tbb->rect.left(), tbb->rect.bottom(),
+ tbb->rect.right(), tbb->rect.bottom());
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.left(), tbb->rect.bottom() - 1,
+ tbb->rect.right() - 1, tbb->rect.bottom() - 1);
+ break;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.topRight(), tbb->rect.bottomRight());
+ break;
+ }
+ p->restore();
+ }
+ break;
+ case PE_IndicatorTabClose: {
+ if (d->tabBarcloseButtonIcon.isNull()) {
+ d->tabBarcloseButtonIcon.addPixmap(QPixmap(
+ QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-16.png")),
+ QIcon::Normal, QIcon::Off);
+ d->tabBarcloseButtonIcon.addPixmap(QPixmap(
+ QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-down-16.png")),
+ QIcon::Normal, QIcon::On);
+ d->tabBarcloseButtonIcon.addPixmap(QPixmap(
+ QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-closetab-hover-16.png")),
+ QIcon::Active, QIcon::Off);
+ }
+
+ int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
+ QIcon::Mode mode = opt->state & State_Enabled ?
+ (opt->state & State_Raised ? QIcon::Active : QIcon::Normal)
+ : QIcon::Disabled;
+ if (!(opt->state & State_Raised)
+ && !(opt->state & State_Sunken)
+ && !(opt->state & QStyle::State_Selected))
+ mode = QIcon::Disabled;
+
+ QIcon::State state = opt->state & State_Sunken ? QIcon::On : QIcon::Off;
+ QPixmap pixmap = d->tabBarcloseButtonIcon.pixmap(QSize(size, size), dpr(opt->window), mode, state);
+ proxy()->drawItemPixmap(p, opt->rect, Qt::AlignCenter, pixmap);
+ break;
+ }
+ case PE_FrameTabWidget:
+ case PE_FrameWindow:
+ qDrawWinPanel(p, opt->rect, opt->palette, false, nullptr);
+ break;
+ case PE_FrameLineEdit:
+ proxy()->drawPrimitive(PE_Frame, opt, p);
+ break;
+ case PE_FrameGroupBox:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ if (frame->features & QStyleOptionFrame::Flat) {
+ QRect fr = frame->rect;
+ QPoint p1(fr.x(), fr.y() + 1);
+ QPoint p2(fr.x() + fr.width(), p1.y());
+ qDrawShadeLine(p, p1, p2, frame->palette, true,
+ frame->lineWidth, frame->midLineWidth);
+ } else {
+ qDrawShadeRect(p, frame->rect.x(), frame->rect.y(), frame->rect.width(),
+ frame->rect.height(), frame->palette, true,
+ frame->lineWidth, frame->midLineWidth);
+ }
+ }
+ break;
+ case PE_FrameDockWidget:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ int lw = frame->lineWidth;
+ if (lw <= 0)
+ lw = proxy()->pixelMetric(PM_DockWidgetFrameWidth);
+
+ qDrawShadePanel(p, frame->rect, frame->palette, false, lw);
+ }
+ break;
+ case PE_IndicatorToolBarHandle:
+ p->save();
+ p->translate(opt->rect.x(), opt->rect.y());
+ if (opt->state & State_Horizontal) {
+ int x = opt->rect.width() / 3;
+ if (opt->direction == Qt::RightToLeft)
+ x -= 2;
+ if (opt->rect.height() > 4) {
+ qDrawShadePanel(p, x, 2, 3, opt->rect.height() - 4,
+ opt->palette, false, 1, nullptr);
+ qDrawShadePanel(p, x+3, 2, 3, opt->rect.height() - 4,
+ opt->palette, false, 1, nullptr);
+ }
+ } else {
+ if (opt->rect.width() > 4) {
+ int y = opt->rect.height() / 3;
+ qDrawShadePanel(p, 2, y, opt->rect.width() - 4, 3,
+ opt->palette, false, 1, nullptr);
+ qDrawShadePanel(p, 2, y+3, opt->rect.width() - 4, 3,
+ opt->palette, false, 1, nullptr);
+ }
+ }
+ p->restore();
+ break;
+ case PE_IndicatorToolBarSeparator:
+ {
+ QPoint p1, p2;
+ if (opt->state & State_Horizontal) {
+ p1 = QPoint(opt->rect.width()/2, 0);
+ p2 = QPoint(p1.x(), opt->rect.height());
+ } else {
+ p1 = QPoint(0, opt->rect.height()/2);
+ p2 = QPoint(opt->rect.width(), p1.y());
+ }
+ qDrawShadeLine(p, p1, p2, opt->palette, 1, 1, 0);
+ break;
+ }
+ case PE_IndicatorSpinPlus:
+ case PE_IndicatorSpinMinus: {
+ QRect r = opt->rect;
+ int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ QRect br = r.adjusted(fw, fw, -fw, -fw);
+
+ int offset = (opt->state & State_Sunken) ? 1 : 0;
+ int step = (br.width() + 4) / 5;
+ p->fillRect(br.x() + offset, br.y() + offset +br.height() / 2 - step / 2,
+ br.width(), step,
+ opt->palette.buttonText());
+ if (pe == PE_IndicatorSpinPlus)
+ p->fillRect(br.x() + br.width() / 2 - step / 2 + offset, br.y() + offset,
+ step, br.height(),
+ opt->palette.buttonText());
+
+ break; }
+ case PE_IndicatorSpinUp:
+ case PE_IndicatorSpinDown: {
+ QRect r = opt->rect;
+ int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ // QRect br = r.adjusted(fw, fw, -fw, -fw);
+ int x = r.x(), y = r.y(), w = r.width(), h = r.height();
+ int sw = w-4;
+ if (sw < 3)
+ break;
+ else if (!(sw & 1))
+ sw--;
+ sw -= (sw / 7) * 2; // Empty border
+ int sh = sw/2 + 2; // Must have empty row at foot of arrow
+
+ int sx = x + w / 2 - sw / 2;
+ int sy = y + h / 2 - sh / 2;
+
+ if (pe == PE_IndicatorSpinUp && fw)
+ --sy;
+
+ int bsx = 0;
+ int bsy = 0;
+ if (opt->state & State_Sunken) {
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
+ }
+ p->save();
+ p->translate(sx + bsx, sy + bsy);
+ p->setPen(opt->palette.buttonText().color());
+ p->setBrush(opt->palette.buttonText());
+ if (pe == PE_IndicatorSpinDown) {
+ const QPoint points[] = { QPoint(0, 1), QPoint(sw-1, 1), QPoint(sh-2, sh-1) };
+ p->drawPolygon(points, sizeof points / sizeof *points);
+ } else {
+ const QPoint points[] = { QPoint(0, sh-1), QPoint(sw-1, sh-1), QPoint(sh-2, 1) };
+ p->drawPolygon(points, sizeof points / sizeof *points);
+ }
+ p->restore();
+ break; }
+ case PE_PanelTipLabel: {
+ const QBrush brush(opt->palette.toolTipBase());
+ qDrawPlainRect(p, opt->rect, opt->palette.toolTipText().color(), 1, &brush);
+ break;
+ }
+ case PE_IndicatorTabTear:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ bool rtl = tab->direction == Qt::RightToLeft;
+ const bool horizontal = tab->rect.height() > tab->rect.width();
+ const int margin = 4;
+ QPainterPath path;
+
+ if (horizontal) {
+ QRect rect = tab->rect.adjusted(rtl ? margin : 0, 0, rtl ? 1 : -margin, 0);
+ rect.setTop(rect.top() + ((tab->state & State_Selected) ? 1 : 3));
+ rect.setBottom(rect.bottom() - ((tab->state & State_Selected) ? 0 : 2));
+
+ path.moveTo(QPoint(rtl ? rect.right() : rect.left(), rect.top()));
+ int count = 4;
+ for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
+ path.lineTo(QPoint(rtl ? rect.left() : rect.right(), rect.top() + jags * rect.height()/count));
+ } else {
+ QRect rect = tab->rect.adjusted(0, 0, 0, -margin);
+ rect.setLeft(rect.left() + ((tab->state & State_Selected) ? 1 : 3));
+ rect.setRight(rect.right() - ((tab->state & State_Selected) ? 0 : 2));
+
+ path.moveTo(QPoint(rect.left(), rect.top()));
+ int count = 4;
+ for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
+ path.lineTo(QPoint(rect.left() + jags * rect.width()/count, rtl ? rect.top() : rect.bottom()));
+ }
+
+ p->setPen(QPen(tab->palette.dark(), qreal(.8)));
+ p->setBrush(tab->palette.window());
+ p->setRenderHint(QPainter::Antialiasing);
+ p->drawPath(path);
+ }
+ break;
+ case PE_PanelLineEdit:
+ if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ p->fillRect(panel->rect.adjusted(panel->lineWidth, panel->lineWidth, -panel->lineWidth, -panel->lineWidth),
+ panel->palette.brush(QPalette::Base));
+
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, p);
+ }
+ break;
+ case PE_IndicatorColumnViewArrow: {
+ if (const QStyleOptionViewItem *viewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ bool reverse = (viewOpt->direction == Qt::RightToLeft);
+ p->save();
+ QPainterPath path;
+ int x = viewOpt->rect.x() + 1;
+ int offset = (viewOpt->rect.height() / 3);
+ int height = (viewOpt->rect.height()) - offset * 2;
+ if (height % 2 == 1)
+ --height;
+ int x2 = x + height - 1;
+ if (reverse) {
+ x = viewOpt->rect.x() + viewOpt->rect.width() - 1;
+ x2 = x - height + 1;
+ }
+ path.moveTo(x, viewOpt->rect.y() + offset);
+ path.lineTo(x, viewOpt->rect.y() + offset + height);
+ path.lineTo(x2, viewOpt->rect.y() + offset+height/2);
+ path.closeSubpath();
+ if (viewOpt->state & QStyle::State_Selected ) {
+ if (viewOpt->showDecorationSelected) {
+ QColor color = viewOpt->palette.color(QPalette::Active, QPalette::HighlightedText);
+ p->setPen(color);
+ p->setBrush(color);
+ } else {
+ QColor color = viewOpt->palette.color(QPalette::Active, QPalette::WindowText);
+ p->setPen(color);
+ p->setBrush(color);
+ }
+
+ } else {
+ QColor color = viewOpt->palette.color(QPalette::Active, QPalette::Mid);
+ p->setPen(color);
+ p->setBrush(color);
+ }
+ p->drawPath(path);
+
+ // draw the vertical and top triangle line
+ if (!(viewOpt->state & QStyle::State_Selected)) {
+ QPainterPath lines;
+ lines.moveTo(x, viewOpt->rect.y() + offset);
+ lines.lineTo(x, viewOpt->rect.y() + offset + height);
+ lines.moveTo(x, viewOpt->rect.y() + offset);
+ lines.lineTo(x2, viewOpt->rect.y() + offset+height/2);
+ QColor color = viewOpt->palette.color(QPalette::Active, QPalette::Dark);
+ p->setPen(color);
+ p->drawPath(lines);
+ }
+ p->restore();
+ }
+ break; }
+ case PE_IndicatorItemViewItemDrop: {
+ QRect rect = opt->rect;
+ if (opt->rect.height() == 0)
+ p->drawLine(rect.topLeft(), rect.topRight());
+ else
+ p->drawRect(rect);
+ break; }
+ case PE_PanelItemViewRow:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ if ((vopt->state & QStyle::State_Selected) && proxy()->styleHint(QStyle::SH_ItemView_ShowDecorationSelected, opt))
+ p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::Highlight));
+ else if (vopt->features & QStyleOptionViewItem::Alternate)
+ p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::AlternateBase));
+ }
+ break;
+ case PE_PanelItemViewItem:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ if (vopt->showDecorationSelected && (vopt->state & QStyle::State_Selected)) {
+ p->fillRect(vopt->rect, vopt->palette.brush(cg, QPalette::Highlight));
+ } else {
+ if (vopt->backgroundBrush.style() != Qt::NoBrush) {
+ QPointF oldBO = p->brushOrigin();
+ p->setBrushOrigin(vopt->rect.topLeft());
+ p->fillRect(vopt->rect, vopt->backgroundBrush);
+ p->setBrushOrigin(oldBO);
+ }
+
+ if (vopt->state & QStyle::State_Selected) {
+ QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, opt);
+ p->fillRect(textRect, vopt->palette.brush(cg, QPalette::Highlight));
+ }
+ }
+ }
+ break;
+ case PE_PanelScrollAreaCorner: {
+ const QBrush brush(opt->palette.brush(QPalette::Window));
+ p->fillRect(opt->rect, brush);
+ } break;
+ case PE_IndicatorArrowUp:
+ case PE_IndicatorArrowDown:
+ case PE_IndicatorArrowRight:
+ case PE_IndicatorArrowLeft:
+ {
+ if (opt->rect.width() <= 1 || opt->rect.height() <= 1)
+ break;
+ QRect r = opt->rect;
+ int size = qMin(r.height(), r.width());
+ QPixmap pixmap;
+ QString pixmapName = QStyleHelper::uniqueName(QLatin1String("$qt_ia-")
+ % QLatin1String(metaObject()->className()), opt, QSize(size, size))
+ % HexString<uint>(pe);
+ if (!QPixmapCache::find(pixmapName, &pixmap)) {
+ qreal pixelRatio = p->device()->devicePixelRatioF();
+ int border = qRound(pixelRatio*(size/5));
+ int sqsize = qRound(pixelRatio*(2*(size/2)));
+ QImage image(sqsize, sqsize, QImage::Format_ARGB32_Premultiplied);
+ image.fill(0);
+ QPainter imagePainter(&image);
+
+ QPolygon a;
+ switch (pe) {
+ case PE_IndicatorArrowUp:
+ a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize - border, sqsize/2);
+ break;
+ case PE_IndicatorArrowDown:
+ a.setPoints(3, border, sqsize/2, sqsize/2, sqsize - border, sqsize - border, sqsize/2);
+ break;
+ case PE_IndicatorArrowRight:
+ a.setPoints(3, sqsize - border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
+ break;
+ case PE_IndicatorArrowLeft:
+ a.setPoints(3, border, sqsize/2, sqsize/2, border, sqsize/2, sqsize - border);
+ break;
+ default:
+ break;
+ }
+
+ int bsx = 0;
+ int bsy = 0;
+
+ if (opt->state & State_Sunken) {
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical, opt);
+ }
+
+ QRect bounds = a.boundingRect();
+ int sx = sqsize / 2 - bounds.center().x() - 1;
+ int sy = sqsize / 2 - bounds.center().y() - 1;
+ imagePainter.translate(sx + bsx, sy + bsy);
+ imagePainter.setPen(opt->palette.buttonText().color());
+ imagePainter.setBrush(opt->palette.buttonText());
+
+ if (!(opt->state & State_Enabled)) {
+ imagePainter.translate(1, 1);
+ imagePainter.setBrush(opt->palette.light().color());
+ imagePainter.setPen(opt->palette.light().color());
+ imagePainter.drawPolygon(a);
+ imagePainter.translate(-1, -1);
+ imagePainter.setBrush(opt->palette.mid().color());
+ imagePainter.setPen(opt->palette.mid().color());
+ }
+
+ imagePainter.drawPolygon(a);
+ imagePainter.end();
+ pixmap = QPixmap::fromImage(image);
+ pixmap.setDevicePixelRatio(pixelRatio);
+ QPixmapCache::insert(pixmapName, pixmap);
+ }
+ int xOffset = r.x() + (r.width() - size)/2;
+ int yOffset = r.y() + (r.height() - size)/2;
+ p->drawPixmap(xOffset, yOffset, pixmap);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void drawArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
+ const QRect &rect, QPainter *painter)
+{
+ QStyle::PrimitiveElement pe;
+ switch (toolbutton->arrowType) {
+ case Qt::LeftArrow:
+ pe = QStyle::PE_IndicatorArrowLeft;
+ break;
+ case Qt::RightArrow:
+ pe = QStyle::PE_IndicatorArrowRight;
+ break;
+ case Qt::UpArrow:
+ pe = QStyle::PE_IndicatorArrowUp;
+ break;
+ case Qt::DownArrow:
+ pe = QStyle::PE_IndicatorArrowDown;
+ break;
+ default:
+ return;
+ }
+ QStyleOption arrowOpt = *toolbutton;
+ arrowOpt.rect = rect;
+ style->drawPrimitive(pe, &arrowOpt, painter);
+}
+
+static QSizeF viewItemTextLayout(QTextLayout &textLayout, int lineWidth, int maxHeight = -1, int *lastVisibleLine = nullptr)
+{
+ if (lastVisibleLine)
+ *lastVisibleLine = -1;
+ qreal height = 0;
+ qreal widthUsed = 0;
+ textLayout.beginLayout();
+ int i = 0;
+ while (true) {
+ QTextLine line = textLayout.createLine();
+ if (!line.isValid())
+ break;
+ line.setLineWidth(lineWidth);
+ line.setPosition(QPointF(0, height));
+ height += line.height();
+ widthUsed = qMax(widthUsed, line.naturalTextWidth());
+ // we assume that the height of the next line is the same as the current one
+ if (maxHeight > 0 && lastVisibleLine && height + line.height() > maxHeight) {
+ const QTextLine nextLine = textLayout.createLine();
+ *lastVisibleLine = nextLine.isValid() ? i : -1;
+ break;
+ }
+ ++i;
+ }
+ textLayout.endLayout();
+ return QSizeF(widthUsed, height);
+}
+
+QString QCommonStylePrivate::calculateElidedText(const QString &text, const QTextOption &textOption,
+ const QFont &font, const QRect &textRect, const Qt::Alignment valign,
+ Qt::TextElideMode textElideMode, int flags,
+ bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const
+{
+ QTextLayout textLayout(text, font);
+ textLayout.setTextOption(textOption);
+
+ // In AlignVCenter mode when more than one line is displayed and the height only allows
+ // some of the lines it makes no sense to display those. From a users perspective it makes
+ // more sense to see the start of the text instead something inbetween.
+ const bool vAlignmentOptimization = paintStartPosition && valign.testFlag(Qt::AlignVCenter);
+
+ int lastVisibleLine = -1;
+ viewItemTextLayout(textLayout, textRect.width(), vAlignmentOptimization ? textRect.height() : -1, &lastVisibleLine);
+
+ const QRectF boundingRect = textLayout.boundingRect();
+ // don't care about LTR/RTL here, only need the height
+ const QRect layoutRect = QStyle::alignedRect(Qt::LayoutDirectionAuto, valign,
+ boundingRect.size().toSize(), textRect);
+
+ if (paintStartPosition)
+ *paintStartPosition = QPointF(textRect.x(), layoutRect.top());
+
+ QString ret;
+ qreal height = 0;
+ const int lineCount = textLayout.lineCount();
+ for (int i = 0; i < lineCount; ++i) {
+ const QTextLine line = textLayout.lineAt(i);
+ height += line.height();
+
+ // above visible rect
+ if (height + layoutRect.top() <= textRect.top()) {
+ if (paintStartPosition)
+ paintStartPosition->ry() += line.height();
+ continue;
+ }
+
+ const int start = line.textStart();
+ const int length = line.textLength();
+ const bool drawElided = line.naturalTextWidth() > textRect.width();
+ bool elideLastVisibleLine = lastVisibleLine == i;
+ if (!drawElided && i + 1 < lineCount && lastVisibleLineShouldBeElided) {
+ const QTextLine nextLine = textLayout.lineAt(i + 1);
+ const int nextHeight = height + nextLine.height() / 2;
+ // elide when less than the next half line is visible
+ if (nextHeight + layoutRect.top() > textRect.height() + textRect.top())
+ elideLastVisibleLine = true;
+ }
+
+ QString text = textLayout.text().mid(start, length);
+ if (drawElided || elideLastVisibleLine) {
+ if (elideLastVisibleLine) {
+ if (text.endsWith(QChar::LineSeparator))
+ text.chop(1);
+ text += QChar(0x2026);
+ }
+ const QStackTextEngine engine(text, font);
+ ret += engine.elidedText(textElideMode, textRect.width(), flags);
+
+ // no newline for the last line (last visible or real)
+ // sometimes drawElided is true but no eliding is done so the text ends
+ // with QChar::LineSeparator - don't add another one. This happened with
+ // arabic text in the testcase for QTBUG-72805
+ if (i < lineCount - 1 &&
+ !ret.endsWith(QChar::LineSeparator))
+ ret += QChar::LineSeparator;
+ } else {
+ ret += text;
+ }
+
+ // below visible text, can stop
+ if ((height + layoutRect.top() >= textRect.bottom()) ||
+ (lastVisibleLine >= 0 && lastVisibleLine == i))
+ break;
+ }
+ return ret;
+}
+
+QSize QCommonStylePrivate::viewItemSize(const QStyleOptionViewItem *option, int role) const
+{
+ switch (role) {
+ case Qt::CheckStateRole:
+ if (option->features & QStyleOptionViewItem::HasCheckIndicator)
+ return QSize(proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth, option),
+ proxyStyle->pixelMetric(QStyle::PM_IndicatorHeight, option));
+ break;
+ case Qt::DisplayRole:
+ if (option->features & QStyleOptionViewItem::HasDisplay) {
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::WordWrap);
+ QTextLayout textLayout(option->text, option->font);
+ textLayout.setTextOption(textOption);
+ const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
+ const int textMargin = proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, option) + 1;
+ QRect bounds = option->rect;
+ switch (option->decorationPosition) {
+ case QStyleOptionViewItem::Left:
+ case QStyleOptionViewItem::Right: {
+ if (wrapText && bounds.isValid()) {
+ int width = bounds.width() - 2 * textMargin;
+ if (option->features & QStyleOptionViewItem::HasDecoration)
+ width -= option->decorationSize.width() + 2 * textMargin;
+ bounds.setWidth(width);
+ } else
+ bounds.setWidth(QFIXED_MAX);
+ break;
+ }
+ case QStyleOptionViewItem::Top:
+ case QStyleOptionViewItem::Bottom:
+ if (wrapText)
+ bounds.setWidth(bounds.isValid() ? bounds.width() - 2 * textMargin : option->decorationSize.width());
+ else
+ bounds.setWidth(QFIXED_MAX);
+ break;
+ default:
+ break;
+ }
+
+ if (wrapText && option->features & QStyleOptionViewItem::HasCheckIndicator)
+ bounds.setWidth(bounds.width() - proxyStyle->pixelMetric(QStyle::PM_IndicatorWidth) - 2 * textMargin);
+
+ const int lineWidth = bounds.width();
+ const QSizeF size = viewItemTextLayout(textLayout, lineWidth);
+ return QSize(qCeil(size.width()) + 2 * textMargin, qCeil(size.height()));
+ }
+ break;
+ case Qt::DecorationRole:
+ if (option->features & QStyleOptionViewItem::HasDecoration) {
+ return option->decorationSize;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return QSize(0, 0);
+}
+
+void QCommonStylePrivate::viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const
+{
+ const int textMargin = proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, nullptr) + 1;
+
+ QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding
+ const bool wrapText = option->features & QStyleOptionViewItem::WrapText;
+ QTextOption textOption;
+ textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap);
+ textOption.setTextDirection(option->direction);
+ textOption.setAlignment(QStyle::visualAlignment(option->direction, option->displayAlignment));
+
+ QPointF paintPosition;
+ const QString newText = calculateElidedText(option->text, textOption,
+ option->font, textRect, option->displayAlignment,
+ option->textElideMode, 0,
+ true, &paintPosition);
+
+ QTextLayout textLayout(newText, option->font);
+ textLayout.setTextOption(textOption);
+ viewItemTextLayout(textLayout, textRect.width());
+ textLayout.draw(p, paintPosition);
+}
+
+/*! \internal
+ compute the position for the different component of an item (pixmap, text, checkbox)
+
+ Set sizehint to false to layout the elements inside opt->rect. Set sizehint to true to ignore
+ opt->rect and return rectangles in infinite space
+
+ Code duplicated in QItemDelegate::doLayout
+*/
+void QCommonStylePrivate::viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect,
+ QRect *pixmapRect, QRect *textRect, bool sizehint) const
+{
+ Q_ASSERT(checkRect && pixmapRect && textRect);
+ *pixmapRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::DecorationRole));
+ *textRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::DisplayRole));
+ *checkRect = QRect(QPoint(0, 0), viewItemSize(opt, Qt::CheckStateRole));
+
+ const bool hasCheck = checkRect->isValid();
+ const bool hasPixmap = pixmapRect->isValid();
+ const bool hasText = textRect->isValid();
+ const bool hasMargin = (hasText | hasPixmap | hasCheck);
+ const int frameHMargin = hasMargin ?
+ proxyStyle->pixelMetric(QStyle::PM_FocusFrameHMargin, opt) + 1 : 0;
+ const int textMargin = hasText ? frameHMargin : 0;
+ const int pixmapMargin = hasPixmap ? frameHMargin : 0;
+ const int checkMargin = hasCheck ? frameHMargin : 0;
+ const int x = opt->rect.left();
+ const int y = opt->rect.top();
+ int w, h;
+
+ if (textRect->height() == 0 && (!hasPixmap || !sizehint)) {
+ //if there is no text, we still want to have a decent height for the item sizeHint and the editor size
+ textRect->setHeight(opt->fontMetrics.height());
+ }
+
+ QSize pm(0, 0);
+ if (hasPixmap) {
+ pm = pixmapRect->size();
+ pm.rwidth() += 2 * pixmapMargin;
+ }
+ if (sizehint) {
+ h = qMax(checkRect->height(), qMax(textRect->height(), pm.height()));
+ if (opt->decorationPosition == QStyleOptionViewItem::Left
+ || opt->decorationPosition == QStyleOptionViewItem::Right) {
+ w = textRect->width() + pm.width();
+ } else {
+ w = qMax(textRect->width(), pm.width());
+ }
+ } else {
+ w = opt->rect.width();
+ h = opt->rect.height();
+ }
+
+ int cw = 0;
+ QRect check;
+ if (hasCheck) {
+ cw = checkRect->width() + 2 * checkMargin;
+ if (sizehint) w += cw;
+ if (opt->direction == Qt::RightToLeft) {
+ check.setRect(x + w - cw, y, cw, h);
+ } else {
+ check.setRect(x, y, cw, h);
+ }
+ }
+
+ QRect display;
+ QRect decoration;
+ switch (opt->decorationPosition) {
+ case QStyleOptionViewItem::Top: {
+ if (hasPixmap)
+ pm.setHeight(pm.height() + pixmapMargin); // add space
+ h = sizehint ? textRect->height() : h - pm.height();
+
+ if (opt->direction == Qt::RightToLeft) {
+ decoration.setRect(x, y, w - cw, pm.height());
+ display.setRect(x, y + pm.height(), w - cw, h);
+ } else {
+ decoration.setRect(x + cw, y, w - cw, pm.height());
+ display.setRect(x + cw, y + pm.height(), w - cw, h);
+ }
+ break; }
+ case QStyleOptionViewItem::Bottom: {
+ if (hasText)
+ textRect->setHeight(textRect->height() + textMargin); // add space
+ h = sizehint ? textRect->height() + pm.height() : h;
+
+ if (opt->direction == Qt::RightToLeft) {
+ display.setRect(x, y, w - cw, textRect->height());
+ decoration.setRect(x, y + textRect->height(), w - cw, h - textRect->height());
+ } else {
+ display.setRect(x + cw, y, w - cw, textRect->height());
+ decoration.setRect(x + cw, y + textRect->height(), w - cw, h - textRect->height());
+ }
+ break; }
+ case QStyleOptionViewItem::Left: {
+ if (opt->direction == Qt::LeftToRight) {
+ decoration.setRect(x + cw, y, pm.width(), h);
+ display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
+ } else {
+ display.setRect(x, y, w - pm.width() - cw, h);
+ decoration.setRect(display.right() + 1, y, pm.width(), h);
+ }
+ break; }
+ case QStyleOptionViewItem::Right: {
+ if (opt->direction == Qt::LeftToRight) {
+ display.setRect(x + cw, y, w - pm.width() - cw, h);
+ decoration.setRect(display.right() + 1, y, pm.width(), h);
+ } else {
+ decoration.setRect(x, y, pm.width(), h);
+ display.setRect(decoration.right() + 1, y, w - pm.width() - cw, h);
+ }
+ break; }
+ default:
+ qWarning("doLayout: decoration position is invalid");
+ decoration = *pixmapRect;
+ break;
+ }
+
+ if (!sizehint) { // we only need to do the internal layout if we are going to paint
+ *checkRect = QStyle::alignedRect(opt->direction, Qt::AlignCenter,
+ checkRect->size(), check);
+ *pixmapRect = QStyle::alignedRect(opt->direction, opt->decorationAlignment,
+ pixmapRect->size(), decoration);
+ // the text takes up all available space, unless the decoration is not shown as selected
+ if (opt->showDecorationSelected)
+ *textRect = display;
+ else
+ *textRect = QStyle::alignedRect(opt->direction, opt->displayAlignment,
+ textRect->size().boundedTo(display.size()), display);
+ } else {
+ *checkRect = check;
+ *pixmapRect = decoration;
+ *textRect = display;
+ }
+}
+
+QString QCommonStylePrivate::toolButtonElideText(const QStyleOptionToolButton *option,
+ const QRect &textRect, int flags) const
+{
+ if (option->fontMetrics.horizontalAdvance(option->text) <= textRect.width())
+ return option->text;
+
+ QString text = option->text;
+ text.replace(QLatin1Char('\n'), QChar::LineSeparator);
+ QTextOption textOption;
+ textOption.setWrapMode(QTextOption::ManualWrap);
+ textOption.setTextDirection(option->direction);
+
+ return calculateElidedText(text, textOption,
+ option->font, textRect, Qt::AlignTop,
+ Qt::ElideMiddle, flags,
+ false, nullptr);
+}
+
+/*! \internal
+ Compute the textRect and the pixmapRect from the opt rect
+
+ Uses the same computation than in QTabBar::tabSizeHint
+ */
+void QCommonStylePrivate::tabLayout(const QStyleOptionTab *opt, QRect *textRect, QRect *iconRect) const
+{
+ Q_ASSERT(textRect);
+ Q_ASSERT(iconRect);
+ QRect tr = opt->rect;
+ bool verticalTabs = opt->shape == QStyleOptionTab::RoundedEast
+ || opt->shape == QStyleOptionTab::RoundedWest
+ || opt->shape == QStyleOptionTab::TriangularEast
+ || opt->shape == QStyleOptionTab::TriangularWest;
+ if (verticalTabs)
+ tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
+
+ int verticalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt);
+ int horizontalShift = proxyStyle->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt);
+ int hpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2;
+ int vpadding = proxyStyle->pixelMetric(QStyle::PM_TabBarTabVSpace, opt) / 2;
+ if (opt->shape == QStyleOptionTab::RoundedSouth || opt->shape == QStyleOptionTab::TriangularSouth)
+ verticalShift = -verticalShift;
+ tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
+ bool selected = opt->state & QStyle::State_Selected;
+ if (selected) {
+ tr.setTop(tr.top() - verticalShift);
+ tr.setRight(tr.right() - horizontalShift);
+ }
+
+ // left widget
+ if (!opt->leftButtonSize.isEmpty()) {
+ tr.setLeft(tr.left() + 4 +
+ (verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width()));
+ }
+ // right widget
+ if (!opt->rightButtonSize.isEmpty()) {
+ tr.setRight(tr.right() - 4 -
+ (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
+ }
+
+ // icon
+ if (!opt->icon.isNull()) {
+ QSize iconSize = opt->iconSize;
+ if (!iconSize.isValid()) {
+ int iconExtent = proxyStyle->pixelMetric(QStyle::PM_SmallIconSize);
+ iconSize = QSize(iconExtent, iconExtent);
+ }
+ QSize tabIconSize = opt->icon.actualSize(iconSize,
+ (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
+ (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
+ // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
+ tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
+
+ const int offsetX = (iconSize.width() - tabIconSize.width()) / 2;
+ *iconRect = QRect(tr.left() + offsetX, tr.center().y() - tabIconSize.height() / 2,
+ tabIconSize.width(), tabIconSize.height());
+ if (!verticalTabs)
+ *iconRect = QStyle::visualRect(opt->direction, opt->rect, *iconRect);
+ tr.setLeft(tr.left() + tabIconSize.width() + 4);
+ }
+
+ if (!verticalTabs)
+ tr = QStyle::visualRect(opt->direction, opt->rect, tr);
+
+ *textRect = tr;
+}
+
+/*!
+ \reimp
+*/
+void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt, QPainter *p) const
+{
+ Q_D(const QCommonStyle);
+
+ // TODO: Set opt->window manually for now before calling any of the drawing functions. opt->window is
+ // pulled of the widget is QStyle. But now that we have no widget, we need some other
+ // solution.
+ Q_ASSERT(opt->window);
+
+ switch (element) {
+
+ case CE_PushButton:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ proxy()->drawControl(CE_PushButtonBevel, btn, p);
+ QStyleOptionButton subopt = *btn;
+ subopt.rect = subElementRect(SE_PushButtonContents, btn);
+ proxy()->drawControl(CE_PushButtonLabel, &subopt, p);
+ }
+ break;
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ QRect br = btn->rect;
+ int dbi = proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn);
+ if (btn->features & QStyleOptionButton::DefaultButton)
+ proxy()->drawPrimitive(PE_FrameDefaultButton, opt, p);
+ if (btn->features & QStyleOptionButton::AutoDefaultButton)
+ br.setCoords(br.left() + dbi, br.top() + dbi, br.right() - dbi, br.bottom() - dbi);
+ if (!(btn->features & (QStyleOptionButton::Flat | QStyleOptionButton::CommandLinkButton))
+ || btn->state & (State_Sunken | State_On)
+ || (btn->features & QStyleOptionButton::CommandLinkButton && btn->state & State_MouseOver)) {
+ QStyleOptionButton tmpBtn = *btn;
+ tmpBtn.rect = br;
+ proxy()->drawPrimitive(PE_PanelButtonCommand, &tmpBtn, p);
+ }
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, btn);
+ QRect ir = btn->rect;
+ QStyleOptionButton newBtn = *btn;
+ newBtn.rect = QRect(ir.right() - mbi + 2, ir.height()/2 - mbi/2 + 3, mbi - 6, mbi - 6);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p);
+ }
+ if (btn->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*btn);
+ fropt.rect = subElementRect(SE_PushButtonFocusRect, btn);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ break;
+ case CE_PushButtonLabel:
+ if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ QRect textRect = button->rect;
+ uint tf = Qt::AlignVCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, button))
+ tf |= Qt::TextHideMnemonic;
+
+ if (!button->icon.isNull()) {
+ //Center both icon and text
+ QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled;
+ if (mode == QIcon::Normal && button->state & State_HasFocus)
+ mode = QIcon::Active;
+ QIcon::State state = QIcon::Off;
+ if (button->state & State_On)
+ state = QIcon::On;
+
+ QPixmap pixmap = button->icon.pixmap(button->iconSize, dpr(opt->window), mode, state);
+ int pixmapWidth = pixmap.width() / pixmap.devicePixelRatio();
+ int pixmapHeight = pixmap.height() / pixmap.devicePixelRatio();
+ int labelWidth = pixmapWidth;
+ int labelHeight = pixmapHeight;
+ int iconSpacing = 4;//### 4 is currently hardcoded in QPushButton::sizeHint()
+ if (!button->text.isEmpty()) {
+ int textWidth = button->fontMetrics.boundingRect(opt->rect, tf, button->text).width();
+ labelWidth += (textWidth + iconSpacing);
+ }
+
+ QRect iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2,
+ textRect.y() + (textRect.height() - labelHeight) / 2,
+ pixmapWidth, pixmapHeight);
+
+ iconRect = visualRect(button->direction, textRect, iconRect);
+
+ if (button->direction == Qt::RightToLeft) {
+ tf |= Qt::AlignRight;
+ textRect.setRight(iconRect.left() - iconSpacing);
+ } else {
+ tf |= Qt::AlignLeft; //left align, we adjust the text-rect instead
+ textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing);
+ }
+
+ if (button->state & (State_On | State_Sunken))
+ iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, opt));
+ p->drawPixmap(iconRect, pixmap);
+ } else {
+ tf |= Qt::AlignHCenter;
+ }
+ if (button->state & (State_On | State_Sunken))
+ textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, opt),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, opt));
+
+ if (button->features & QStyleOptionButton::HasMenu) {
+ int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button);
+ if (button->direction == Qt::LeftToRight)
+ textRect = textRect.adjusted(0, 0, -indicatorSize, 0);
+ else
+ textRect = textRect.adjusted(indicatorSize, 0, 0, 0);
+ }
+ proxy()->drawItemText(p, textRect, tf, button->palette, (button->state & State_Enabled),
+ button->text, QPalette::ButtonText);
+ }
+ break;
+ case CE_RadioButton:
+ case CE_CheckBox:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ bool isRadio = (element == CE_RadioButton);
+ QStyleOptionButton subopt = *btn;
+ subopt.rect = subElementRect(isRadio ? SE_RadioButtonIndicator
+ : SE_CheckBoxIndicator, btn);
+ proxy()->drawPrimitive(isRadio ? PE_IndicatorRadioButton : PE_IndicatorCheckBox,
+ &subopt, p);
+ subopt.rect = subElementRect(isRadio ? SE_RadioButtonContents
+ : SE_CheckBoxContents, btn);
+ proxy()->drawControl(isRadio ? CE_RadioButtonLabel : CE_CheckBoxLabel, &subopt, p);
+ if (btn->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*btn);
+ fropt.rect = subElementRect(isRadio ? SE_RadioButtonFocusRect
+ : SE_CheckBoxFocusRect, btn);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ break;
+ case CE_RadioButtonLabel:
+ case CE_CheckBoxLabel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ uint alignment = visualAlignment(btn->direction, Qt::AlignLeft | Qt::AlignVCenter);
+
+ if (!proxy()->styleHint(SH_UnderlineShortcut, btn))
+ alignment |= Qt::TextHideMnemonic;
+ QPixmap pix;
+ QRect textRect = btn->rect;
+ if (!btn->icon.isNull()) {
+ pix = btn->icon.pixmap(btn->iconSize, dpr(opt->window), btn->state & State_Enabled ? QIcon::Normal : QIcon::Disabled);
+ proxy()->drawItemPixmap(p, btn->rect, alignment, pix);
+ if (btn->direction == Qt::RightToLeft)
+ textRect.setRight(textRect.right() - btn->iconSize.width() - 4);
+ else
+ textRect.setLeft(textRect.left() + btn->iconSize.width() + 4);
+ }
+ if (!btn->text.isEmpty()){
+ proxy()->drawItemText(p, textRect, alignment | Qt::TextShowMnemonic,
+ btn->palette, btn->state & State_Enabled, btn->text, QPalette::WindowText);
+ }
+ }
+ break;
+ case CE_MenuScroller: {
+ QStyleOption arrowOpt = *opt;
+ arrowOpt.state |= State_Enabled;
+ proxy()->drawPrimitive(((opt->state & State_DownArrow) ? PE_IndicatorArrowDown : PE_IndicatorArrowUp), &arrowOpt, p);
+ break; }
+ case CE_MenuTearoff:
+ if (opt->state & State_Selected)
+ p->fillRect(opt->rect, opt->palette.brush(QPalette::Highlight));
+ else
+ p->fillRect(opt->rect, opt->palette.brush(QPalette::Button));
+ p->setPen(QPen(opt->palette.dark().color(), 1, Qt::DashLine));
+ p->drawLine(opt->rect.x() + 2, opt->rect.y() + opt->rect.height() / 2 - 1,
+ opt->rect.x() + opt->rect.width() - 4,
+ opt->rect.y() + opt->rect.height() / 2 - 1);
+ p->setPen(QPen(opt->palette.light().color(), 1, Qt::DashLine));
+ p->drawLine(opt->rect.x() + 2, opt->rect.y() + opt->rect.height() / 2,
+ opt->rect.x() + opt->rect.width() - 4, opt->rect.y() + opt->rect.height() / 2);
+ break;
+ case CE_MenuBarItem:
+ if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip
+ | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, mbi))
+ alignment |= Qt::TextHideMnemonic;
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ QPixmap pix = mbi->icon.pixmap(QSize(iconExtent, iconExtent), dpr(opt->window),
+ mbi->state.testFlag(State_Enabled) ? QIcon::Normal : QIcon::Disabled);
+ if (!pix.isNull())
+ proxy()->drawItemPixmap(p,mbi->rect, alignment, pix);
+ else
+ proxy()->drawItemText(p, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled,
+ mbi->text, QPalette::ButtonText);
+ }
+ break;
+ case CE_MenuBarEmptyArea:
+ break;
+ case CE_ProgressBar:
+ if (const QStyleOptionProgressBar *pb
+ = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ QStyleOptionProgressBar subopt = *pb;
+ subopt.rect = subElementRect(SE_ProgressBarGroove, pb);
+ proxy()->drawControl(CE_ProgressBarGroove, &subopt, p);
+ subopt.rect = subElementRect(SE_ProgressBarContents, pb);
+ proxy()->drawControl(CE_ProgressBarContents, &subopt, p);
+ if (pb->textVisible) {
+ subopt.rect = subElementRect(SE_ProgressBarLabel, pb);
+ proxy()->drawControl(CE_ProgressBarLabel, &subopt, p);
+ }
+ }
+ break;
+ case CE_ProgressBarGroove:
+ if (opt->rect.isValid())
+ qDrawShadePanel(p, opt->rect, opt->palette, true, 1,
+ &opt->palette.brush(QPalette::Window));
+ break;
+ case CE_ProgressBarLabel:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ QPalette::ColorRole textRole = QPalette::NoRole;
+ if ((pb->textAlignment & Qt::AlignCenter) && pb->textVisible
+ && ((qint64(pb->progress) - qint64(pb->minimum)) * 2 >= (qint64(pb->maximum) - qint64(pb->minimum)))) {
+ textRole = QPalette::HighlightedText;
+ //Draw text shadow, This will increase readability when the background of same color
+ QRect shadowRect(pb->rect);
+ shadowRect.translate(1,1);
+ QColor shadowColor = (pb->palette.color(textRole).value() <= 128)
+ ? QColor(255,255,255,160) : QColor(0,0,0,160);
+ QPalette shadowPalette = pb->palette;
+ shadowPalette.setColor(textRole, shadowColor);
+ proxy()->drawItemText(p, shadowRect, Qt::AlignCenter | Qt::TextSingleLine, shadowPalette,
+ pb->state & State_Enabled, pb->text, textRole);
+ }
+ proxy()->drawItemText(p, pb->rect, Qt::AlignCenter | Qt::TextSingleLine, pb->palette,
+ pb->state & State_Enabled, pb->text, textRole);
+ }
+ break;
+ case CE_ProgressBarContents:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+
+ QRect rect = pb->rect;
+ const bool inverted = pb->invertedAppearance;
+ qint64 minimum = qint64(pb->minimum);
+ qint64 maximum = qint64(pb->maximum);
+ qint64 progress = qint64(pb->progress);
+
+ QPalette pal2 = pb->palette;
+ // Correct the highlight color if it is the same as the background
+ if (pal2.highlight() == pal2.window())
+ pal2.setColor(QPalette::Highlight, pb->palette.color(QPalette::Active,
+ QPalette::Highlight));
+ bool reverse = pb->direction == Qt::RightToLeft;
+ if (inverted)
+ reverse = !reverse;
+ int w = rect.width();
+ if (pb->minimum == 0 && pb->maximum == 0) {
+ // draw busy indicator
+ int x = (progress - minimum) % (w * 2);
+ if (x > w)
+ x = 2 * w - x;
+ x = reverse ? rect.right() - x : x + rect.x();
+ p->setPen(QPen(pal2.highlight().color(), 4));
+ p->drawLine(x, rect.y(), x, rect.height());
+ } else {
+ const int unit_width = proxy()->pixelMetric(PM_ProgressBarChunkWidth, pb);
+ if (!unit_width)
+ return;
+
+ int u;
+ if (unit_width > 1)
+ u = ((rect.width() + unit_width) / unit_width);
+ else
+ u = w / unit_width;
+ qint64 p_v = progress - minimum;
+ qint64 t_s = (maximum - minimum) ? (maximum - minimum) : qint64(1);
+
+ if (u > 0 && p_v >= INT_MAX / u && t_s >= u) {
+ // scale down to something usable.
+ p_v /= u;
+ t_s /= u;
+ }
+
+ // nu < tnu, if last chunk is only a partial chunk
+ int tnu, nu;
+ tnu = nu = p_v * u / t_s;
+
+ if (nu * unit_width > w)
+ --nu;
+
+ // Draw nu units out of a possible u of unit_width
+ // width, each a rectangle bordered by background
+ // color, all in a sunken panel with a percentage text
+ // display at the end.
+ int x = 0;
+ int x0 = reverse ? rect.right() - ((unit_width > 1) ? unit_width : 0)
+ : rect.x();
+
+ QStyleOptionProgressBar pbBits = *pb;
+ pbBits.rect = rect;
+ pbBits.palette = pal2;
+ int myY = pbBits.rect.y();
+ int myHeight = pbBits.rect.height();
+ pbBits.state = State_Horizontal;
+ for (int i = 0; i < nu; ++i) {
+ pbBits.rect.setRect(x0 + x, myY, unit_width, myHeight);
+ proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p);
+ x += reverse ? -unit_width : unit_width;
+ }
+
+ // Draw the last partial chunk to fill up the
+ // progress bar entirely
+ if (nu < tnu) {
+ int pixels_left = w - (nu * unit_width);
+ int offset = reverse ? x0 + x + unit_width-pixels_left : x0 + x;
+ pbBits.rect.setRect(offset, myY, pixels_left, myHeight);
+ proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p);
+ }
+ }
+ }
+ break;
+ case CE_HeaderLabel:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ QRect rect = header->rect;
+ if (!header->icon.isNull()) {
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ QPixmap pixmap
+ = header->icon.pixmap(QSize(iconExtent, iconExtent), dpr(opt->window),
+ header->state.testFlag(State_Enabled) ? QIcon::Normal : QIcon::Disabled);
+ int pixw = pixmap.width() / pixmap.devicePixelRatio();
+
+ QRect aligned = alignedRect(header->direction, QFlag(header->iconAlignment), pixmap.size() / pixmap.devicePixelRatio(), rect);
+ QRect inter = aligned.intersected(rect);
+ p->drawPixmap(inter.x(), inter.y(), pixmap,
+ inter.x() - aligned.x(), inter.y() - aligned.y(),
+ aligned.width() * pixmap.devicePixelRatio(),
+ pixmap.height() * pixmap.devicePixelRatio());
+
+ const int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
+ if (header->direction == Qt::LeftToRight)
+ rect.setLeft(rect.left() + pixw + margin);
+ else
+ rect.setRight(rect.right() - pixw - margin);
+ }
+ if (header->state & QStyle::State_On) {
+ QFont fnt = p->font();
+ fnt.setBold(true);
+ p->setFont(fnt);
+ }
+ proxy()->drawItemText(p, rect, header->textAlignment, header->palette,
+ (header->state & State_Enabled), header->text, QPalette::ButtonText);
+ }
+ break;
+ case CE_ToolButtonLabel:
+ if (const QStyleOptionToolButton *toolbutton
+ = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+ QRect rect = toolbutton->rect;
+ int shiftX = 0;
+ int shiftY = 0;
+ if (toolbutton->state & (State_Sunken | State_On)) {
+ shiftX = proxy()->pixelMetric(PM_ButtonShiftHorizontal, toolbutton);
+ shiftY = proxy()->pixelMetric(PM_ButtonShiftVertical, toolbutton);
+ }
+ // Arrow type always overrules and is always shown
+ bool hasArrow = toolbutton->features & QStyleOptionToolButton::Arrow;
+ if (((!hasArrow && toolbutton->icon.isNull()) && !toolbutton->text.isEmpty())
+ || toolbutton->toolButtonStyle == Qt::ToolButtonTextOnly) {
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, opt))
+ alignment |= Qt::TextHideMnemonic;
+ rect.translate(shiftX, shiftY);
+ p->setFont(toolbutton->font);
+ proxy()->drawItemText(p, rect, alignment, toolbutton->palette,
+ opt->state & State_Enabled, toolbutton->text,
+ QPalette::ButtonText);
+ } else {
+ QPixmap pm;
+ QSize pmSize = toolbutton->iconSize;
+ if (!toolbutton->icon.isNull()) {
+ QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
+ QIcon::Mode mode;
+ if (!(toolbutton->state & State_Enabled))
+ mode = QIcon::Disabled;
+ else if ((opt->state & State_MouseOver) && (opt->state & State_AutoRaise))
+ mode = QIcon::Active;
+ else
+ mode = QIcon::Normal;
+ pm = toolbutton->icon.pixmap(toolbutton->rect.size().boundedTo(toolbutton->iconSize),
+ dpr(opt->window), mode, state);
+ pmSize = pm.size() / pm.devicePixelRatio();
+ }
+
+ if (toolbutton->toolButtonStyle != Qt::ToolButtonIconOnly) {
+ p->setFont(toolbutton->font);
+ QRect pr = rect,
+ tr = rect;
+ int alignment = Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, opt))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (toolbutton->toolButtonStyle == Qt::ToolButtonTextUnderIcon) {
+ pr.setHeight(pmSize.height() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(0, pr.height() - 1, 0, -1);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(p, pr, Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, p);
+ }
+ alignment |= Qt::AlignCenter;
+ } else {
+ pr.setWidth(pmSize.width() + 4); //### 4 is currently hardcoded in QToolButton::sizeHint()
+ tr.adjust(pr.width(), 0, 0, 0);
+ pr.translate(shiftX, shiftY);
+ if (!hasArrow) {
+ proxy()->drawItemPixmap(p, QStyle::visualRect(opt->direction, rect, pr), Qt::AlignCenter, pm);
+ } else {
+ drawArrow(proxy(), toolbutton, pr, p);
+ }
+ alignment |= Qt::AlignLeft | Qt::AlignVCenter;
+ }
+ tr.translate(shiftX, shiftY);
+ const QString text = d->toolButtonElideText(toolbutton, tr, alignment);
+ proxy()->drawItemText(p, QStyle::visualRect(opt->direction, rect, tr), alignment, toolbutton->palette,
+ toolbutton->state & State_Enabled, text,
+ QPalette::ButtonText);
+ } else {
+ rect.translate(shiftX, shiftY);
+ if (hasArrow) {
+ drawArrow(proxy(), toolbutton, rect, p);
+ } else {
+ proxy()->drawItemPixmap(p, rect, Qt::AlignCenter, pm);
+ }
+ }
+ }
+ }
+ break;
+ case CE_ToolBoxTab:
+ if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
+ proxy()->drawControl(CE_ToolBoxTabShape, tb, p);
+ proxy()->drawControl(CE_ToolBoxTabLabel, tb, p);
+ }
+ break;
+ case CE_ToolBoxTabShape:
+ if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
+ p->setPen(tb->palette.mid().color().darker(150));
+ int d = 20 + tb->rect.height() - 3;
+ if (tb->direction != Qt::RightToLeft) {
+ const QPoint points[] = {
+ QPoint(-1, tb->rect.height() + 1),
+ QPoint(-1, 1),
+ QPoint(tb->rect.width() - d, 1),
+ QPoint(tb->rect.width() - 20, tb->rect.height() - 2),
+ QPoint(tb->rect.width() - 1, tb->rect.height() - 2),
+ QPoint(tb->rect.width() - 1, tb->rect.height() + 1),
+ QPoint(-1, tb->rect.height() + 1),
+ };
+ p->drawPolygon(points, sizeof points / sizeof *points);
+ } else {
+ const QPoint points[] = {
+ QPoint(tb->rect.width(), tb->rect.height() + 1),
+ QPoint(tb->rect.width(), 1),
+ QPoint(d - 1, 1),
+ QPoint(20 - 1, tb->rect.height() - 2),
+ QPoint(0, tb->rect.height() - 2),
+ QPoint(0, tb->rect.height() + 1),
+ QPoint(tb->rect.width(), tb->rect.height() + 1),
+ };
+ p->drawPolygon(points, sizeof points / sizeof *points);
+ }
+ p->setPen(tb->palette.light().color());
+ if (tb->direction != Qt::RightToLeft) {
+ p->drawLine(0, 2, tb->rect.width() - d, 2);
+ p->drawLine(tb->rect.width() - d - 1, 2, tb->rect.width() - 21, tb->rect.height() - 1);
+ p->drawLine(tb->rect.width() - 20, tb->rect.height() - 1,
+ tb->rect.width(), tb->rect.height() - 1);
+ } else {
+ p->drawLine(tb->rect.width() - 1, 2, d - 1, 2);
+ p->drawLine(d, 2, 20, tb->rect.height() - 1);
+ p->drawLine(19, tb->rect.height() - 1,
+ -1, tb->rect.height() - 1);
+ }
+ p->setBrush(Qt::NoBrush);
+ }
+ break;
+ case CE_TabBarTab:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ proxy()->drawControl(CE_TabBarTabShape, tab, p);
+ proxy()->drawControl(CE_TabBarTabLabel, tab, p);
+ }
+ break;
+ case CE_TabBarTabShape:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ p->save();
+
+ QRect rect(tab->rect);
+ bool selected = tab->state & State_Selected;
+ bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
+ int tabOverlap = onlyOne ? 0 : proxy()->pixelMetric(PM_TabBarTabOverlap, opt);
+
+ if (!selected) {
+ switch (tab->shape) {
+ case QStyleOptionTab::TriangularNorth:
+ rect.adjust(0, 0, 0, -tabOverlap);
+ if(!selected)
+ rect.adjust(1, 1, -1, 0);
+ break;
+ case QStyleOptionTab::TriangularSouth:
+ rect.adjust(0, tabOverlap, 0, 0);
+ if(!selected)
+ rect.adjust(1, 0, -1, -1);
+ break;
+ case QStyleOptionTab::TriangularEast:
+ rect.adjust(tabOverlap, 0, 0, 0);
+ if(!selected)
+ rect.adjust(0, 1, -1, -1);
+ break;
+ case QStyleOptionTab::TriangularWest:
+ rect.adjust(0, 0, -tabOverlap, 0);
+ if(!selected)
+ rect.adjust(1, 1, 0, -1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ p->setPen(QPen(tab->palette.windowText(), 0));
+ if (selected) {
+ p->setBrush(tab->palette.base());
+ } else {
+ p->setBrush(tab->palette.window());
+ }
+
+ int y;
+ int x;
+ QPolygon a(10);
+ switch (tab->shape) {
+ case QStyleOptionTab::TriangularNorth:
+ case QStyleOptionTab::TriangularSouth: {
+ a.setPoint(0, 0, -1);
+ a.setPoint(1, 0, 0);
+ y = rect.height() - 2;
+ x = y / 3;
+ a.setPoint(2, x++, y - 1);
+ ++x;
+ a.setPoint(3, x++, y++);
+ a.setPoint(4, x, y);
+
+ int i;
+ int right = rect.width() - 1;
+ for (i = 0; i < 5; ++i)
+ a.setPoint(9 - i, right - a.point(i).x(), a.point(i).y());
+ if (tab->shape == QStyleOptionTab::TriangularNorth)
+ for (i = 0; i < 10; ++i)
+ a.setPoint(i, a.point(i).x(), rect.height() - 1 - a.point(i).y());
+
+ a.translate(rect.left(), rect.top());
+ p->setRenderHint(QPainter::Antialiasing);
+ p->translate(0, 0.5);
+
+ QPainterPath path;
+ path.addPolygon(a);
+ p->drawPath(path);
+ break; }
+ case QStyleOptionTab::TriangularEast:
+ case QStyleOptionTab::TriangularWest: {
+ a.setPoint(0, -1, 0);
+ a.setPoint(1, 0, 0);
+ x = rect.width() - 2;
+ y = x / 3;
+ a.setPoint(2, x - 1, y++);
+ ++y;
+ a.setPoint(3, x++, y++);
+ a.setPoint(4, x, y);
+ int i;
+ int bottom = rect.height() - 1;
+ for (i = 0; i < 5; ++i)
+ a.setPoint(9 - i, a.point(i).x(), bottom - a.point(i).y());
+ if (tab->shape == QStyleOptionTab::TriangularWest)
+ for (i = 0; i < 10; ++i)
+ a.setPoint(i, rect.width() - 1 - a.point(i).x(), a.point(i).y());
+ a.translate(rect.left(), rect.top());
+ p->setRenderHint(QPainter::Antialiasing);
+ p->translate(0.5, 0);
+ QPainterPath path;
+ path.addPolygon(a);
+ p->drawPath(path);
+ break; }
+ default:
+ break;
+ }
+ p->restore();
+ }
+ break;
+ case CE_ToolBoxTabLabel:
+ if (const QStyleOptionToolBox *tb = qstyleoption_cast<const QStyleOptionToolBox *>(opt)) {
+ bool enabled = tb->state & State_Enabled;
+ bool selected = tb->state & State_Selected;
+ int iconExtent = proxy()->pixelMetric(QStyle::PM_SmallIconSize, tb);
+ QPixmap pm = tb->icon.pixmap(QSize(iconExtent, iconExtent), dpr(opt->window),
+ enabled ? QIcon::Normal : QIcon::Disabled);
+
+ QRect cr = subElementRect(QStyle::SE_ToolBoxTabContents, tb);
+ QRect tr, ir;
+ int ih = 0;
+ if (pm.isNull()) {
+ tr = cr;
+ tr.adjust(4, 0, -8, 0);
+ } else {
+ int iw = pm.width() / pm.devicePixelRatio() + 4;
+ ih = pm.height()/ pm.devicePixelRatio();
+ ir = QRect(cr.left() + 4, cr.top(), iw + 2, ih);
+ tr = QRect(ir.right(), cr.top(), cr.width() - ir.right() - 4, cr.height());
+ }
+
+ if (selected && proxy()->styleHint(QStyle::SH_ToolBox_SelectedPageTitleBold, tb)) {
+ QFont f(p->font());
+ f.setBold(true);
+ p->setFont(f);
+ }
+
+ QString txt = tb->fontMetrics.elidedText(tb->text, Qt::ElideRight, tr.width());
+
+ if (ih)
+ p->drawPixmap(ir.left(), (tb->rect.height() - ih) / 2, pm);
+
+ int alignment = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(QStyle::SH_UnderlineShortcut, tb))
+ alignment |= Qt::TextHideMnemonic;
+ proxy()->drawItemText(p, tr, alignment, tb->palette, enabled, txt, QPalette::ButtonText);
+
+ if (!txt.isEmpty() && opt->state & State_HasFocus) {
+ QStyleOptionFocusRect opt;
+ opt.rect = tr;
+ opt.palette = tb->palette;
+ opt.state = QStyle::State_None;
+ proxy()->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, p);
+ }
+ }
+ break;
+ case CE_TabBarTabLabel:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ QRect tr = tab->rect;
+ bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
+ || tab->shape == QStyleOptionTab::RoundedWest
+ || tab->shape == QStyleOptionTab::TriangularEast
+ || tab->shape == QStyleOptionTab::TriangularWest;
+
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, opt))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (verticalTabs) {
+ p->save();
+ int newX, newY, newRot;
+ if (tab->shape == QStyleOptionTab::RoundedEast || tab->shape == QStyleOptionTab::TriangularEast) {
+ newX = tr.width() + tr.x();
+ newY = tr.y();
+ newRot = 90;
+ } else {
+ newX = tr.x();
+ newY = tr.y() + tr.height();
+ newRot = -90;
+ }
+ QTransform m = QTransform::fromTranslate(newX, newY);
+ m.rotate(newRot);
+ p->setTransform(m, true);
+ }
+ QRect iconRect;
+ d->tabLayout(tab, &tr, &iconRect);
+ tr = proxy()->subElementRect(SE_TabBarTabText, opt); //we compute tr twice because the style may override subElementRect
+
+ if (!tab->icon.isNull()) {
+ QPixmap tabIcon = tab->icon.pixmap(tab->iconSize, dpr(opt->window),
+ (tab->state & State_Enabled) ? QIcon::Normal
+ : QIcon::Disabled,
+ (tab->state & State_Selected) ? QIcon::On
+ : QIcon::Off);
+ p->drawPixmap(iconRect.x(), iconRect.y(), tabIcon);
+ }
+
+ proxy()->drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text, QPalette::WindowText);
+ if (verticalTabs)
+ p->restore();
+
+ if (tab->state & State_HasFocus) {
+ const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth);
+
+ int x1, x2;
+ x1 = tab->rect.left();
+ x2 = tab->rect.right() - 1;
+
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*tab);
+ fropt.rect.setRect(x1 + 1 + OFFSET, tab->rect.y() + OFFSET,
+ x2 - x1 - 2*OFFSET, tab->rect.height() - 2*OFFSET);
+ drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ break;
+ case CE_SizeGrip: {
+ p->save();
+ int x, y, w, h;
+ opt->rect.getRect(&x, &y, &w, &h);
+
+ int sw = qMin(h, w);
+ if (h > w)
+ p->translate(0, h - w);
+ else
+ p->translate(w - h, 0);
+
+ int sx = x;
+ int sy = y;
+ int s = sw / 3;
+
+ Qt::Corner corner;
+ if (const QStyleOptionSizeGrip *sgOpt = qstyleoption_cast<const QStyleOptionSizeGrip *>(opt))
+ corner = sgOpt->corner;
+ else if (opt->direction == Qt::RightToLeft)
+ corner = Qt::BottomLeftCorner;
+ else
+ corner = Qt::BottomRightCorner;
+
+ if (corner == Qt::BottomLeftCorner) {
+ sx = x + sw;
+ for (int i = 0; i < 4; ++i) {
+ p->setPen(QPen(opt->palette.light().color(), 1));
+ p->drawLine(x, sy - 1 , sx + 1, sw);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(x, sy, sx, sw);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(x, sy + 1, sx - 1, sw);
+ sx -= s;
+ sy += s;
+ }
+ } else if (corner == Qt::BottomRightCorner) {
+ for (int i = 0; i < 4; ++i) {
+ p->setPen(QPen(opt->palette.light().color(), 1));
+ p->drawLine(sx - 1, sw, sw, sy - 1);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(sx, sw, sw, sy);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(sx + 1, sw, sw, sy + 1);
+ sx += s;
+ sy += s;
+ }
+ } else if (corner == Qt::TopRightCorner) {
+ sy = y + sw;
+ for (int i = 0; i < 4; ++i) {
+ p->setPen(QPen(opt->palette.light().color(), 1));
+ p->drawLine(sx - 1, y, sw, sy + 1);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(sx, y, sw, sy);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(sx + 1, y, sw, sy - 1);
+ sx += s;
+ sy -= s;
+ }
+ } else if (corner == Qt::TopLeftCorner) {
+ for (int i = 0; i < 4; ++i) {
+ p->setPen(QPen(opt->palette.light().color(), 1));
+ p->drawLine(x, sy - 1, sx - 1, y);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(x, sy, sx, y);
+ p->setPen(QPen(opt->palette.dark().color(), 1));
+ p->drawLine(x, sy + 1, sx + 1, y);
+ sx += s;
+ sy += s;
+ }
+ }
+ p->restore();
+ break; }
+ case CE_RubberBand: {
+ if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
+ QPixmap tiledPixmap(16, 16);
+ QPainter pixmapPainter(&tiledPixmap);
+ pixmapPainter.setPen(Qt::NoPen);
+ pixmapPainter.setBrush(Qt::Dense4Pattern);
+ pixmapPainter.setBackground(QBrush(opt->palette.base()));
+ pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
+ pixmapPainter.drawRect(0, 0, tiledPixmap.width(), tiledPixmap.height());
+ pixmapPainter.end();
+ // ### workaround for borked XRENDER
+ tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage());
+
+ p->save();
+ QRect r = opt->rect;
+ QStyleHintReturnMask mask;
+ if (proxy()->styleHint(QStyle::SH_RubberBand_Mask, opt, &mask))
+ p->setClipRegion(mask.region);
+ p->drawTiledPixmap(r.x(), r.y(), r.width(), r.height(), tiledPixmap);
+ p->setPen(opt->palette.color(QPalette::Active, QPalette::WindowText));
+ p->setBrush(Qt::NoBrush);
+ p->drawRect(r.adjusted(0, 0, -1, -1));
+ if (rbOpt->shape == QStyleOptionRubberBand::Rectangle)
+ p->drawRect(r.adjusted(3, 3, -4, -4));
+ p->restore();
+ }
+ break; }
+ case CE_DockWidgetTitle:
+ if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
+ QRect r = dwOpt->rect.adjusted(0, 0, -1, -1);
+ if (dwOpt->movable) {
+ p->setPen(dwOpt->palette.color(QPalette::Dark));
+ p->drawRect(r);
+ }
+
+ if (!dwOpt->title.isEmpty()) {
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ if (verticalTitleBar) {
+ r = r.transposed();
+
+ p->save();
+ p->translate(r.left(), r.top() + r.width());
+ p->rotate(-90);
+ p->translate(-r.left(), -r.top());
+ }
+
+ const int indent = p->fontMetrics().descent();
+ proxy()->drawItemText(p, r.adjusted(indent + 1, 1, -indent - 1, -1),
+ Qt::AlignLeft | Qt::AlignVCenter, dwOpt->palette,
+ dwOpt->state & State_Enabled, dwOpt->title,
+ QPalette::WindowText);
+
+ if (verticalTitleBar)
+ p->restore();
+ }
+ }
+ break;
+ case CE_Header:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ QRegion clipRegion = p->clipRegion();
+ p->setClipRect(opt->rect);
+ proxy()->drawControl(CE_HeaderSection, header, p);
+ QStyleOptionHeader subopt = *header;
+ subopt.rect = subElementRect(SE_HeaderLabel, header);
+ if (subopt.rect.isValid())
+ proxy()->drawControl(CE_HeaderLabel, &subopt, p);
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ subopt.rect = subElementRect(SE_HeaderArrow, opt);
+ proxy()->drawPrimitive(PE_IndicatorHeaderArrow, &subopt, p);
+ }
+ p->setClipRegion(clipRegion);
+ }
+ break;
+ case CE_FocusFrame:
+ p->fillRect(opt->rect, opt->palette.windowText());
+ break;
+ case CE_HeaderSection:
+ qDrawShadePanel(p, opt->rect, opt->palette,
+ opt->state & State_Sunken, 1,
+ &opt->palette.brush(QPalette::Button));
+ break;
+ case CE_HeaderEmptyArea:
+ p->fillRect(opt->rect, opt->palette.window());
+ break;
+ case CE_ComboBoxLabel:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField);
+ p->save();
+ p->setClipRect(editRect);
+ if (!cb->currentIcon.isNull()) {
+ QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal
+ : QIcon::Disabled;
+ QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, dpr(opt->window), mode);
+ QRect iconRect(editRect);
+ iconRect.setWidth(cb->iconSize.width() + 4);
+ iconRect = alignedRect(cb->direction,
+ Qt::AlignLeft | Qt::AlignVCenter,
+ iconRect.size(), editRect);
+ if (cb->editable)
+ p->fillRect(iconRect, opt->palette.brush(QPalette::Base));
+ proxy()->drawItemPixmap(p, iconRect, Qt::AlignCenter, pixmap);
+
+ if (cb->direction == Qt::RightToLeft)
+ editRect.translate(-4 - cb->iconSize.width(), 0);
+ else
+ editRect.translate(cb->iconSize.width() + 4, 0);
+ }
+ if (!cb->currentText.isEmpty() && !cb->editable) {
+ proxy()->drawItemText(p, editRect.adjusted(1, 0, -1, 0),
+ visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter),
+ cb->palette, cb->state & State_Enabled, cb->currentText);
+ }
+ p->restore();
+ }
+ break;
+ case CE_ToolBar:
+ if (const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
+ // Compatibility with styles that use PE_PanelToolBar
+ QStyleOptionFrame frame;
+ frame.QStyleOption::operator=(*toolBar);
+ frame.lineWidth = toolBar->lineWidth;
+ frame.midLineWidth = toolBar->midLineWidth;
+ proxy()->drawPrimitive(PE_PanelToolBar, opt, p);
+
+ qDrawShadePanel(p, toolBar->rect, toolBar->palette, false, toolBar->lineWidth,
+ &toolBar->palette.brush(QPalette::Button));
+ }
+ break;
+ case CE_ColumnViewGrip: {
+ // draw background gradients
+ QLinearGradient g(0, 0, opt->rect.width(), 0);
+ g.setColorAt(0, opt->palette.color(QPalette::Active, QPalette::Mid));
+ g.setColorAt(0.5, Qt::white);
+ p->fillRect(QRect(0, 0, opt->rect.width(), opt->rect.height()), g);
+
+ // draw the two lines
+ QPen pen(p->pen());
+ pen.setWidth(opt->rect.width()/20);
+ pen.setColor(opt->palette.color(QPalette::Active, QPalette::Dark));
+ p->setPen(pen);
+
+ int line1starting = opt->rect.width()*8 / 20;
+ int line2starting = opt->rect.width()*13 / 20;
+ int top = opt->rect.height()*20/75;
+ int bottom = opt->rect.height() - 1 - top;
+ p->drawLine(line1starting, top, line1starting, bottom);
+ p->drawLine(line2starting, top, line2starting, bottom);
+ }
+ break;
+ case CE_ItemViewItem:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ p->save();
+ p->setClipRect(opt->rect);
+
+ QRect checkRect = proxy()->subElementRect(SE_ItemViewItemCheckIndicator, vopt);
+ QRect iconRect = proxy()->subElementRect(SE_ItemViewItemDecoration, vopt);
+ QRect textRect = proxy()->subElementRect(SE_ItemViewItemText, vopt);
+
+ // draw the background
+ proxy()->drawPrimitive(PE_PanelItemViewItem, opt, p);
+
+ // draw the check mark
+ if (vopt->features & QStyleOptionViewItem::HasCheckIndicator) {
+ QStyleOptionViewItem option(*vopt);
+ option.rect = checkRect;
+ option.state = option.state & ~QStyle::State_HasFocus;
+
+ switch (vopt->checkState) {
+ case Qt::Unchecked:
+ option.state |= QStyle::State_Off;
+ break;
+ case Qt::PartiallyChecked:
+ option.state |= QStyle::State_NoChange;
+ break;
+ case Qt::Checked:
+ option.state |= QStyle::State_On;
+ break;
+ }
+ proxy()->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &option, p);
+ }
+
+ // draw the icon
+ QIcon::Mode mode = QIcon::Normal;
+ if (!(vopt->state & QStyle::State_Enabled))
+ mode = QIcon::Disabled;
+ else if (vopt->state & QStyle::State_Selected)
+ mode = QIcon::Selected;
+ QIcon::State state = vopt->state & QStyle::State_Open ? QIcon::On : QIcon::Off;
+ vopt->icon.paint(p, iconRect, vopt->decorationAlignment, mode, state);
+
+ // draw the text
+ if (!vopt->text.isEmpty()) {
+ QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
+ ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ if (vopt->state & QStyle::State_Selected) {
+ p->setPen(vopt->palette.color(cg, QPalette::HighlightedText));
+ } else {
+ p->setPen(vopt->palette.color(cg, QPalette::Text));
+ }
+ if (vopt->state & QStyle::State_Editing) {
+ p->setPen(vopt->palette.color(cg, QPalette::Text));
+ p->drawRect(textRect.adjusted(0, 0, -1, -1));
+ }
+
+ d->viewItemDrawText(p, vopt, textRect);
+ }
+
+ // draw the focus rect
+ if (vopt->state & QStyle::State_HasFocus) {
+ QStyleOptionFocusRect o;
+ o.QStyleOption::operator=(*vopt);
+ o.rect = proxy()->subElementRect(SE_ItemViewItemFocusRect, vopt);
+ o.state |= QStyle::State_KeyboardFocusChange;
+ o.state |= QStyle::State_Item;
+ QPalette::ColorGroup cg = (vopt->state & QStyle::State_Enabled)
+ ? QPalette::Normal : QPalette::Disabled;
+ o.backgroundColor = vopt->palette.color(cg, (vopt->state & QStyle::State_Selected)
+ ? QPalette::Highlight : QPalette::Window);
+ proxy()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, p);
+ }
+
+ p->restore();
+ }
+ break;
+ case CE_ShapedFrame:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ int frameShape = f->frameShape;
+ int frameShadow = QStyleOptionFrame::Plain;
+ if (f->state & QStyle::State_Sunken) {
+ frameShadow = QStyleOptionFrame::Sunken;
+ } else if (f->state & QStyle::State_Raised) {
+ frameShadow = QStyleOptionFrame::Raised;
+ }
+
+ int lw = f->lineWidth;
+ int mlw = f->midLineWidth;
+ QPalette::ColorRole foregroundRole = QPalette::WindowText;
+
+ switch (frameShape) {
+ case QStyleOptionFrame::Box:
+ if (frameShadow == QStyleOptionFrame::Plain) {
+ qDrawPlainRect(p, f->rect, f->palette.color(foregroundRole), lw);
+ } else {
+ qDrawShadeRect(p, f->rect, f->palette, frameShadow == QStyleOptionFrame::Sunken, lw, mlw);
+ }
+ break;
+ case QStyleOptionFrame::StyledPanel:
+ proxy()->drawPrimitive(QStyle::PE_Frame, opt, p);
+ break;
+ case QStyleOptionFrame::Panel:
+ if (frameShadow == QStyleOptionFrame::Plain) {
+ qDrawPlainRect(p, f->rect, f->palette.color(foregroundRole), lw);
+ } else {
+ qDrawShadePanel(p, f->rect, f->palette, frameShadow == QStyleOptionFrame::Sunken, lw);
+ }
+ break;
+ case QStyleOptionFrame::WinPanel:
+ if (frameShadow == QStyleOptionFrame::Plain) {
+ qDrawPlainRect(p, f->rect, f->palette.color(foregroundRole), lw);
+ } else {
+ qDrawWinPanel(p, f->rect, f->palette, frameShadow == QStyleOptionFrame::Sunken);
+ }
+ break;
+ case QStyleOptionFrame::HLine:
+ case QStyleOptionFrame::VLine: {
+ QPoint p1, p2;
+ if (frameShape == QStyleOptionFrame::HLine) {
+ p1 = QPoint(opt->rect.x(), opt->rect.y() + opt->rect.height() / 2);
+ p2 = QPoint(opt->rect.x() + opt->rect.width(), p1.y());
+ } else {
+ p1 = QPoint(opt->rect.x() + opt->rect.width() / 2, opt->rect.y());
+ p2 = QPoint(p1.x(), p1.y() + opt->rect.height());
+ }
+ if (frameShadow == QStyleOptionFrame::Plain) {
+ QPen oldPen = p->pen();
+ p->setPen(QPen(opt->palette.brush(foregroundRole), lw));
+ p->drawLine(p1, p2);
+ p->setPen(oldPen);
+ } else {
+ qDrawShadeLine(p, p1, p2, f->palette, frameShadow == QStyleOptionFrame::Sunken, lw, mlw);
+ }
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt) const
+{
+ Q_D(const QCommonStyle);
+ QRect r;
+ switch (sr) {
+ case SE_PushButtonContents:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ int dx1, dx2;
+ dx1 = proxy()->pixelMetric(PM_DefaultFrameWidth, btn);
+ if (btn->features & QStyleOptionButton::AutoDefaultButton)
+ dx1 += proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn);
+ dx2 = dx1 * 2;
+ r.setRect(opt->rect.x() + dx1, opt->rect.y() + dx1, opt->rect.width() - dx2,
+ opt->rect.height() - dx2);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_PushButtonFocusRect:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ int dbw1 = 0, dbw2 = 0;
+ if (btn->features & QStyleOptionButton::AutoDefaultButton){
+ dbw1 = proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn);
+ dbw2 = dbw1 * 2;
+ }
+
+ int dfw1 = proxy()->pixelMetric(PM_DefaultFrameWidth, btn) + 1,
+ dfw2 = dfw1 * 2;
+
+ r.setRect(btn->rect.x() + dfw1 + dbw1, btn->rect.y() + dfw1 + dbw1,
+ btn->rect.width() - dfw2 - dbw2, btn->rect.height()- dfw2 - dbw2);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_CheckBoxIndicator:
+ {
+ int h = proxy()->pixelMetric(PM_IndicatorHeight, opt);
+ r.setRect(opt->rect.x(), opt->rect.y() + ((opt->rect.height() - h) / 2),
+ proxy()->pixelMetric(PM_IndicatorWidth, opt), h);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+
+ case SE_CheckBoxContents:
+ {
+ // Deal with the logical first, then convert it back to screen coords.
+ QRect ir = visualRect(opt->direction, opt->rect,
+ subElementRect(SE_CheckBoxIndicator, opt));
+ int spacing = proxy()->pixelMetric(PM_CheckBoxLabelSpacing, opt);
+ r.setRect(ir.right() + spacing, opt->rect.y(), opt->rect.width() - ir.width() - spacing,
+ opt->rect.height());
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+
+ case SE_CheckBoxFocusRect:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ if (btn->icon.isNull() && btn->text.isEmpty()) {
+ r = subElementRect(SE_CheckBoxIndicator, opt);
+ r.adjust(1, 1, -1, -1);
+ break;
+ }
+ // As above, deal with the logical first, then convert it back to screen coords.
+ QRect cr = visualRect(btn->direction, btn->rect, subElementRect(SE_CheckBoxContents, btn));
+
+ QRect iconRect, textRect;
+ if (!btn->text.isEmpty()) {
+ textRect = itemTextRect(opt->fontMetrics, cr, Qt::AlignAbsolute | Qt::AlignLeft
+ | Qt::AlignVCenter | Qt::TextShowMnemonic,
+ btn->state & State_Enabled, btn->text);
+ }
+ if (!btn->icon.isNull()) {
+ iconRect = itemPixmapRect(cr, Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter
+ | Qt::TextShowMnemonic,
+ btn->icon.pixmap(btn->iconSize, dpr(opt->window), QIcon::Normal));
+ if (!textRect.isEmpty())
+ textRect.translate(iconRect.right() + 4, 0);
+ }
+ r = iconRect | textRect;
+ r.adjust(-3, -2, 3, 2);
+ r = r.intersected(btn->rect);
+ r = visualRect(btn->direction, btn->rect, r);
+ }
+ break;
+
+ case SE_RadioButtonIndicator:
+ {
+ int h = proxy()->pixelMetric(PM_ExclusiveIndicatorHeight, opt);
+ r.setRect(opt->rect.x(), opt->rect.y() + ((opt->rect.height() - h) / 2),
+ proxy()->pixelMetric(PM_ExclusiveIndicatorWidth, opt), h);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+
+ case SE_RadioButtonContents:
+ {
+ QRect ir = visualRect(opt->direction, opt->rect,
+ subElementRect(SE_RadioButtonIndicator, opt));
+ int spacing = proxy()->pixelMetric(PM_RadioButtonLabelSpacing, opt);
+ r.setRect(ir.left() + ir.width() + spacing, opt->rect.y(), opt->rect.width() - ir.width() - spacing,
+ opt->rect.height());
+ r = visualRect(opt->direction, opt->rect, r);
+ break;
+ }
+
+ case SE_RadioButtonFocusRect:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ if (btn->icon.isNull() && btn->text.isEmpty()) {
+ r = subElementRect(SE_RadioButtonIndicator, opt);
+ r.adjust(1, 1, -1, -1);
+ break;
+ }
+ QRect cr = visualRect(btn->direction, btn->rect, subElementRect(SE_RadioButtonContents, opt));
+
+ QRect iconRect, textRect;
+ if (!btn->text.isEmpty()){
+ textRect = itemTextRect(opt->fontMetrics, cr, Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter
+ | Qt::TextShowMnemonic, btn->state & State_Enabled, btn->text);
+ }
+ if (!btn->icon.isNull()) {
+ iconRect = itemPixmapRect(cr, Qt::AlignAbsolute | Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
+ btn->icon.pixmap(btn->iconSize, dpr(opt->window), QIcon::Normal));
+ if (!textRect.isEmpty())
+ textRect.translate(iconRect.right() + 4, 0);
+ }
+ r = iconRect | textRect;
+ r.adjust(-3, -2, 3, 2);
+ r = r.intersected(btn->rect);
+ r = visualRect(btn->direction, btn->rect, r);
+ }
+ break;
+ case SE_SliderFocusRect:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider);
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider);
+ if (slider->orientation == Qt::Horizontal)
+ r.setRect(0, tickOffset - 1, slider->rect.width(), thickness + 2);
+ else
+ r.setRect(tickOffset - 1, 0, thickness + 2, slider->rect.height());
+ r = r.intersected(slider->rect);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_ProgressBarGroove:
+ case SE_ProgressBarContents:
+ case SE_ProgressBarLabel:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ int textw = 0;
+ if (pb->textVisible)
+ textw = qMax(pb->fontMetrics.horizontalAdvance(pb->text), pb->fontMetrics.horizontalAdvance(QLatin1String("100%"))) + 6;
+
+ if ((pb->textAlignment & Qt::AlignCenter) == 0) {
+ if (sr != SE_ProgressBarLabel)
+ r.setCoords(pb->rect.left(), pb->rect.top(),
+ pb->rect.right() - textw, pb->rect.bottom());
+ else
+ r.setCoords(pb->rect.right() - textw, pb->rect.top(),
+ pb->rect.right(), pb->rect.bottom());
+ } else {
+ r = pb->rect;
+ }
+ r = visualRect(pb->direction, pb->rect, r);
+ }
+ break;
+ case SE_ComboBoxFocusRect:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ int margin = cb->frame ? 3 : 0;
+ r.setRect(opt->rect.left() + margin, opt->rect.top() + margin,
+ opt->rect.width() - 2*margin - 16, opt->rect.height() - 2*margin);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_ToolBoxTabContents:
+ r = opt->rect;
+ r.adjust(0, 0, -30, 0);
+ break;
+ case SE_HeaderLabel: {
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
+ r.setRect(opt->rect.x() + margin, opt->rect.y() + margin,
+ opt->rect.width() - margin * 2, opt->rect.height() - margin * 2);
+
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ // Subtract width needed for arrow, if there is one
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ if (opt->state & State_Horizontal)
+ r.setWidth(r.width() - (opt->rect.height() / 2) - (margin * 2));
+ else
+ r.setHeight(r.height() - (opt->rect.width() / 2) - (margin * 2));
+ }
+ }
+ r = visualRect(opt->direction, opt->rect, r);
+ break; }
+ case SE_HeaderArrow: {
+ int h = opt->rect.height();
+ int w = opt->rect.width();
+ int x = opt->rect.x();
+ int y = opt->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt);
+
+ if (opt->state & State_Horizontal) {
+ int horiz_size = h / 2;
+ r.setRect(x + w - margin * 2 - horiz_size, y + 5,
+ horiz_size, h - margin * 2 - 5);
+ } else {
+ int vert_size = w / 2;
+ r.setRect(x + 5, y + h - margin * 2 - vert_size,
+ w - margin * 2 - 5, vert_size);
+ }
+ r = visualRect(opt->direction, opt->rect, r);
+ break; }
+
+ case SE_RadioButtonClickRect:
+ r = subElementRect(SE_RadioButtonFocusRect, opt);
+ r |= subElementRect(SE_RadioButtonIndicator, opt);
+ break;
+ case SE_CheckBoxClickRect:
+ r = subElementRect(SE_CheckBoxFocusRect, opt);
+ r |= subElementRect(SE_CheckBoxIndicator, opt);
+ break;
+ case SE_TabWidgetTabBar:
+ if (const QStyleOptionTabWidgetFrame *twf
+ = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ r.setSize(twf->tabBarSize);
+ const uint alingMask = Qt::AlignLeft | Qt::AlignRight | Qt::AlignHCenter;
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ // Constrain the size now, otherwise, center could get off the page
+ // This of course repeated for all the other directions
+ r.setWidth(qMin(r.width(), twf->rect.width()
+ - twf->leftCornerWidgetSize.width()
+ - twf->rightCornerWidgetSize.width()));
+ switch (proxy()->styleHint(SH_TabBar_Alignment, twf) & alingMask) {
+ default:
+ case Qt::AlignLeft:
+ r.moveTopLeft(QPoint(twf->leftCornerWidgetSize.width(), 0));
+ break;
+ case Qt::AlignHCenter:
+ r.moveTopLeft(QPoint(twf->rect.center().x() - qRound(r.width() / 2.0f)
+ + (twf->leftCornerWidgetSize.width() / 2)
+ - (twf->rightCornerWidgetSize.width() / 2), 0));
+ break;
+ case Qt::AlignRight:
+ r.moveTopLeft(QPoint(twf->rect.width() - twf->tabBarSize.width()
+ - twf->rightCornerWidgetSize.width(), 0));
+ break;
+ }
+ r = visualRect(twf->direction, twf->rect, r);
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ r.setWidth(qMin(r.width(), twf->rect.width()
+ - twf->leftCornerWidgetSize.width()
+ - twf->rightCornerWidgetSize.width()));
+ switch (proxy()->styleHint(SH_TabBar_Alignment, twf) & alingMask) {
+ default:
+ case Qt::AlignLeft:
+ r.moveTopLeft(QPoint(twf->leftCornerWidgetSize.width(),
+ twf->rect.height() - twf->tabBarSize.height()));
+ break;
+ case Qt::AlignHCenter:
+ r.moveTopLeft(QPoint(twf->rect.center().x() - qRound(r.width() / 2.0f)
+ + (twf->leftCornerWidgetSize.width() / 2)
+ - (twf->rightCornerWidgetSize.width() / 2),
+ twf->rect.height() - twf->tabBarSize.height()));
+ break;
+ case Qt::AlignRight:
+ r.moveTopLeft(QPoint(twf->rect.width() - twf->tabBarSize.width()
+ - twf->rightCornerWidgetSize.width(),
+ twf->rect.height() - twf->tabBarSize.height()));
+ break;
+ }
+ r = visualRect(twf->direction, twf->rect, r);
+ break;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ r.setHeight(qMin(r.height(), twf->rect.height()
+ - twf->leftCornerWidgetSize.height()
+ - twf->rightCornerWidgetSize.height()));
+ switch (proxy()->styleHint(SH_TabBar_Alignment, twf) & alingMask) {
+ default:
+ case Qt::AlignLeft:
+ r.moveTopLeft(QPoint(twf->rect.width() - twf->tabBarSize.width(),
+ twf->leftCornerWidgetSize.height()));
+ break;
+ case Qt::AlignHCenter:
+ r.moveTopLeft(QPoint(twf->rect.width() - twf->tabBarSize.width(),
+ twf->rect.center().y() - r.height() / 2));
+ break;
+ case Qt::AlignRight:
+ r.moveTopLeft(QPoint(twf->rect.width() - twf->tabBarSize.width(),
+ twf->rect.height() - twf->tabBarSize.height()
+ - twf->rightCornerWidgetSize.height()));
+ break;
+ }
+ break;
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ r.setHeight(qMin(r.height(), twf->rect.height()
+ - twf->leftCornerWidgetSize.height()
+ - twf->rightCornerWidgetSize.height()));
+ switch (proxy()->styleHint(SH_TabBar_Alignment, twf) & alingMask) {
+ default:
+ case Qt::AlignLeft:
+ r.moveTopLeft(QPoint(0, twf->leftCornerWidgetSize.height()));
+ break;
+ case Qt::AlignHCenter:
+ r.moveTopLeft(QPoint(0, twf->rect.center().y() - r.height() / 2));
+ break;
+ case Qt::AlignRight:
+ r.moveTopLeft(QPoint(0, twf->rect.height() - twf->tabBarSize.height()
+ - twf->rightCornerWidgetSize.height()));
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case SE_TabWidgetTabPane:
+ case SE_TabWidgetTabContents:
+ if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ QStyleOptionTab tabopt;
+ tabopt.shape = twf->shape;
+ int overlap = proxy()->pixelMetric(PM_TabBarBaseOverlap, &tabopt);
+ if (twf->lineWidth == 0)
+ overlap = 0;
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ r = QRect(QPoint(0,qMax(twf->tabBarSize.height() - overlap, 0)),
+ QSize(twf->rect.width(), qMin(twf->rect.height() - twf->tabBarSize.height() + overlap, twf->rect.height())));
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ r = QRect(QPoint(0,0), QSize(twf->rect.width(), qMin(twf->rect.height() - twf->tabBarSize.height() + overlap, twf->rect.height())));
+ break;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ r = QRect(QPoint(0, 0), QSize(qMin(twf->rect.width() - twf->tabBarSize.width() + overlap, twf->rect.width()), twf->rect.height()));
+ break;
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ r = QRect(QPoint(qMax(twf->tabBarSize.width() - overlap, 0), 0),
+ QSize(qMin(twf->rect.width() - twf->tabBarSize.width() + overlap, twf->rect.width()), twf->rect.height()));
+ break;
+ }
+ if (sr == SE_TabWidgetTabContents && twf->lineWidth > 0)
+ r.adjust(2, 2, -2, -2);
+ }
+ break;
+ case SE_TabWidgetLeftCorner:
+ if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ QRect paneRect = subElementRect(SE_TabWidgetTabPane, twf);
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ r = QRect(QPoint(paneRect.x(), paneRect.y() - twf->leftCornerWidgetSize.height()),
+ twf->leftCornerWidgetSize);
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ r = QRect(QPoint(paneRect.x(), paneRect.height()), twf->leftCornerWidgetSize);
+ break;
+ default:
+ break;
+ }
+ r = visualRect(twf->direction, twf->rect, r);
+ }
+ break;
+ case SE_TabWidgetRightCorner:
+ if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) {
+ QRect paneRect = subElementRect(SE_TabWidgetTabPane, twf);
+ switch (twf->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ r = QRect(QPoint(paneRect.width() - twf->rightCornerWidgetSize.width(),
+ paneRect.y() - twf->rightCornerWidgetSize.height()),
+ twf->rightCornerWidgetSize);
+ break;
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ r = QRect(QPoint(paneRect.width() - twf->rightCornerWidgetSize.width(),
+ paneRect.height()), twf->rightCornerWidgetSize);
+ break;
+ default:
+ break;
+ }
+ r = visualRect(twf->direction, twf->rect, r);
+ }
+ break;
+ case SE_TabBarTabText:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ QRect dummyIconRect;
+ d->tabLayout(tab, &r, &dummyIconRect);
+ }
+ break;
+ case SE_TabBarTabLeftButton:
+ case SE_TabBarTabRightButton:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ bool selected = tab->state & State_Selected;
+ int verticalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab);
+ int horizontalShift = proxy()->pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab);
+ int hpadding = proxy()->pixelMetric(QStyle::PM_TabBarTabHSpace, opt) / 2;
+ hpadding = qMax(hpadding, 4); //workaround KStyle returning 0 because they workaround an old bug in Qt
+
+ bool verticalTabs = tab->shape == QStyleOptionTab::RoundedEast
+ || tab->shape == QStyleOptionTab::RoundedWest
+ || tab->shape == QStyleOptionTab::TriangularEast
+ || tab->shape == QStyleOptionTab::TriangularWest;
+
+ QRect tr = tab->rect;
+ if (tab->shape == QStyleOptionTab::RoundedSouth || tab->shape == QStyleOptionTab::TriangularSouth)
+ verticalShift = -verticalShift;
+ if (verticalTabs) {
+ qSwap(horizontalShift, verticalShift);
+ horizontalShift *= -1;
+ verticalShift *= -1;
+ }
+ if (tab->shape == QStyleOptionTab::RoundedWest || tab->shape == QStyleOptionTab::TriangularWest)
+ horizontalShift = -horizontalShift;
+
+ tr.adjust(0, 0, horizontalShift, verticalShift);
+ if (selected)
+ {
+ tr.setBottom(tr.bottom() - verticalShift);
+ tr.setRight(tr.right() - horizontalShift);
+ }
+
+ QSize size = (sr == SE_TabBarTabLeftButton) ? tab->leftButtonSize : tab->rightButtonSize;
+ int w = size.width();
+ int h = size.height();
+ int midHeight = static_cast<int>(qCeil(float(tr.height() - h) / 2));
+ int midWidth = ((tr.width() - w) / 2);
+
+ bool atTheTop = true;
+ switch (tab->shape) {
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ atTheTop = (sr == SE_TabBarTabLeftButton);
+ break;
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ atTheTop = (sr == SE_TabBarTabRightButton);
+ break;
+ default:
+ if (sr == SE_TabBarTabLeftButton)
+ r = QRect(tab->rect.x() + hpadding, midHeight, w, h);
+ else
+ r = QRect(tab->rect.right() - w - hpadding, midHeight, w, h);
+ r = visualRect(tab->direction, tab->rect, r);
+ }
+ if (verticalTabs) {
+ if (atTheTop)
+ r = QRect(midWidth, tr.y() + tab->rect.height() - hpadding - h, w, h);
+ else
+ r = QRect(midWidth, tr.y() + hpadding, w, h);
+ }
+ }
+
+ break;
+ case SE_TabBarTearIndicator:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ switch (tab->shape) {
+ case QStyleOptionTab::RoundedNorth:
+ case QStyleOptionTab::TriangularNorth:
+ case QStyleOptionTab::RoundedSouth:
+ case QStyleOptionTab::TriangularSouth:
+ r.setRect(tab->rect.left(), tab->rect.top(), 8, opt->rect.height());
+ break;
+ case QStyleOptionTab::RoundedWest:
+ case QStyleOptionTab::TriangularWest:
+ case QStyleOptionTab::RoundedEast:
+ case QStyleOptionTab::TriangularEast:
+ r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), 8);
+ break;
+ default:
+ break;
+ }
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_TabBarScrollLeftButton: {
+ const bool vertical = opt->rect.width() < opt->rect.height();
+ const Qt::LayoutDirection ld = opt->direction;
+ const int buttonWidth = proxy()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, nullptr);
+ const int buttonOverlap = proxy()->pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, nullptr);
+
+ r = vertical ? QRect(0, opt->rect.height() - (buttonWidth * 2) + buttonOverlap, opt->rect.width(), buttonWidth)
+ : QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - (buttonWidth * 2) + buttonOverlap, 0, buttonWidth, opt->rect.height()));
+ break; }
+ case SE_TabBarScrollRightButton: {
+ const bool vertical = opt->rect.width() < opt->rect.height();
+ const Qt::LayoutDirection ld = opt->direction;
+ const int buttonWidth = proxy()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, nullptr);
+
+ r = vertical ? QRect(0, opt->rect.height() - buttonWidth, opt->rect.width(), buttonWidth)
+ : QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - buttonWidth, 0, buttonWidth, opt->rect.height()));
+ break; }
+ case SE_TreeViewDisclosureItem:
+ r = opt->rect;
+ break;
+ case SE_LineEditContents:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ r = f->rect.adjusted(f->lineWidth, f->lineWidth, -f->lineWidth, -f->lineWidth);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_FrameContents:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, f);
+ r = opt->rect.adjusted(fw, fw, -fw, -fw);
+ r = visualRect(opt->direction, opt->rect, r);
+ }
+ break;
+ case SE_ShapedFrameContents:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ int frameShape = f->frameShape;
+ int frameShadow = QStyleOptionFrame::Plain;
+ if (f->state & QStyle::State_Sunken) {
+ frameShadow = QStyleOptionFrame::Sunken;
+ } else if (f->state & QStyle::State_Raised) {
+ frameShadow = QStyleOptionFrame::Raised;
+ }
+
+ int frameWidth = 0;
+
+ switch (frameShape) {
+ case QStyleOptionFrame::NoFrame:
+ frameWidth = 0;
+ break;
+
+ case QStyleOptionFrame::Box:
+ case QStyleOptionFrame::HLine:
+ case QStyleOptionFrame::VLine:
+ switch (frameShadow) {
+ case QStyleOptionFrame::Plain:
+ frameWidth = f->lineWidth;
+ break;
+ case QStyleOptionFrame::Raised:
+ case QStyleOptionFrame::Sunken:
+ frameWidth = (short)(f->lineWidth*2 + f->midLineWidth);
+ break;
+ }
+ break;
+
+ case QStyleOptionFrame::StyledPanel:
+ //keep the compatibility with Qt 4.4 if there is a proxy style.
+ //be sure to call drawPrimitive(QStyle::SE_FrameContents) on the proxy style
+ return subElementRect(QStyle::SE_FrameContents, opt);
+
+ case QStyleOptionFrame::WinPanel:
+ frameWidth = 2;
+ break;
+
+ case QStyleOptionFrame::Panel:
+ switch (frameShadow) {
+ case QStyleOptionFrame::Plain:
+ case QStyleOptionFrame::Raised:
+ case QStyleOptionFrame::Sunken:
+ frameWidth = f->lineWidth;
+ break;
+ }
+ break;
+ }
+ r = f->rect.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth);
+ }
+ break;
+ case SE_DockWidgetCloseButton:
+ case SE_DockWidgetFloatButton:
+ case SE_DockWidgetTitleBarText:
+ case SE_DockWidgetIcon: {
+ int iconSize = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ int buttonMargin = proxy()->pixelMetric(PM_DockWidgetTitleBarButtonMargin, opt);
+ QRect rect = opt->rect;
+
+ const QStyleOptionDockWidget *dwOpt
+ = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
+ bool canClose = dwOpt == nullptr ? true : dwOpt->closable;
+ bool canFloat = dwOpt == nullptr ? false : dwOpt->floatable;
+
+ const bool verticalTitleBar = dwOpt && dwOpt->verticalTitleBar;
+
+ // If this is a vertical titlebar, we transpose and work as if it was
+ // horizontal, then transpose again.
+
+ if (verticalTitleBar)
+ rect = rect.transposed();
+
+ do {
+ int right = rect.right();
+ int left = rect.left();
+
+ QRect closeRect;
+ if (canClose) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton,
+ opt).actualSize(QSize(iconSize, iconSize));
+ sz += QSize(buttonMargin, buttonMargin);
+ if (verticalTitleBar)
+ sz = sz.transposed();
+ closeRect = QRect(right - sz.width(),
+ rect.center().y() - sz.height()/2,
+ sz.width(), sz.height());
+ right = closeRect.left() - 1;
+ }
+ if (sr == SE_DockWidgetCloseButton) {
+ r = closeRect;
+ break;
+ }
+
+ QRect floatRect;
+ if (canFloat) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarNormalButton,
+ opt).actualSize(QSize(iconSize, iconSize));
+ sz += QSize(buttonMargin, buttonMargin);
+ if (verticalTitleBar)
+ sz = sz.transposed();
+ floatRect = QRect(right - sz.width(),
+ rect.center().y() - sz.height()/2,
+ sz.width(), sz.height());
+ right = floatRect.left() - 1;
+ }
+ if (sr == SE_DockWidgetFloatButton) {
+ r = floatRect;
+ break;
+ }
+
+ QRect iconRect;
+ if (sr == SE_DockWidgetIcon) {
+ r = iconRect;
+ break;
+ }
+
+ QRect textRect = QRect(left, rect.top(),
+ right - left, rect.height());
+ if (sr == SE_DockWidgetTitleBarText) {
+ r = textRect;
+ break;
+ }
+
+ } while (false);
+
+ if (verticalTitleBar) {
+ r = QRect(rect.left() + r.top() - rect.top(),
+ rect.top() + rect.right() - r.right(),
+ r.height(), r.width());
+ } else {
+ r = visualRect(opt->direction, rect, r);
+ }
+ break;
+ }
+ case SE_ItemViewItemCheckIndicator:
+ if (!qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ r = subElementRect(SE_CheckBoxIndicator, opt);
+ break;
+ }
+ Q_FALLTHROUGH();
+ case SE_ItemViewItemDecoration:
+ case SE_ItemViewItemText:
+ case SE_ItemViewItemFocusRect:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ if (!d->isViewItemCached(*vopt)) {
+ d->viewItemLayout(vopt, &d->checkRect, &d->decorationRect, &d->displayRect, false);
+ if (d->cachedOption) {
+ delete d->cachedOption;
+ d->cachedOption = nullptr;
+ }
+ d->cachedOption = new QStyleOptionViewItem(*vopt);
+ }
+ if (sr == SE_ItemViewItemCheckIndicator)
+ r = d->checkRect;
+ else if (sr == SE_ItemViewItemDecoration)
+ r = d->decorationRect;
+ else if (sr == SE_ItemViewItemText || sr == SE_ItemViewItemFocusRect)
+ r = d->displayRect;
+ }
+ break;
+ case SE_ToolBarHandle:
+ if (const QStyleOptionToolBar *tbopt = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
+ if (tbopt->features & QStyleOptionToolBar::Movable) {
+ ///we need to access the widget here because the style option doesn't
+ //have all the information we need (ie. the layout's margin)
+ const QMargins margins(2, 2, 2, 2);
+ const int handleExtent = proxy()->pixelMetric(QStyle::PM_ToolBarHandleExtent, opt);
+ if (tbopt->state & QStyle::State_Horizontal) {
+ r = QRect(margins.left(), margins.top(),
+ handleExtent,
+ tbopt->rect.height() - (margins.top() + margins.bottom()));
+ r = QStyle::visualRect(tbopt->direction, tbopt->rect, r);
+ } else {
+ r = QRect(margins.left(), margins.top(),
+ tbopt->rect.width() - (margins.left() + margins.right()),
+ handleExtent);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return r;
+}
+
+// in lieu of std::array, minimal API
+template <int N>
+struct StaticPolygonF
+{
+ QPointF data[N];
+
+ Q_DECL_CONSTEXPR int size() const { return N; }
+ Q_DECL_CONSTEXPR const QPointF *cbegin() const { return data; }
+ Q_DECL_CONSTEXPR const QPointF &operator[](int idx) const { return data[idx]; }
+};
+
+static StaticPolygonF<3> calcArrow(const QStyleOptionSlider *dial, qreal &a)
+{
+ int width = dial->rect.width();
+ int height = dial->rect.height();
+ int r = qMin(width, height) / 2;
+ int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition);
+
+ if (dial->maximum == dial->minimum)
+ a = Q_PI / 2;
+ else if (dial->dialWrapping)
+ a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI
+ / (dial->maximum - dial->minimum);
+ else
+ a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI
+ / (dial->maximum - dial->minimum)) / 6;
+
+ int xc = width / 2;
+ int yc = height / 2;
+
+ int len = r - QStyleHelper::calcBigLineSize(r) - 5;
+ if (len < 5)
+ len = 5;
+ int back = len / 2;
+
+ StaticPolygonF<3> arrow = {{
+ QPointF(0.5 + xc + len * qCos(a),
+ 0.5 + yc - len * qSin(a)),
+ QPointF(0.5 + xc + back * qCos(a + Q_PI * 5 / 6),
+ 0.5 + yc - back * qSin(a + Q_PI * 5 / 6)),
+ QPointF(0.5 + xc + back * qCos(a - Q_PI * 5 / 6),
+ 0.5 + yc - back * qSin(a - Q_PI * 5 / 6)),
+ }};
+ return arrow;
+}
+
+void QCommonStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const
+{
+ switch (cc) {
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ if (slider->subControls == SC_SliderTickmarks) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider);
+ int ticks = slider->tickPosition;
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (!interval)
+ interval = 1;
+ int fudge = len / 2;
+ int pos;
+ // Since there is no subrect for tickmarks do a translation here.
+ p->save();
+ p->translate(slider->rect.x(), slider->rect.y());
+ p->setPen(slider->palette.windowText().color());
+ int v = slider->minimum;
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, available) + fudge;
+ if (slider->orientation == Qt::Horizontal) {
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ p->drawLine(pos, 0, pos, tickOffset - 2);
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ p->drawLine(pos, tickOffset + thickness + 1, pos,
+ slider->rect.height()-1);
+ } else {
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ p->drawLine(0, pos, tickOffset - 2, pos);
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ p->drawLine(tickOffset + thickness + 1, pos,
+ slider->rect.width()-1, pos);
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ p->restore();
+ }
+ }
+ break;
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ // Make a copy here and reset it for each primitive.
+ QStyleOptionSlider newScrollbar = *scrollbar;
+ State saveFlags = scrollbar->state;
+
+ if (scrollbar->subControls & SC_ScrollBarSubLine) {
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarSubLine);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarSubLine))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarSubLine, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarAddLine) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarAddLine);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarAddLine))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarAddLine, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarSubPage) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarSubPage);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarSubPage))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarSubPage, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarAddPage) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarAddPage);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarAddPage))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarAddPage, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarFirst) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarFirst);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarFirst))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarFirst, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarLast) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarLast);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarLast))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarLast, &newScrollbar, p);
+ }
+ }
+ if (scrollbar->subControls & SC_ScrollBarSlider) {
+ newScrollbar.rect = scrollbar->rect;
+ newScrollbar.state = saveFlags;
+ newScrollbar.rect = proxy()->subControlRect(cc, &newScrollbar, SC_ScrollBarSlider);
+ if (newScrollbar.rect.isValid()) {
+ if (!(scrollbar->activeSubControls & SC_ScrollBarSlider))
+ newScrollbar.state &= ~(State_Sunken | State_MouseOver);
+ proxy()->drawControl(CE_ScrollBarSlider, &newScrollbar, p);
+
+ if (scrollbar->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(newScrollbar);
+ fropt.rect.setRect(newScrollbar.rect.x() + 2, newScrollbar.rect.y() + 2,
+ newScrollbar.rect.width() - 5,
+ newScrollbar.rect.height() - 5);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ }
+ }
+ break;
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ QStyleOptionSpinBox copy = *sb;
+ PrimitiveElement pe;
+
+ if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
+ QRect r = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxFrame);
+ qDrawWinPanel(p, r, sb->palette, true);
+ }
+
+ if (sb->subControls & SC_SpinBoxUp) {
+ copy.subControls = SC_SpinBoxUp;
+ QPalette pal2 = sb->palette;
+ if (!(sb->stepEnabled & QStyleOptionSpinBox::StepUpEnabled)) {
+ pal2.setCurrentColorGroup(QPalette::Disabled);
+ copy.state &= ~State_Enabled;
+ }
+
+ copy.palette = pal2;
+
+ if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken)) {
+ copy.state |= State_On;
+ copy.state |= State_Sunken;
+ } else {
+ copy.state |= State_Raised;
+ copy.state &= ~State_Sunken;
+ }
+ pe = (sb->buttonSymbols == QStyleOptionSpinBox::PlusMinus ? PE_IndicatorSpinPlus
+ : PE_IndicatorSpinUp);
+
+ copy.rect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp);
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &copy, p);
+ copy.rect.adjust(3, 0, -4, 0);
+ proxy()->drawPrimitive(pe, &copy, p);
+ }
+
+ if (sb->subControls & SC_SpinBoxDown) {
+ copy.subControls = SC_SpinBoxDown;
+ copy.state = sb->state;
+ QPalette pal2 = sb->palette;
+ if (!(sb->stepEnabled & QStyleOptionSpinBox::StepDownEnabled)) {
+ pal2.setCurrentColorGroup(QPalette::Disabled);
+ copy.state &= ~State_Enabled;
+ }
+ copy.palette = pal2;
+
+ if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken)) {
+ copy.state |= State_On;
+ copy.state |= State_Sunken;
+ } else {
+ copy.state |= State_Raised;
+ copy.state &= ~State_Sunken;
+ }
+ pe = (sb->buttonSymbols == QStyleOptionSpinBox::PlusMinus ? PE_IndicatorSpinMinus
+ : PE_IndicatorSpinDown);
+
+ copy.rect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown);
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &copy, p);
+ copy.rect.adjust(3, 0, -4, 0);
+ proxy()->drawPrimitive(pe, &copy, p);
+ }
+ }
+ break;
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *toolbutton
+ = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+ QRect button, menuarea;
+ button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton);
+ menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu);
+
+ State bflags = toolbutton->state & ~State_Sunken;
+
+ if (bflags & State_AutoRaise) {
+ if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
+ bflags &= ~State_Raised;
+ }
+ }
+ State mflags = bflags;
+ if (toolbutton->state & State_Sunken) {
+ if (toolbutton->activeSubControls & SC_ToolButton)
+ bflags |= State_Sunken;
+ mflags |= State_Sunken;
+ }
+
+ QStyleOption tool = *toolbutton;
+ if (toolbutton->subControls & SC_ToolButton) {
+ if (bflags & (State_Sunken | State_On | State_Raised)) {
+ tool.rect = button;
+ tool.state = bflags;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+ }
+ }
+
+ if (toolbutton->state & State_HasFocus) {
+ QStyleOptionFocusRect fr;
+ fr.QStyleOption::operator=(*toolbutton);
+ fr.rect.adjust(3, 3, -3, -3);
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
+ fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
+ toolbutton), 0);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p);
+ }
+ QStyleOptionToolButton label = *toolbutton;
+ label.state = bflags;
+ int fw = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ label.rect = button.adjusted(fw, fw, -fw, -fw);
+ proxy()->drawControl(CE_ToolButtonLabel, &label, p);
+
+ if (toolbutton->subControls & SC_ToolButtonMenu) {
+ tool.rect = menuarea;
+ tool.state = mflags;
+ if (mflags & (State_Sunken | State_On | State_Raised))
+ proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, p);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, p);
+ } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
+ int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton);
+ QRect ir = toolbutton->rect;
+ QStyleOptionToolButton newBtn = *toolbutton;
+ newBtn.rect = QRect(ir.right() + 5 - mbi, ir.y() + ir.height() - mbi + 4, mbi - 6, mbi - 6);
+ newBtn.rect = visualRect(toolbutton->direction, button, newBtn.rect);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p);
+ }
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ QRect ir;
+ if (opt->subControls & SC_TitleBarLabel) {
+ QColor left = tb->palette.highlight().color();
+ QColor right = tb->palette.base().color();
+
+ QBrush fillBrush(left);
+ if (left != right) {
+ QPoint p1(tb->rect.x(), tb->rect.top() + tb->rect.height()/2);
+ QPoint p2(tb->rect.right(), tb->rect.top() + tb->rect.height()/2);
+ QLinearGradient lg(p1, p2);
+ lg.setColorAt(0, left);
+ lg.setColorAt(1, right);
+ fillBrush = lg;
+ }
+
+ p->fillRect(opt->rect, fillBrush);
+
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarLabel);
+
+ p->setPen(tb->palette.highlightedText().color());
+ p->drawText(ir.x() + 2, ir.y(), ir.width() - 2, ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
+ }
+
+ bool down = false;
+ QPixmap pm;
+
+ QStyleOption tool = *tb;
+ if (tb->subControls & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarCloseButton);
+ down = tb->activeSubControls & SC_TitleBarCloseButton && (opt->state & State_Sunken);
+ if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool)
+ pm = proxy()->standardIcon(SP_DockWidgetCloseButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ else
+ pm = proxy()->standardIcon(SP_TitleBarCloseButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+
+ if (tb->subControls & SC_TitleBarMaxButton
+ && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMaximized)) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarMaxButton);
+
+ down = tb->activeSubControls & SC_TitleBarMaxButton && (opt->state & State_Sunken);
+ pm = proxy()->standardIcon(SP_TitleBarMaxButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+
+ if (tb->subControls & SC_TitleBarMinButton
+ && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarMinButton);
+ down = tb->activeSubControls & SC_TitleBarMinButton && (opt->state & State_Sunken);
+ pm = proxy()->standardIcon(SP_TitleBarMinButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+
+ bool drawNormalButton = (tb->subControls & SC_TitleBarNormalButton)
+ && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMinimized))
+ || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMaximized)));
+
+ if (drawNormalButton) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarNormalButton);
+ down = tb->activeSubControls & SC_TitleBarNormalButton && (opt->state & State_Sunken);
+ pm = proxy()->standardIcon(SP_TitleBarNormalButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+
+ if (tb->subControls & SC_TitleBarShadeButton
+ && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarShadeButton);
+ down = (tb->activeSubControls & SC_TitleBarShadeButton && (opt->state & State_Sunken));
+ pm = proxy()->standardIcon(SP_TitleBarShadeButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+
+ if (tb->subControls & SC_TitleBarUnshadeButton
+ && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && tb->titleBarState & Qt::WindowMinimized) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarUnshadeButton);
+
+ down = tb->activeSubControls & SC_TitleBarUnshadeButton && (opt->state & State_Sunken);
+ pm = proxy()->standardIcon(SP_TitleBarUnshadeButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+ if (tb->subControls & SC_TitleBarContextHelpButton
+ && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarContextHelpButton);
+
+ down = tb->activeSubControls & SC_TitleBarContextHelpButton && (opt->state & State_Sunken);
+ pm = proxy()->standardIcon(SP_TitleBarContextHelpButton, &tool).pixmap(QSize(10, 10), dpr(opt->window));
+ tool.rect = ir;
+ tool.state = down ? State_Sunken : State_Raised;
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+ p->save();
+ if (down)
+ p->translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, tb),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, tb));
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+ if (tb->subControls & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarSysMenu);
+ if (!tb->icon.isNull()) {
+ tb->icon.paint(p, ir);
+ } else {
+ int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb);
+ pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool).pixmap(QSize(iconSize, iconSize), dpr(opt->window));
+ tool.rect = ir;
+ p->save();
+ proxy()->drawItemPixmap(p, ir, Qt::AlignCenter, pm);
+ p->restore();
+ }
+ }
+ }
+ break;
+ case CC_Dial:
+ if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ // OK, this is more a port of things over
+ p->save();
+
+ // avoid dithering
+ if (p->paintEngine()->hasFeature(QPaintEngine::Antialiasing))
+ p->setRenderHint(QPainter::Antialiasing);
+
+ int width = dial->rect.width();
+ int height = dial->rect.height();
+ qreal r = qMin(width, height) / 2;
+ qreal d_ = r / 6;
+ qreal dx = dial->rect.x() + d_ + (width - 2 * r) / 2 + 1;
+ qreal dy = dial->rect.y() + d_ + (height - 2 * r) / 2 + 1;
+ QRect br = QRect(int(dx), int(dy), int(r * 2 - 2 * d_ - 2), int(r * 2 - 2 * d_ - 2));
+
+ QPalette pal = opt->palette;
+ // draw notches
+ if (dial->subControls & QStyle::SC_DialTickmarks) {
+ p->setPen(pal.windowText().color());
+ p->drawLines(QStyleHelper::calcLines(dial));
+ }
+
+ if (dial->state & State_Enabled) {
+ p->setBrush(pal.brush(QPalette::ColorRole(proxy()->styleHint(SH_Dial_BackgroundRole, dial))));
+ p->setPen(Qt::NoPen);
+ p->drawEllipse(br);
+ p->setBrush(Qt::NoBrush);
+ }
+ p->setPen(QPen(pal.dark().color()));
+ p->drawArc(br, 60 * 16, 180 * 16);
+ p->setPen(QPen(pal.light().color()));
+ p->drawArc(br, 240 * 16, 180 * 16);
+
+ qreal a;
+ const StaticPolygonF<3> arrow = calcArrow(dial, a);
+
+ p->setPen(Qt::NoPen);
+ p->setBrush(pal.button());
+ p->drawPolygon(arrow.cbegin(), arrow.size());
+
+ a = QStyleHelper::angle(QPointF(width / 2, height / 2), arrow[0]);
+ p->setBrush(Qt::NoBrush);
+
+ if (a <= 0 || a > 200) {
+ p->setPen(pal.light().color());
+ p->drawLine(arrow[2], arrow[0]);
+ p->drawLine(arrow[1], arrow[2]);
+ p->setPen(pal.dark().color());
+ p->drawLine(arrow[0], arrow[1]);
+ } else if (a > 0 && a < 45) {
+ p->setPen(pal.light().color());
+ p->drawLine(arrow[2], arrow[0]);
+ p->setPen(pal.dark().color());
+ p->drawLine(arrow[1], arrow[2]);
+ p->drawLine(arrow[0], arrow[1]);
+ } else if (a >= 45 && a < 135) {
+ p->setPen(pal.dark().color());
+ p->drawLine(arrow[2], arrow[0]);
+ p->drawLine(arrow[1], arrow[2]);
+ p->setPen(pal.light().color());
+ p->drawLine(arrow[0], arrow[1]);
+ } else if (a >= 135 && a < 200) {
+ p->setPen(pal.dark().color());
+ p->drawLine(arrow[2], arrow[0]);
+ p->setPen(pal.light().color());
+ p->drawLine(arrow[0], arrow[1]);
+ p->drawLine(arrow[1], arrow[2]);
+ }
+
+ // draw focus rect around the dial
+ QStyleOptionFocusRect fropt;
+ fropt.rect = dial->rect;
+ fropt.state = dial->state;
+ fropt.palette = dial->palette;
+ if (fropt.state & QStyle::State_HasFocus) {
+ br.adjust(0, 0, 2, 2);
+ if (dial->subControls & SC_DialTickmarks) {
+ int r = qMin(width, height) / 2;
+ br.translate(-r / 6, - r / 6);
+ br.setWidth(br.width() + r / 3);
+ br.setHeight(br.height() + r / 3);
+ }
+ fropt.rect = br.adjusted(-2, -2, 2, 2);
+ proxy()->drawPrimitive(QStyle::PE_FrameFocusRect, &fropt, p);
+ }
+ p->restore();
+ }
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ // Draw frame
+ QRect textRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxLabel);
+ QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxCheckBox);
+ if (groupBox->subControls & QStyle::SC_GroupBoxFrame) {
+ QStyleOptionFrame frame;
+ frame.QStyleOption::operator=(*groupBox);
+ frame.features = groupBox->features;
+ frame.lineWidth = groupBox->lineWidth;
+ frame.midLineWidth = groupBox->midLineWidth;
+ frame.rect = proxy()->subControlRect(CC_GroupBox, opt, SC_GroupBoxFrame);
+ p->save();
+ QRegion region(groupBox->rect);
+ if (!groupBox->text.isEmpty()) {
+ bool ltr = groupBox->direction == Qt::LeftToRight;
+ QRect finalRect;
+ if (groupBox->subControls & QStyle::SC_GroupBoxCheckBox) {
+ finalRect = checkBoxRect.united(textRect);
+ finalRect.adjust(ltr ? -4 : 0, 0, ltr ? 0 : 4, 0);
+ } else {
+ finalRect = textRect;
+ }
+ region -= finalRect;
+ }
+ p->setClipRegion(region);
+ proxy()->drawPrimitive(PE_FrameGroupBox, &frame, p);
+ p->restore();
+ }
+
+ // Draw title
+ if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) {
+ QColor textColor = groupBox->textColor;
+ if (textColor.isValid())
+ p->setPen(textColor);
+ int alignment = int(groupBox->textAlignment);
+ if (!proxy()->styleHint(QStyle::SH_UnderlineShortcut, opt))
+ alignment |= Qt::TextHideMnemonic;
+
+ proxy()->drawItemText(p, textRect, Qt::TextShowMnemonic | Qt::AlignHCenter | alignment,
+ groupBox->palette, groupBox->state & State_Enabled, groupBox->text,
+ textColor.isValid() ? QPalette::NoRole : QPalette::WindowText);
+
+ if (groupBox->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*groupBox);
+ fropt.rect = textRect;
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+
+ // Draw checkbox
+ if (groupBox->subControls & SC_GroupBoxCheckBox) {
+ QStyleOptionButton box;
+ box.QStyleOption::operator=(*groupBox);
+ box.rect = checkBoxRect;
+ proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, p);
+ }
+ }
+ break;
+ case CC_MdiControls:
+ {
+ QStyleOptionButton btnOpt;
+ btnOpt.QStyleOption::operator=(*opt);
+ btnOpt.state &= ~State_MouseOver;
+ int bsx = 0;
+ int bsy = 0;
+ const int buttonIconMetric = proxy()->pixelMetric(PM_TitleBarButtonIconSize, &btnOpt);
+ const QSize buttonIconSize(buttonIconMetric, buttonIconMetric);
+ if (opt->subControls & QStyle::SC_MdiCloseButton) {
+ if (opt->activeSubControls & QStyle::SC_MdiCloseButton && (opt->state & State_Sunken)) {
+ btnOpt.state |= State_Sunken;
+ btnOpt.state &= ~State_Raised;
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
+ } else {
+ btnOpt.state |= State_Raised;
+ btnOpt.state &= ~State_Sunken;
+ bsx = 0;
+ bsy = 0;
+ }
+ btnOpt.rect = proxy()->subControlRect(CC_MdiControls, opt, SC_MdiCloseButton);
+ proxy()->drawPrimitive(PE_PanelButtonCommand, &btnOpt, p);
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarCloseButton).pixmap(buttonIconSize, dpr(opt->window));
+ proxy()->drawItemPixmap(p, btnOpt.rect.translated(bsx, bsy), Qt::AlignCenter, pm);
+ }
+ if (opt->subControls & QStyle::SC_MdiNormalButton) {
+ if (opt->activeSubControls & QStyle::SC_MdiNormalButton && (opt->state & State_Sunken)) {
+ btnOpt.state |= State_Sunken;
+ btnOpt.state &= ~State_Raised;
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
+ } else {
+ btnOpt.state |= State_Raised;
+ btnOpt.state &= ~State_Sunken;
+ bsx = 0;
+ bsy = 0;
+ }
+ btnOpt.rect = proxy()->subControlRect(CC_MdiControls, opt, SC_MdiNormalButton);
+ proxy()->drawPrimitive(PE_PanelButtonCommand, &btnOpt, p);
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarNormalButton).pixmap(buttonIconSize, dpr(opt->window));
+ proxy()->drawItemPixmap(p, btnOpt.rect.translated(bsx, bsy), Qt::AlignCenter, pm);
+ }
+ if (opt->subControls & QStyle::SC_MdiMinButton) {
+ if (opt->activeSubControls & QStyle::SC_MdiMinButton && (opt->state & State_Sunken)) {
+ btnOpt.state |= State_Sunken;
+ btnOpt.state &= ~State_Raised;
+ bsx = proxy()->pixelMetric(PM_ButtonShiftHorizontal);
+ bsy = proxy()->pixelMetric(PM_ButtonShiftVertical);
+ } else {
+ btnOpt.state |= State_Raised;
+ btnOpt.state &= ~State_Sunken;
+ bsx = 0;
+ bsy = 0;
+ }
+ btnOpt.rect = proxy()->subControlRect(CC_MdiControls, opt, SC_MdiMinButton);
+ proxy()->drawPrimitive(PE_PanelButtonCommand, &btnOpt, p);
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarMinButton).pixmap(buttonIconSize, dpr(opt->window));
+ proxy()->drawItemPixmap(p, btnOpt.rect.translated(bsx, bsy), Qt::AlignCenter, pm);
+ }
+ }
+ break;
+ default:
+ qWarning("QCommonStyle::drawComplexControl: Control %d not handled", cc);
+ }
+}
+
+/*!
+ \reimp
+*/
+QStyle::SubControl QCommonStyle::hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const
+{
+ SubControl sc = SC_None;
+ switch (cc) {
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ QRect r = proxy()->subControlRect(cc, slider, SC_SliderHandle);
+ if (r.isValid() && r.contains(pt)) {
+ sc = SC_SliderHandle;
+ } else {
+ r = proxy()->subControlRect(cc, slider, SC_SliderGroove);
+ if (r.isValid() && r.contains(pt))
+ sc = SC_SliderGroove;
+ }
+ }
+ break;
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ QRect r;
+ uint ctrl = SC_ScrollBarAddLine;
+ while (ctrl <= SC_ScrollBarGroove) {
+ r = proxy()->subControlRect(cc, scrollbar, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *toolbutton = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+ QRect r;
+ uint ctrl = SC_ToolButton;
+ while (ctrl <= SC_ToolButtonMenu) {
+ r = proxy()->subControlRect(cc, toolbutton, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ QRect r;
+ uint ctrl = SC_SpinBoxUp;
+ while (ctrl <= SC_SpinBoxEditField) {
+ r = proxy()->subControlRect(cc, spinbox, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ QRect r;
+ uint ctrl = SC_TitleBarSysMenu;
+
+ while (ctrl <= SC_TitleBarLabel) {
+ r = proxy()->subControlRect(cc, tb, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ QRect r;
+ uint ctrl = SC_ComboBoxArrow; // Start here and go down.
+ while (ctrl > 0) {
+ r = proxy()->subControlRect(cc, cb, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl >>= 1;
+ }
+ }
+ break;
+ case CC_GroupBox:
+ if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ QRect r;
+ uint ctrl = SC_GroupBoxCheckBox;
+ while (ctrl <= SC_GroupBoxFrame) {
+ r = proxy()->subControlRect(cc, groupBox, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt)) {
+ sc = QStyle::SubControl(ctrl);
+ break;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ case CC_MdiControls:
+ {
+ QRect r;
+ uint ctrl = SC_MdiMinButton;
+ while (ctrl <= SC_MdiCloseButton) {
+ r = proxy()->subControlRect(CC_MdiControls, opt, QStyle::SubControl(ctrl));
+ if (r.isValid() && r.contains(pt) && (opt->subControls & ctrl)) {
+ sc = QStyle::SubControl(ctrl);
+ return sc;
+ }
+ ctrl <<= 1;
+ }
+ }
+ break;
+ default:
+ qWarning("QCommonStyle::hitTestComplexControl: Case %d not handled", cc);
+ }
+ return sc;
+}
+
+/*!
+ \reimp
+*/
+QRect QCommonStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc) const
+{
+ QRect ret;
+ switch (cc) {
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider);
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider);
+
+ switch (sc) {
+ case SC_SliderHandle: {
+ int sliderPos = 0;
+ int len = proxy()->pixelMetric(PM_SliderLength, slider);
+ bool horizontal = slider->orientation == Qt::Horizontal;
+ sliderPos = sliderPositionFromValue(slider->minimum, slider->maximum,
+ slider->sliderPosition,
+ (horizontal ? slider->rect.width()
+ : slider->rect.height()) - len,
+ slider->upsideDown);
+ if (horizontal)
+ ret.setRect(slider->rect.x() + sliderPos, slider->rect.y() + tickOffset, len, thickness);
+ else
+ ret.setRect(slider->rect.x() + tickOffset, slider->rect.y() + sliderPos, thickness, len);
+ break; }
+ case SC_SliderGroove:
+ if (slider->orientation == Qt::Horizontal)
+ ret.setRect(slider->rect.x(), slider->rect.y() + tickOffset,
+ slider->rect.width(), thickness);
+ else
+ ret.setRect(slider->rect.x() + tickOffset, slider->rect.y(),
+ thickness, slider->rect.height());
+ break;
+ default:
+ break;
+ }
+ ret = visualRect(slider->direction, slider->rect, ret);
+ }
+ break;
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ const QRect scrollBarRect = scrollbar->rect;
+ int sbextent = 0;
+ if (!proxy()->styleHint(SH_ScrollBar_Transient, scrollbar))
+ sbextent = proxy()->pixelMetric(PM_ScrollBarExtent, scrollbar);
+ int maxlen = ((scrollbar->orientation == Qt::Horizontal) ?
+ scrollBarRect.width() : scrollBarRect.height()) - (sbextent * 2);
+ int sliderlen;
+
+ // calculate slider length
+ if (scrollbar->maximum != scrollbar->minimum) {
+ uint range = scrollbar->maximum - scrollbar->minimum;
+ sliderlen = (qint64(scrollbar->pageStep) * maxlen) / (range + scrollbar->pageStep);
+
+ int slidermin = proxy()->pixelMetric(PM_ScrollBarSliderMin, scrollbar);
+ if (sliderlen < slidermin || range > INT_MAX / 2)
+ sliderlen = slidermin;
+ if (sliderlen > maxlen)
+ sliderlen = maxlen;
+ } else {
+ sliderlen = maxlen;
+ }
+
+ int sliderstart = sbextent + sliderPositionFromValue(scrollbar->minimum,
+ scrollbar->maximum,
+ scrollbar->sliderPosition,
+ maxlen - sliderlen,
+ scrollbar->upsideDown);
+
+ switch (sc) {
+ case SC_ScrollBarSubLine: // top/left button
+ if (scrollbar->orientation == Qt::Horizontal) {
+ int buttonWidth = qMin(scrollBarRect.width() / 2, sbextent);
+ ret.setRect(0, 0, buttonWidth, scrollBarRect.height());
+ } else {
+ int buttonHeight = qMin(scrollBarRect.height() / 2, sbextent);
+ ret.setRect(0, 0, scrollBarRect.width(), buttonHeight);
+ }
+ break;
+ case SC_ScrollBarAddLine: // bottom/right button
+ if (scrollbar->orientation == Qt::Horizontal) {
+ int buttonWidth = qMin(scrollBarRect.width()/2, sbextent);
+ ret.setRect(scrollBarRect.width() - buttonWidth, 0, buttonWidth, scrollBarRect.height());
+ } else {
+ int buttonHeight = qMin(scrollBarRect.height()/2, sbextent);
+ ret.setRect(0, scrollBarRect.height() - buttonHeight, scrollBarRect.width(), buttonHeight);
+ }
+ break;
+ case SC_ScrollBarSubPage: // between top/left button and slider
+ if (scrollbar->orientation == Qt::Horizontal)
+ ret.setRect(sbextent, 0, sliderstart - sbextent, scrollBarRect.height());
+ else
+ ret.setRect(0, sbextent, scrollBarRect.width(), sliderstart - sbextent);
+ break;
+ case SC_ScrollBarAddPage: // between bottom/right button and slider
+ if (scrollbar->orientation == Qt::Horizontal)
+ ret.setRect(sliderstart + sliderlen, 0,
+ maxlen - sliderstart - sliderlen + sbextent, scrollBarRect.height());
+ else
+ ret.setRect(0, sliderstart + sliderlen, scrollBarRect.width(),
+ maxlen - sliderstart - sliderlen + sbextent);
+ break;
+ case SC_ScrollBarGroove:
+ if (scrollbar->orientation == Qt::Horizontal)
+ ret.setRect(sbextent, 0, scrollBarRect.width() - sbextent * 2,
+ scrollBarRect.height());
+ else
+ ret.setRect(0, sbextent, scrollBarRect.width(),
+ scrollBarRect.height() - sbextent * 2);
+ break;
+ case SC_ScrollBarSlider:
+ if (scrollbar->orientation == Qt::Horizontal)
+ ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height());
+ else
+ ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen);
+ break;
+ default:
+ break;
+ }
+ ret = visualRect(scrollbar->direction, scrollBarRect, ret);
+ }
+ break;
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ QSize bs;
+ int fw = spinbox->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, spinbox) : 0;
+ bs.setHeight(qMax(8, spinbox->rect.height()/2 - fw));
+ // 1.6 -approximate golden mean
+ bs.setWidth(qMax(16, qMin(bs.height() * 8 / 5, spinbox->rect.width() / 4)));
+ int y = fw + spinbox->rect.y();
+ int x, lx, rx;
+ x = spinbox->rect.x() + spinbox->rect.width() - fw - bs.width();
+ lx = fw;
+ rx = x - fw;
+ switch (sc) {
+ case SC_SpinBoxUp:
+ if (spinbox->buttonSymbols == QStyleOptionSpinBox::NoButtons)
+ return QRect();
+ ret = QRect(x, y, bs.width(), bs.height());
+ break;
+ case SC_SpinBoxDown:
+ if (spinbox->buttonSymbols == QStyleOptionSpinBox::NoButtons)
+ return QRect();
+
+ ret = QRect(x, y + bs.height(), bs.width(), bs.height());
+ break;
+ case SC_SpinBoxEditField:
+ if (spinbox->buttonSymbols == QStyleOptionSpinBox::NoButtons) {
+ ret = QRect(lx, fw, spinbox->rect.width() - 2*fw, spinbox->rect.height() - 2*fw);
+ } else {
+ ret = QRect(lx, fw, rx, spinbox->rect.height() - 2*fw);
+ }
+ break;
+ case SC_SpinBoxFrame:
+ ret = spinbox->rect;
+ default:
+ break;
+ }
+ ret = visualRect(spinbox->direction, spinbox->rect, ret);
+ }
+ break;
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *tb = qstyleoption_cast<const QStyleOptionToolButton *>(opt)) {
+ int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, tb);
+ ret = tb->rect;
+ switch (sc) {
+ case SC_ToolButton:
+ if ((tb->features
+ & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay))
+ == QStyleOptionToolButton::MenuButtonPopup)
+ ret.adjust(0, 0, -mbi, 0);
+ break;
+ case SC_ToolButtonMenu:
+ if ((tb->features
+ & (QStyleOptionToolButton::MenuButtonPopup | QStyleOptionToolButton::PopupDelay))
+ == QStyleOptionToolButton::MenuButtonPopup)
+ ret.adjust(ret.width() - mbi, 0, 0, 0);
+ break;
+ default:
+ break;
+ }
+ ret = visualRect(tb->direction, tb->rect, ret);
+ }
+ break;
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ const qreal dpi = QStyleHelper::dpi(opt);
+ const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
+ const int margin = cb->frame ? qRound(QStyleHelper::dpiScaled(3, dpi)) : 0;
+ const int bmarg = cb->frame ? qRound(QStyleHelper::dpiScaled(2, dpi)) : 0;
+ const int xpos = x + wi - bmarg - qRound(QStyleHelper::dpiScaled(16, dpi));
+
+
+ switch (sc) {
+ case SC_ComboBoxFrame:
+ ret = cb->rect;
+ break;
+ case SC_ComboBoxArrow:
+ ret.setRect(xpos, y + bmarg, qRound(QStyleHelper::dpiScaled(16, opt)), he - 2*bmarg);
+ break;
+ case SC_ComboBoxEditField:
+ ret.setRect(x + margin, y + margin, wi - 2 * margin - qRound(QStyleHelper::dpiScaled(16, dpi)), he - 2 * margin);
+ break;
+ case SC_ComboBoxListBoxPopup:
+ ret = cb->rect;
+ break;
+ default:
+ break;
+ }
+ ret = visualRect(cb->direction, cb->rect, ret);
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ const int controlMargin = 2;
+ const int controlHeight = tb->rect.height() - controlMargin *2;
+ const int delta = controlHeight + controlMargin;
+ int offset = 0;
+
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+
+ switch (sc) {
+ case SC_TitleBarLabel:
+ if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) {
+ ret = tb->rect;
+ if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
+ ret.adjust(delta, 0, -delta, 0);
+ if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ ret.adjust(0, 0, -delta, 0);
+ if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ ret.adjust(0, 0, -delta, 0);
+ if (tb->titleBarFlags & Qt::WindowShadeButtonHint)
+ ret.adjust(0, 0, -delta, 0);
+ if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ ret.adjust(0, 0, -delta, 0);
+ }
+ break;
+ case SC_TitleBarContextHelpButton:
+ if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ offset += delta;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMinButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (sc == SC_TitleBarMinButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (sc == SC_TitleBarNormalButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (sc == SC_TitleBarMaxButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarShadeButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (sc == SC_TitleBarShadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarUnshadeButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (sc == SC_TitleBarUnshadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarCloseButton:
+ if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
+ offset += delta;
+ else if (sc == SC_TitleBarCloseButton)
+ break;
+ ret.setRect(tb->rect.right() - offset, tb->rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ break;
+ case SC_TitleBarSysMenu:
+ if (tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ ret.setRect(tb->rect.left() + controlMargin, tb->rect.top() + controlMargin,
+ controlHeight, controlHeight);
+ }
+ break;
+ default:
+ break;
+ }
+ ret = visualRect(tb->direction, tb->rect, ret);
+ }
+ break;
+ case CC_GroupBox: {
+ if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ switch (sc) {
+ case SC_GroupBoxFrame:
+ case SC_GroupBoxContents: {
+ int topMargin = 0;
+ int topHeight = 0;
+ int verticalAlignment = proxy()->styleHint(SH_GroupBox_TextLabelVerticalAlignment, groupBox);
+ bool hasCheckBox = groupBox->subControls & QStyle::SC_GroupBoxCheckBox;
+ if (groupBox->text.size() || hasCheckBox) {
+ int checkBoxHeight = hasCheckBox ? proxy()->pixelMetric(PM_IndicatorHeight, groupBox) : 0;
+ topHeight = qMax(groupBox->fontMetrics.height(), checkBoxHeight);
+ if (verticalAlignment & Qt::AlignVCenter)
+ topMargin = topHeight / 2;
+ else if (verticalAlignment & Qt::AlignTop)
+ topMargin = topHeight;
+ }
+
+ QRect frameRect = groupBox->rect;
+ frameRect.setTop(topMargin);
+
+ if (sc == SC_GroupBoxFrame) {
+ ret = frameRect;
+ break;
+ }
+
+ int frameWidth = 0;
+ if ((groupBox->features & QStyleOptionFrame::Flat) == 0)
+ frameWidth = proxy()->pixelMetric(PM_DefaultFrameWidth, groupBox);
+ ret = frameRect.adjusted(frameWidth, frameWidth + topHeight - topMargin,
+ -frameWidth, -frameWidth);
+ break;
+ }
+ case SC_GroupBoxCheckBox:
+ case SC_GroupBoxLabel: {
+ QFontMetrics fontMetrics = groupBox->fontMetrics;
+ int th = fontMetrics.height();
+ int tw = fontMetrics.size(Qt::TextShowMnemonic, groupBox->text + QLatin1Char(' ')).width();
+ int marg = (groupBox->features & QStyleOptionFrame::Flat) ? 0 : 8;
+ ret = groupBox->rect.adjusted(marg, 0, -marg, 0);
+
+ int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, opt);
+ int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, opt);
+ int indicatorSpace = proxy()->pixelMetric(PM_CheckBoxLabelSpacing, opt) - 1;
+ bool hasCheckBox = groupBox->subControls & QStyle::SC_GroupBoxCheckBox;
+ int checkBoxWidth = hasCheckBox ? (indicatorWidth + indicatorSpace) : 0;
+ int checkBoxHeight = hasCheckBox ? indicatorHeight : 0;
+
+ int h = qMax(th, checkBoxHeight);
+ ret.setHeight(h);
+
+ // Adjusted rect for label + indicatorWidth + indicatorSpace
+ QRect totalRect = alignedRect(groupBox->direction, groupBox->textAlignment,
+ QSize(tw + checkBoxWidth, h), ret);
+
+ // Adjust totalRect if checkbox is set
+ if (hasCheckBox) {
+ bool ltr = groupBox->direction == Qt::LeftToRight;
+ int left = 0;
+ // Adjust for check box
+ if (sc == SC_GroupBoxCheckBox) {
+ left = ltr ? totalRect.left() : (totalRect.right() - indicatorWidth);
+ int top = totalRect.top() + (h - checkBoxHeight) / 2;
+ totalRect.setRect(left, top, indicatorWidth, indicatorHeight);
+ // Adjust for label
+ } else {
+ left = ltr ? (totalRect.left() + checkBoxWidth - 2) : totalRect.left();
+ int top = totalRect.top() + (h - th) / 2;
+ totalRect.setRect(left, top, totalRect.width() - checkBoxWidth, th);
+ }
+ }
+ ret = totalRect;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ case CC_MdiControls:
+ {
+ int numSubControls = 0;
+ if (opt->subControls & SC_MdiCloseButton)
+ ++numSubControls;
+ if (opt->subControls & SC_MdiMinButton)
+ ++numSubControls;
+ if (opt->subControls & SC_MdiNormalButton)
+ ++numSubControls;
+ if (numSubControls == 0)
+ break;
+
+ int buttonWidth = opt->rect.width() / numSubControls - 1;
+ int offset = 0;
+ switch (sc) {
+ case SC_MdiCloseButton:
+ // Only one sub control, no offset needed.
+ if (numSubControls == 1)
+ break;
+ offset += buttonWidth + 2;
+ Q_FALLTHROUGH();
+ case SC_MdiNormalButton:
+ // No offset needed if
+ // 1) There's only one sub control
+ // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
+ if (numSubControls == 1 || (numSubControls == 2 && !(opt->subControls & SC_MdiMinButton)))
+ break;
+ if (opt->subControls & SC_MdiNormalButton)
+ offset += buttonWidth;
+ break;
+ default:
+ break;
+ }
+
+ // Subtract one pixel if we only have one sub control. At this point
+ // buttonWidth is the actual width + 1 pixel margin, but we don't want the
+ // margin when there are no other controllers.
+ if (numSubControls == 1)
+ --buttonWidth;
+ ret = QRect(offset, 0, buttonWidth, opt->rect.height());
+ break; }
+ default:
+ qWarning("QCommonStyle::subControlRect: Case %d not handled", cc);
+ }
+
+ return ret;
+}
+
+int QCommonStyle::pixelMetric(PixelMetric m, const QStyleOption *opt) const
+{
+ int ret;
+
+ switch (m) {
+ case PM_FocusFrameVMargin:
+ case PM_FocusFrameHMargin:
+ ret = 2;
+ break;
+ case PM_MenuBarVMargin:
+ case PM_MenuBarHMargin:
+ ret = 0;
+ break;
+ case PM_DialogButtonsSeparator:
+ ret = int(QStyleHelper::dpiScaled(5, opt));
+ break;
+ case PM_DialogButtonsButtonWidth:
+ ret = int(QStyleHelper::dpiScaled(70, opt));
+ break;
+ case PM_DialogButtonsButtonHeight:
+ ret = int(QStyleHelper::dpiScaled(30, opt));
+ break;
+ case PM_TitleBarHeight: {
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool) {
+ ret = qMax(opt->fontMetrics.height(), 16);
+ } else {
+ ret = qMax(opt->fontMetrics.height(), 18);
+ }
+ } else {
+ ret = int(QStyleHelper::dpiScaled(18., opt));
+ }
+
+ break; }
+ case PM_TitleBarButtonSize:
+ ret = int(QStyleHelper::dpiScaled(16., opt));
+ break;
+ case PM_TitleBarButtonIconSize:
+ ret = int(QStyleHelper::dpiScaled(16., opt));
+ break;
+
+ case PM_ScrollBarSliderMin:
+ ret = int(QStyleHelper::dpiScaled(9., opt));
+ break;
+
+ case PM_ButtonMargin:
+ ret = int(QStyleHelper::dpiScaled(6., opt));
+ break;
+
+ case PM_DockWidgetTitleBarButtonMargin:
+ ret = int(QStyleHelper::dpiScaled(2., opt));
+ break;
+
+ case PM_ButtonDefaultIndicator:
+ ret = 0;
+ break;
+
+ case PM_MenuButtonIndicator:
+ ret = int(QStyleHelper::dpiScaled(12, opt));
+ break;
+
+ case PM_ButtonShiftHorizontal:
+ case PM_ButtonShiftVertical:
+
+ case PM_DefaultFrameWidth:
+ ret = 2;
+ break;
+
+ case PM_ComboBoxFrameWidth:
+ case PM_SpinBoxFrameWidth:
+ case PM_MenuPanelWidth:
+ case PM_TabBarBaseOverlap:
+ case PM_TabBarBaseHeight:
+ ret = proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ break;
+ case PM_MdiSubWindowFrameWidth:
+ ret = int(QStyleHelper::dpiScaled(4, opt));
+ break;
+ case PM_MdiSubWindowMinimizedWidth:
+ ret = int(QStyleHelper::dpiScaled(196, opt));
+ break;
+ case PM_ScrollBarExtent:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_MaximumDragDistance:
+ ret = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::MaximumScrollBarDragDistance).toInt();
+ break;
+ case PM_SliderThickness:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_SliderTickmarkOffset:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height()
+ : sl->rect.width();
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, sl);
+ int ticks = sl->tickPosition;
+
+ if (ticks == QStyleOptionSlider::TicksBothSides)
+ ret = (space - thickness) / 2;
+ else if (ticks == QStyleOptionSlider::TicksAbove)
+ ret = space - thickness;
+ else
+ ret = 0;
+ } else {
+ ret = 0;
+ }
+ break;
+ case PM_SliderSpaceAvailable:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ if (sl->orientation == Qt::Horizontal)
+ ret = sl->rect.width() - proxy()->pixelMetric(PM_SliderLength, sl);
+ else
+ ret = sl->rect.height() - proxy()->pixelMetric(PM_SliderLength, sl);
+ } else {
+ ret = 0;
+ }
+ break;
+ case PM_DockWidgetSeparatorExtent:
+ ret = int(QStyleHelper::dpiScaled(6, opt));
+ break;
+
+ case PM_DockWidgetHandleExtent:
+ ret = int(QStyleHelper::dpiScaled(8, opt));
+ break;
+ case PM_DockWidgetTitleMargin:
+ ret = 0;
+ break;
+ case PM_DockWidgetFrameWidth:
+ ret = 1;
+ break;
+ case PM_SpinBoxSliderHeight:
+ case PM_MenuBarPanelWidth:
+ ret = 2;
+ break;
+ case PM_MenuBarItemSpacing:
+ ret = 0;
+ break;
+ case PM_ToolBarFrameWidth:
+ ret = 1;
+ break;
+
+ case PM_ToolBarItemMargin:
+ ret = 0;
+ break;
+
+ case PM_ToolBarItemSpacing:
+ ret = int(QStyleHelper::dpiScaled(4, opt));
+ break;
+
+ case PM_ToolBarHandleExtent:
+ ret = int(QStyleHelper::dpiScaled(8, opt));
+ break;
+
+ case PM_ToolBarSeparatorExtent:
+ ret = int(QStyleHelper::dpiScaled(6, opt));
+ break;
+
+ case PM_ToolBarExtensionExtent:
+ ret = int(QStyleHelper::dpiScaled(12, opt));
+ break;
+
+ case PM_TabBarTabOverlap:
+ ret = 3;
+ break;
+
+ case PM_TabBarTabHSpace:
+ ret = int(QStyleHelper::dpiScaled(24, opt));
+ break;
+
+ case PM_TabBarTabShiftHorizontal:
+ ret = 0;
+ break;
+
+ case PM_TabBarTabShiftVertical:
+ ret = 2;
+ break;
+
+ case PM_TabBarTabVSpace: {
+ const QStyleOptionTab *tb = qstyleoption_cast<const QStyleOptionTab *>(opt);
+ if (tb && (tb->shape == QStyleOptionTab::RoundedNorth || tb->shape == QStyleOptionTab::RoundedSouth
+ || tb->shape == QStyleOptionTab::RoundedWest || tb->shape == QStyleOptionTab::RoundedEast))
+ ret = 8;
+ else
+ if(tb && (tb->shape == QStyleOptionTab::TriangularWest || tb->shape == QStyleOptionTab::TriangularEast))
+ ret = 3;
+ else
+ ret = 2;
+ break; }
+
+ case PM_ProgressBarChunkWidth:
+ ret = 9;
+ break;
+
+ case PM_IndicatorWidth:
+ ret = int(QStyleHelper::dpiScaled(13, opt));
+ break;
+
+ case PM_IndicatorHeight:
+ ret = int(QStyleHelper::dpiScaled(13, opt));
+ break;
+
+ case PM_ExclusiveIndicatorWidth:
+ ret = int(QStyleHelper::dpiScaled(12, opt));
+ break;
+
+ case PM_ExclusiveIndicatorHeight:
+ ret = int(QStyleHelper::dpiScaled(12, opt));
+ break;
+
+ case PM_MenuTearoffHeight:
+ ret = int(QStyleHelper::dpiScaled(10, opt));
+ break;
+
+ case PM_MenuScrollerHeight:
+ ret = int(QStyleHelper::dpiScaled(10, opt));
+ break;
+
+ case PM_MenuDesktopFrameWidth:
+ case PM_MenuHMargin:
+ case PM_MenuVMargin:
+ ret = 0;
+ break;
+
+ case PM_HeaderMargin:
+ ret = int(QStyleHelper::dpiScaled(4, opt));
+ break;
+ case PM_HeaderMarkSize:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_HeaderGripMargin:
+ ret = int(QStyleHelper::dpiScaled(4, opt));
+ break;
+ case PM_HeaderDefaultSectionSizeHorizontal:
+ ret = int(QStyleHelper::dpiScaled(100, opt));
+ break;
+ case PM_HeaderDefaultSectionSizeVertical:
+ ret = int(QStyleHelper::dpiScaled(30, opt));
+ break;
+ case PM_TabBarScrollButtonWidth:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_LayoutLeftMargin:
+ case PM_LayoutTopMargin:
+ case PM_LayoutRightMargin:
+ case PM_LayoutBottomMargin:
+ {
+ bool isWindow = opt ? (opt->state & State_Window) : false;
+ ret = proxy()->pixelMetric(isWindow ? PM_DefaultTopLevelMargin : PM_DefaultChildMargin);
+ }
+ break;
+ case PM_LayoutHorizontalSpacing:
+ case PM_LayoutVerticalSpacing:
+ ret = proxy()->pixelMetric(PM_DefaultLayoutSpacing);
+ break;
+
+ case PM_DefaultTopLevelMargin:
+ ret = int(QStyleHelper::dpiScaled(11, opt));
+ break;
+ case PM_DefaultChildMargin:
+ ret = int(QStyleHelper::dpiScaled(9, opt));
+ break;
+ case PM_DefaultLayoutSpacing:
+ ret = int(QStyleHelper::dpiScaled(6, opt));
+ break;
+
+ case PM_ToolBarIconSize:
+ ret = 0;
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ ret = theme->themeHint(QPlatformTheme::ToolBarIconSize).toInt();
+ if (ret <= 0)
+ ret = int(QStyleHelper::dpiScaled(24, opt));
+ break;
+
+ case PM_TabBarIconSize:
+ case PM_ListViewIconSize:
+ ret = proxy()->pixelMetric(PM_SmallIconSize, opt);
+ break;
+
+ case PM_ButtonIconSize:
+ case PM_SmallIconSize:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_IconViewIconSize:
+ ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
+ break;
+
+ case PM_LargeIconSize:
+ ret = int(QStyleHelper::dpiScaled(32, opt));
+ break;
+
+ case PM_ToolTipLabelFrameWidth:
+ ret = 1;
+ break;
+ case PM_CheckBoxLabelSpacing:
+ case PM_RadioButtonLabelSpacing:
+ ret = int(QStyleHelper::dpiScaled(6, opt));
+ break;
+ case PM_SizeGripSize:
+ ret = int(QStyleHelper::dpiScaled(13, opt));
+ break;
+ case PM_MessageBoxIconSize:
+#ifdef Q_OS_MAC
+ if (QGuiApplication::desktopSettingsAware()) {
+ ret = 64; // No DPI scaling, it's handled elsewhere.
+ } else
+#endif
+ {
+ ret = int(QStyleHelper::dpiScaled(32, opt));
+ }
+ break;
+ case PM_TextCursorWidth:
+ ret = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TextCursorWidth).toInt();
+ break;
+ case PM_TabBar_ScrollButtonOverlap:
+ ret = 1;
+ break;
+ case PM_TabCloseIndicatorWidth:
+ case PM_TabCloseIndicatorHeight:
+ ret = int(QStyleHelper::dpiScaled(16, opt));
+ break;
+ case PM_ScrollView_ScrollBarSpacing:
+ ret = 2 * proxy()->pixelMetric(PM_DefaultFrameWidth, opt);
+ break;
+ case PM_ScrollView_ScrollBarOverlap:
+ ret = 0;
+ break;
+ case PM_SubMenuOverlap:
+ ret = -proxy()->pixelMetric(QStyle::PM_MenuPanelWidth, opt);
+ break;
+ case PM_TreeViewIndentation:
+ ret = int(QStyleHelper::dpiScaled(20, opt));
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+QSize QCommonStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz) const
+{
+ Q_D(const QCommonStyle);
+ QSize sz(!csz.isEmpty() ? csz : QSize(0,0));
+
+ switch (ct) {
+ case CT_PushButton:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ int w = sz.width(),
+ h = sz.height(),
+ bm = proxy()->pixelMetric(PM_ButtonMargin, btn),
+ fw = proxy()->pixelMetric(PM_DefaultFrameWidth, btn) * 2;
+ w += bm + fw;
+ h += bm + fw;
+ if (btn->features & QStyleOptionButton::AutoDefaultButton){
+ int dbw = proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn) * 2;
+ w += dbw;
+ h += dbw;
+ }
+ sz = QSize(w, h);
+ }
+ break;
+ case CT_RadioButton:
+ case CT_CheckBox:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ bool isRadio = (ct == CT_RadioButton);
+
+ int w = proxy()->pixelMetric(isRadio ? PM_ExclusiveIndicatorWidth
+ : PM_IndicatorWidth, btn);
+ int h = proxy()->pixelMetric(isRadio ? PM_ExclusiveIndicatorHeight
+ : PM_IndicatorHeight, btn);
+
+ int margins = 0;
+ // we add 4 pixels for label margins
+ if (!btn->icon.isNull() || !btn->text.isEmpty())
+ margins = 4 + proxy()->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing
+ : PM_CheckBoxLabelSpacing, opt);
+ sz += QSize(w + margins, 4);
+ sz.setHeight(qMax(sz.height(), h));
+ }
+ break;
+ case CT_MenuItem:
+ if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ bool checkable = mi->menuHasCheckableItems;
+ int maxpmw = mi->maxIconWidth;
+ int w = sz.width(), h = sz.height();
+ if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
+ w = 10;
+ h = 2;
+ } else {
+ h = mi->fontMetrics.height() + 8;
+ if (!mi->icon.isNull()) {
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize);
+ h = qMax(h, mi->icon.actualSize(QSize(iconExtent, iconExtent)).height() + 4);
+ }
+ }
+ if (mi->text.contains(QLatin1Char('\t')))
+ w += 12;
+ if (maxpmw > 0)
+ w += maxpmw + 6;
+ if (checkable && maxpmw < 20)
+ w += 20 - maxpmw;
+ if (checkable || maxpmw > 0)
+ w += 2;
+ w += 12;
+ sz = QSize(w, h);
+ }
+ break;
+ case CT_ToolButton:
+ sz = QSize(sz.width() + 6, sz.height() + 5);
+ break;
+ case CT_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ int fw = cmb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, opt) * 2 : 0;
+ const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin) + 1);
+ // QItemDelegate::sizeHint expands the textMargins two times, thus the 2*textMargins...
+ int other = qMax(23, 2*textMargins + proxy()->pixelMetric(QStyle::PM_ScrollBarExtent, opt));
+ sz = QSize(sz.width() + fw + other, sz.height() + fw);
+ }
+ break;
+ case CT_HeaderSection:
+ if (const QStyleOptionHeader *hdr = qstyleoption_cast<const QStyleOptionHeader *>(opt)) {
+ bool nullIcon = hdr->icon.isNull();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, hdr);
+ int iconSize = nullIcon ? 0 : proxy()->pixelMetric(QStyle::PM_SmallIconSize, hdr);
+ QSize txt = hdr->fontMetrics.size(0, hdr->text);
+ sz.setHeight(margin + qMax(iconSize, txt.height()) + margin);
+ sz.setWidth((nullIcon ? 0 : margin) + iconSize
+ + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin);
+ if (hdr->sortIndicator != QStyleOptionHeader::None) {
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, hdr);
+ if (hdr->orientation == Qt::Horizontal)
+ sz.rwidth() += sz.height() + margin;
+ else
+ sz.rheight() += sz.width() + margin;
+ }
+ }
+ break;
+ case CT_TabWidget:
+ sz += QSize(4, 4);
+ break;
+ case CT_LineEdit:
+ if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ const int borderSize = 2 * f->lineWidth;
+ sz += QSize(borderSize, borderSize);
+ const int minSize = 10;
+ if (sz.width() < minSize)
+ sz.rwidth() = minSize;
+ if (sz.height() < minSize)
+ sz.rheight() = minSize;
+ }
+ break;
+ case CT_GroupBox:
+ if (const QStyleOptionGroupBox *styleOpt = qstyleoption_cast<const QStyleOptionGroupBox *>(opt)) {
+ if (sz.isEmpty())
+ sz = QSize(20, 20);
+ sz += QSize(styleOpt->features.testFlag(QStyleOptionFrame::Flat) ? 0 : 16, 0);
+ }
+ break;
+ case CT_MdiControls:
+ if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(opt)) {
+ const int buttonSize = proxy()->pixelMetric(PM_TitleBarButtonSize, styleOpt);
+ int width = 1;
+ if (styleOpt->subControls & SC_MdiMinButton)
+ width += buttonSize + 1;
+ if (styleOpt->subControls & SC_MdiNormalButton)
+ width += buttonSize + 1;
+ if (styleOpt->subControls & SC_MdiCloseButton)
+ width += buttonSize + 1;
+ sz = QSize(width, buttonSize);
+ } else {
+ const int buttonSize = proxy()->pixelMetric(PM_TitleBarButtonSize, opt);
+ sz = QSize(1 + 3 * (buttonSize + 1), buttonSize);
+ }
+ break;
+ case CT_ItemViewItem:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(opt)) {
+ QRect decorationRect, displayRect, checkRect;
+ d->viewItemLayout(vopt, &checkRect, &decorationRect, &displayRect, true);
+ sz = (decorationRect|displayRect|checkRect).size();
+ if (decorationRect.isValid() && sz.height() == decorationRect.height())
+ sz.rheight() += 2; // Prevent icons from overlapping.
+ }
+ break;
+ case CT_SpinBox:
+ if (const QStyleOptionSpinBox *vopt = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ // Add button + frame widths
+ if (vopt->subControls == SC_SpinBoxFrame) {
+ const qreal dpi = QStyleHelper::dpi(opt);
+ const bool hasButtons = (vopt->buttonSymbols != QStyleOptionSpinBox::NoButtons);
+ const int buttonWidth = hasButtons ? qRound(QStyleHelper::dpiScaled(16, dpi)) : 0;
+ const int fw = vopt->frame ? proxy()->pixelMetric(PM_SpinBoxFrameWidth, vopt) : 0;
+ sz += QSize(buttonWidth + 2*fw, 1 + 2*fw);
+ } else {
+ const QSize buttonSize = proxy()->subControlRect(CC_SpinBox, vopt, SC_SpinBoxUp).size();
+ const int upAndDownTogetherHeight = buttonSize.height() * 2;
+ sz += QSize(buttonSize.width(), upAndDownTogetherHeight);
+ }
+ }
+ break;
+ case CT_Slider:
+ if (const QStyleOptionSlider *option = qstyleoption_cast<const QStyleOptionSlider *>(opt))
+ sz = subControlRect(QStyle::CC_Slider, option, QStyle::SC_SliderHandle).size();
+ break;
+ case CT_Dial:
+ sz = QSize(20, 20);
+ break;
+ case CT_Frame:
+ if (const QStyleOptionFrame *option = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ const int ninePatchSplit = 1;
+ int w = qMax(10, (option->lineWidth * 2) + ninePatchSplit);
+ sz = QSize(w, w);
+ }
+ break;
+ case CT_ProgressBar:
+ if (sz.isNull()) {
+ // Special case: return minimum nine patch image size
+ sz = QSize(10, 10);
+ }
+ break;
+ case CT_ScrollBar:
+ case CT_MenuBar:
+ case CT_Menu:
+ case CT_MenuBarItem:
+ case CT_TabBarTab:
+ // just return the contentsSize for now
+ Q_FALLTHROUGH();
+ default:
+ break;
+ }
+ return sz;
+}
+
+QFont QCommonStyle::font(QStyle::ControlElement element, const QStyle::State state) const
+{
+ Q_UNUSED(element);
+ Q_UNUSED(state);
+ return QGuiApplication::font();
+}
+
+QMargins QCommonStyle::ninePatchMargins(QStyle::ControlElement /*ce*/, const QStyleOption * /*opt*/, const QSize &imageSize) const
+{
+ // By default, we just divide the image at the center
+ int w = imageSize.width() / 2;
+ int h = imageSize.height() / 2;
+ return QMargins(w, h, w, h);
+}
+
+QMargins QCommonStyle::ninePatchMargins(QStyle::ComplexControl /*cc*/, const QStyleOptionComplex * /*opt*/, const QSize &imageSize) const
+{
+ // By default, we just divide the image at the center
+ int w = imageSize.width() / 2;
+ int h = imageSize.height() / 2;
+ return QMargins(w, h, w, h);
+}
+
+int QCommonStyle::styleHint(StyleHint sh, const QStyleOption *opt, QStyleHintReturn *hret) const
+{
+ int ret = 0;
+
+ switch (sh) {
+ case SH_Menu_KeyboardSearch:
+ ret = false;
+ break;
+ case SH_Slider_AbsoluteSetButtons:
+ ret = Qt::MiddleButton;
+ break;
+ case SH_Slider_PageSetButtons:
+ ret = Qt::LeftButton;
+ break;
+ case SH_ScrollBar_ContextMenu:
+ ret = true;
+ break;
+ case SH_GroupBox_TextLabelVerticalAlignment:
+ ret = Qt::AlignVCenter;
+ break;
+ case SH_GroupBox_TextLabelColor:
+ ret = opt ? int(opt->palette.color(QPalette::Text).rgba()) : 0;
+ break;
+
+ case SH_ListViewExpand_SelectMouseType:
+ case SH_TabBar_SelectMouseType:
+ ret = QEvent::MouseButtonPress;
+ break;
+
+ case SH_TabBar_Alignment:
+ ret = Qt::AlignLeft;
+ break;
+
+ case SH_Header_ArrowAlignment:
+ ret = Qt::AlignRight | Qt::AlignVCenter;
+ break;
+
+ case SH_TitleBar_AutoRaise:
+ ret = false;
+ break;
+
+ case SH_Menu_SubMenuPopupDelay:
+ ret = 256;
+ break;
+
+ case SH_Menu_SloppySubMenus:
+ ret = true;
+ break;
+
+ case SH_Menu_SubMenuUniDirection:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuUniDirectionFailCount:
+ ret = 1;
+ break;
+ case SH_Menu_SubMenuSloppySelectOtherActions:
+ ret = true;
+ break;
+ case SH_Menu_SubMenuSloppyCloseTimeout:
+ ret = 1000;
+ break;
+ case SH_Menu_SubMenuResetWhenReenteringParent:
+ ret = false;
+ break;
+ case SH_Menu_SubMenuDontStartSloppyOnLeave:
+ ret = false;
+ break;
+
+ case SH_ProgressDialog_TextLabelAlignment:
+ ret = Qt::AlignCenter;
+ break;
+
+ case SH_BlinkCursorWhenTextSelected:
+#if defined(Q_OS_DARWIN)
+ ret = 0;
+#else
+ ret = 1;
+#endif
+ break;
+
+ case SH_Table_GridLineColor:
+ if (opt)
+ ret = opt->palette.color(QPalette::Mid).rgba();
+ else
+ ret = -1;
+ break;
+ case SH_LineEdit_PasswordCharacter: {
+ const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
+ const QPlatformTheme::ThemeHint hintType = QPlatformTheme::PasswordMaskCharacter;
+ const QVariant hint = theme ? theme->themeHint(hintType) : QPlatformTheme::defaultThemeHint(hintType);
+ ret = hint.toChar().unicode();
+ break;
+ }
+ case SH_LineEdit_PasswordMaskDelay:
+ ret = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::PasswordMaskDelay).toInt();
+ break;
+ case SH_ToolBox_SelectedPageTitleBold:
+ ret = 1;
+ break;
+
+ case SH_UnderlineShortcut:
+ ret = 1;
+ break;
+
+ case SH_SpinBox_ClickAutoRepeatRate:
+ ret = 150;
+ break;
+
+ case SH_SpinBox_ClickAutoRepeatThreshold:
+ ret = 500;
+ break;
+
+ case SH_SpinBox_KeyPressAutoRepeatRate:
+ ret = 75;
+ break;
+
+ case SH_Menu_SelectionWrap:
+ ret = true;
+ break;
+
+ case SH_Menu_FillScreenWithScroll:
+ ret = true;
+ break;
+
+ case SH_ToolTipLabel_Opacity:
+ ret = 255;
+ break;
+
+ case SH_Button_FocusPolicy:
+ ret = Qt::StrongFocus;
+ break;
+
+ case SH_MessageBox_UseBorderForButtonSpacing:
+ ret = 0;
+ break;
+
+ case SH_ToolButton_PopupDelay:
+ ret = 600;
+ break;
+
+ case SH_FocusFrame_Mask:
+ ret = 1;
+ break;
+ case SH_RubberBand_Mask:
+ if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
+ ret = 0;
+ if (rbOpt->shape == QStyleOptionRubberBand::Rectangle) {
+ ret = true;
+ if(QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(hret)) {
+ mask->region = opt->rect;
+ int margin = proxy()->pixelMetric(PM_DefaultFrameWidth) * 2;
+ mask->region -= opt->rect.adjusted(margin, margin, -margin, -margin);
+ }
+ }
+ }
+ break;
+ case SH_SpinControls_DisableOnBounds:
+ ret = 1;
+ break;
+
+ case SH_Dial_BackgroundRole:
+ ret = QPalette::Window;
+ break;
+
+ case SH_ComboBox_LayoutDirection:
+ ret = opt ? opt->direction : Qt::LeftToRight;
+ break;
+
+ case SH_ItemView_EllipsisLocation:
+ ret = Qt::AlignTrailing;
+ break;
+
+ case SH_ItemView_ShowDecorationSelected:
+ ret = false;
+ break;
+
+ case SH_ItemView_ActivateItemOnSingleClick:
+ ret = 0;
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ ret = theme->themeHint(QPlatformTheme::ItemViewActivateItemOnSingleClick).toBool() ? 1 : 0;
+ break;
+ case SH_TitleBar_ModifyNotification:
+ ret = true;
+ break;
+ case SH_ScrollBar_RollBetweenButtons:
+ ret = false;
+ break;
+ case SH_TabBar_ElideMode:
+ ret = Qt::ElideNone;
+ break;
+ case SH_DialogButtonLayout:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ ret = theme->themeHint(QPlatformTheme::DialogButtonBoxLayout).toInt();
+ break;
+ case SH_ComboBox_PopupFrameStyle:
+ ret = QStyleOptionFrame::StyledPanel | QStyleOptionFrame::Plain;
+ break;
+ case SH_MessageBox_TextInteractionFlags:
+ ret = Qt::LinksAccessibleByMouse;
+ break;
+ case SH_DialogButtonBox_ButtonsHaveIcons:
+ ret = 0;
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ ret = theme->themeHint(QPlatformTheme::DialogButtonBoxButtonsHaveIcons).toBool() ? 1 : 0;
+ break;
+ case SH_SpellCheckUnderlineStyle:
+ ret = QTextCharFormat::WaveUnderline;
+ break;
+ case SH_MessageBox_CenterButtons:
+ ret = true;
+ break;
+ case SH_ItemView_MovementWithoutUpdatingSelection:
+ ret = true;
+ break;
+ case SH_FocusFrame_AboveWidget:
+ ret = false;
+ break;
+ case SH_TabWidget_DefaultTabPosition:
+ ret = QStyleOptionTabBarBase::North;
+ break;
+ case SH_ToolBar_Movable:
+ ret = true;
+ break;
+ case SH_TextControl_FocusIndicatorTextCharFormat:
+ ret = true;
+ if (QStyleHintReturnVariant *vret = qstyleoption_cast<QStyleHintReturnVariant*>(hret)) {
+ QPen outline(opt->palette.color(QPalette::Text), 1, Qt::DotLine);
+ QTextCharFormat fmt;
+ fmt.setProperty(QTextFormat::OutlinePen, outline);
+ vret->variant = fmt;
+ }
+ break;
+ case SH_WizardStyle:
+ break;
+ case SH_FormLayoutWrapPolicy:
+ break;
+ case SH_FormLayoutFieldGrowthPolicy:
+ break;
+ case SH_FormLayoutFormAlignment:
+ ret = Qt::AlignLeft | Qt::AlignTop;
+ break;
+ case SH_FormLayoutLabelAlignment:
+ ret = Qt::AlignLeft;
+ break;
+ case SH_ItemView_ArrowKeysNavigateIntoChildren:
+ ret = false;
+ break;
+ case SH_ItemView_DrawDelegateFrame:
+ ret = 0;
+ break;
+ case SH_TabBar_CloseButtonPosition:
+ ret = QStyleOptionTabBarBase::RightSide;
+ break;
+ case SH_TabBar_ChangeCurrentDelay:
+ ret = 500;
+ break;
+ case SH_DockWidget_ButtonsHaveFrame:
+ ret = true;
+ break;
+ case SH_ToolButtonStyle:
+ ret = 0;
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ ret = theme->themeHint(QPlatformTheme::ToolButtonStyle).toInt();
+ break;
+ case SH_RequestSoftwareInputPanel:
+ ret = RSIP_OnMouseClick;
+ break;
+ case SH_ScrollBar_Transient:
+ ret = false;
+ break;
+ case SH_Menu_SupportsSections:
+ ret = false;
+ break;
+ case SH_ToolTip_WakeUpDelay:
+ ret = 700;
+ break;
+ case SH_ToolTip_FallAsleepDelay:
+ ret = 2000;
+ break;
+ case SH_Widget_Animate:
+ ret = true;
+ break;
+ case SH_Splitter_OpaqueResize:
+ ret = true;
+ break;
+ case SH_ItemView_ScrollMode:
+ ret = QStyleOptionViewItem::ScrollPerItem;
+ break;
+ case SH_TitleBar_ShowToolTipsOnButtons:
+ ret = true;
+ break;
+ case SH_Widget_Animation_Duration:
+ ret = styleHint(SH_Widget_Animate, opt, hret) ? 200 : 0;
+ break;
+ case SH_ComboBox_AllowWheelScrolling:
+ ret = true;
+ break;
+ case SH_SpinBox_ButtonsInsideFrame:
+ ret = true;
+ break;
+ case SH_SpinBox_StepModifier:
+ ret = Qt::ControlModifier;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+#if QT_CONFIG(imageformat_xpm)
+static QPixmap cachedPixmapFromXPM(const char * const *xpm)
+{
+ QPixmap result;
+ const QString tag = QString::asprintf("xpm:0x%p", static_cast<const void*>(xpm));
+ if (!QPixmapCache::find(tag, &result)) {
+ result = QPixmap(xpm);
+ QPixmapCache::insert(tag, result);
+ }
+ return result;
+}
+
+static inline QPixmap titleBarMenuCachedPixmapFromXPM() { return cachedPixmapFromXPM(qt_menu_xpm); }
+#endif
+
+static inline QString clearText16IconPath()
+{
+ return QStringLiteral(":/qt-project.org/styles/commonstyle/images/cleartext-16.png");
+}
+
+#if defined(Q_OS_WIN) || QT_CONFIG(imageformat_png)
+static QIcon clearTextIcon(bool rtl)
+{
+ const QString directionalThemeName = rtl
+ ? QStringLiteral("edit-clear-locationbar-ltr") : QStringLiteral("edit-clear-locationbar-rtl");
+ if (QIcon::hasThemeIcon(directionalThemeName))
+ return QIcon::fromTheme(directionalThemeName);
+ const QString themeName = QStringLiteral("edit-clear");
+ if (QIcon::hasThemeIcon(themeName))
+ return QIcon::fromTheme(themeName);
+
+ QIcon icon;
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ QPixmap clearText16(clearText16IconPath());
+ Q_ASSERT(!clearText16.size().isEmpty());
+ icon.addPixmap(clearText16);
+ QPixmap clearText32(QStringLiteral(":/qt-project.org/styles/commonstyle/images/cleartext-32.png"));
+ Q_ASSERT(!clearText32.size().isEmpty());
+ icon.addPixmap(clearText32);
+ clearText32.setDevicePixelRatio(2); // The 32x32 pixmap can also be used for 16x16/devicePixelRatio=2
+ icon.addPixmap(clearText32);
+#endif // !QT_NO_IMAGEFORMAT_PNG
+ return icon;
+}
+#endif
+
+QPixmap QCommonStyle::standardPixmap(StandardPixmap sp, const QStyleOption *option) const
+{
+ const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QGuiApplication::isRightToLeft());
+#if QT_CONFIG(imageformat_png)
+ QPixmap pixmap;
+
+ if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) {
+ switch (sp) {
+ case SP_DialogYesButton:
+ case SP_DialogOkButton:
+ pixmap = QIcon::fromTheme(QLatin1String("dialog-ok")).pixmap(16);
+ break;
+ case SP_DialogApplyButton:
+ pixmap = QIcon::fromTheme(QLatin1String("dialog-ok-apply")).pixmap(16);
+ break;
+ case SP_DialogDiscardButton:
+ pixmap = QIcon::fromTheme(QLatin1String("edit-delete")).pixmap(16);
+ break;
+ case SP_DialogCloseButton:
+ pixmap = QIcon::fromTheme(QLatin1String("dialog-close")).pixmap(16);
+ break;
+ case SP_DirHomeIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("user-home")).pixmap(16);
+ break;
+ case SP_MessageBoxInformation:
+ pixmap = QIcon::fromTheme(QLatin1String("messagebox_info")).pixmap(16);
+ break;
+ case SP_MessageBoxWarning:
+ pixmap = QIcon::fromTheme(QLatin1String("messagebox_warning")).pixmap(16);
+ break;
+ case SP_MessageBoxCritical:
+ pixmap = QIcon::fromTheme(QLatin1String("messagebox_critical")).pixmap(16);
+ break;
+ case SP_MessageBoxQuestion:
+ pixmap = QIcon::fromTheme(QLatin1String("help")).pixmap(16);
+ break;
+ case SP_DialogOpenButton:
+ case SP_DirOpenIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("folder-open")).pixmap(16);
+ break;
+ case SP_FileIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("text-x-generic"),
+ QIcon::fromTheme(QLatin1String("empty"))).pixmap(16);
+ break;
+ case SP_DirClosedIcon:
+ case SP_DirIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("folder")).pixmap(16);
+ break;
+ case SP_DriveFDIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("media-floppy"),
+ QIcon::fromTheme(QLatin1String("3floppy_unmount"))).pixmap(16);
+ break;
+ case SP_ComputerIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("computer"),
+ QIcon::fromTheme(QLatin1String("system"))).pixmap(16);
+ break;
+ case SP_DesktopIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("user-desktop"),
+ QIcon::fromTheme(QLatin1String("desktop"))).pixmap(16);
+ break;
+ case SP_TrashIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("user-trash"),
+ QIcon::fromTheme(QLatin1String("trashcan_empty"))).pixmap(16);
+ break;
+ case SP_DriveCDIcon:
+ case SP_DriveDVDIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("media-optical"),
+ QIcon::fromTheme(QLatin1String("cdrom_unmount"))).pixmap(16);
+ break;
+ case SP_DriveHDIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("drive-harddisk"),
+ QIcon::fromTheme(QLatin1String("hdd_unmount"))).pixmap(16);
+ break;
+ case SP_FileDialogToParent:
+ pixmap = QIcon::fromTheme(QLatin1String("go-up"),
+ QIcon::fromTheme(QLatin1String("up"))).pixmap(16);
+ break;
+ case SP_FileDialogNewFolder:
+ pixmap = QIcon::fromTheme(QLatin1String("folder_new")).pixmap(16);
+ break;
+ case SP_ArrowUp:
+ pixmap = QIcon::fromTheme(QLatin1String("go-up"),
+ QIcon::fromTheme(QLatin1String("up"))).pixmap(16);
+ break;
+ case SP_ArrowDown:
+ pixmap = QIcon::fromTheme(QLatin1String("go-down"),
+ QIcon::fromTheme(QLatin1String("down"))).pixmap(16);
+ break;
+ case SP_ArrowRight:
+ pixmap = QIcon::fromTheme(QLatin1String("go-next"),
+ QIcon::fromTheme(QLatin1String("forward"))).pixmap(16);
+ break;
+ case SP_ArrowLeft:
+ pixmap = QIcon::fromTheme(QLatin1String("go-previous"),
+ QIcon::fromTheme(QLatin1String("back"))).pixmap(16);
+ break;
+ case SP_FileDialogDetailedView:
+ pixmap = QIcon::fromTheme(QLatin1String("view_detailed")).pixmap(16);
+ break;
+ case SP_FileDialogListView:
+ pixmap = QIcon::fromTheme(QLatin1String("view_icon")).pixmap(16);
+ break;
+ case SP_BrowserReload:
+ pixmap = QIcon::fromTheme(QLatin1String("reload")).pixmap(16);
+ break;
+ case SP_BrowserStop:
+ pixmap = QIcon::fromTheme(QLatin1String("process-stop")).pixmap(16);
+ break;
+ case SP_MediaPlay:
+ pixmap = QIcon::fromTheme(QLatin1String("media-playback-start")).pixmap(16);
+ break;
+ case SP_MediaPause:
+ pixmap = QIcon::fromTheme(QLatin1String("media-playback-pause")).pixmap(16);
+ break;
+ case SP_MediaStop:
+ pixmap = QIcon::fromTheme(QLatin1String("media-playback-stop")).pixmap(16);
+ break;
+ case SP_MediaSeekForward:
+ pixmap = QIcon::fromTheme(QLatin1String("media-seek-forward")).pixmap(16);
+ break;
+ case SP_MediaSeekBackward:
+ pixmap = QIcon::fromTheme(QLatin1String("media-seek-backward")).pixmap(16);
+ break;
+ case SP_MediaSkipForward:
+ pixmap = QIcon::fromTheme(QLatin1String("media-skip-forward")).pixmap(16);
+ break;
+ case SP_MediaSkipBackward:
+ pixmap = QIcon::fromTheme(QLatin1String("media-skip-backward")).pixmap(16);
+ break;
+ case SP_DialogResetButton:
+ pixmap = QIcon::fromTheme(QLatin1String("edit-clear")).pixmap(24);
+ break;
+ case SP_DialogHelpButton:
+ pixmap = QIcon::fromTheme(QLatin1String("help-contents")).pixmap(24);
+ break;
+ case SP_DialogNoButton:
+ case SP_DialogCancelButton:
+ pixmap = QIcon::fromTheme(QLatin1String("dialog-cancel"),
+ QIcon::fromTheme(QLatin1String("process-stop"))).pixmap(24);
+ break;
+ case SP_DialogSaveButton:
+ pixmap = QIcon::fromTheme(QLatin1String("document-save")).pixmap(24);
+ break;
+ case SP_FileLinkIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")).pixmap(16);
+ if (!pixmap.isNull()) {
+ QPixmap fileIcon = QIcon::fromTheme(QLatin1String("text-x-generic")).pixmap(16);
+ if (fileIcon.isNull())
+ fileIcon = QIcon::fromTheme(QLatin1String("empty")).pixmap(16);
+ if (!fileIcon.isNull()) {
+ QPainter painter(&fileIcon);
+ painter.drawPixmap(0, 0, 16, 16, pixmap);
+ return fileIcon;
+ }
+ }
+ break;
+ case SP_DirLinkIcon:
+ pixmap = QIcon::fromTheme(QLatin1String("emblem-symbolic-link")).pixmap(16);
+ if (!pixmap.isNull()) {
+ QPixmap dirIcon = QIcon::fromTheme(QLatin1String("folder")).pixmap(16);
+ if (!dirIcon.isNull()) {
+ QPainter painter(&dirIcon);
+ painter.drawPixmap(0, 0, 16, 16, pixmap);
+ return dirIcon;
+ }
+ }
+ break;
+ case SP_LineEditClearButton:
+ pixmap = clearTextIcon(rtl).pixmap(16);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!pixmap.isNull())
+ return pixmap;
+#endif // QT_CONFIG(imageformat_png)
+ switch (sp) {
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ case SP_ToolBarHorizontalExtensionButton:
+ if (rtl) {
+ QImage im(tb_extension_arrow_h_xpm);
+ im = im.convertToFormat(QImage::Format_ARGB32).mirrored(true, false);
+ return QPixmap::fromImage(im);
+ }
+ return cachedPixmapFromXPM(tb_extension_arrow_h_xpm);
+ case SP_ToolBarVerticalExtensionButton:
+ return cachedPixmapFromXPM(tb_extension_arrow_v_xpm);
+ case SP_FileDialogStart:
+ return cachedPixmapFromXPM(filedialog_start_xpm);
+ case SP_FileDialogEnd:
+ return cachedPixmapFromXPM(filedialog_end_xpm);
+#endif
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ case SP_CommandLink:
+ case SP_ArrowForward:
+ if (rtl)
+ return proxy()->standardPixmap(SP_ArrowLeft, option);
+ return proxy()->standardPixmap(SP_ArrowRight, option);
+ case SP_ArrowBack:
+ if (rtl)
+ return proxy()->standardPixmap(SP_ArrowRight, option);
+ return proxy()->standardPixmap(SP_ArrowLeft, option);
+ case SP_ArrowLeft:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/left-16.png"));
+ case SP_ArrowRight:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/right-16.png"));
+ case SP_ArrowUp:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/up-16.png"));
+ case SP_ArrowDown:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/down-16.png"));
+ case SP_FileDialogToParent:
+ return proxy()->standardPixmap(SP_ArrowUp, option);
+ case SP_FileDialogNewFolder:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-16.png"));
+ case SP_FileDialogDetailedView:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewdetailed-16.png"));
+ case SP_FileDialogInfoView:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/fileinfo-16.png"));
+ case SP_FileDialogContentsView:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/filecontents-16.png"));
+ case SP_FileDialogListView:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewlist-16.png"));
+ case SP_FileDialogBack:
+ return proxy()->standardPixmap(SP_ArrowBack, option);
+ case SP_DriveHDIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/harddrive-16.png"));
+ case SP_TrashIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/trash-16.png"));
+ case SP_DriveFDIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/floppy-16.png"));
+ case SP_DriveNetIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/networkdrive-16.png"));
+ case SP_DesktopIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/desktop-16.png"));
+ case SP_ComputerIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/computer-16.png"));
+ case SP_DriveCDIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/cdr-16.png"));
+ case SP_DriveDVDIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/dvd-16.png"));
+ case SP_DirHomeIcon:
+ case SP_DirOpenIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-16.png"));
+ case SP_DirIcon:
+ case SP_DirClosedIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/dirclosed-16.png"));
+ case SP_DirLinkIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/dirlink-16.png"));
+ case SP_FileIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png"));
+ case SP_FileLinkIcon:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/filelink-16.png"));
+ case SP_DialogOkButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-16.png"));
+ case SP_DialogCancelButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-16.png"));
+ case SP_DialogHelpButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-help-16.png"));
+ case SP_DialogOpenButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-open-16.png"));
+ case SP_DialogSaveButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-save-16.png"));
+ case SP_DialogCloseButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-close-16.png"));
+ case SP_DialogApplyButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-16.png"));
+ case SP_DialogResetButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-16.png"));
+ case SP_DialogDiscardButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-16.png"));
+ case SP_DialogYesButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-16.png"));
+ case SP_DialogNoButton:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-no-16.png"));
+ case SP_BrowserReload:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/refresh-24.png"));
+ case SP_BrowserStop:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/stop-24.png"));
+ case SP_MediaPlay:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-play-32.png"));
+ case SP_MediaPause:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-pause-32.png"));
+ case SP_MediaStop:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-stop-32.png"));
+ case SP_MediaSeekForward:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-forward-32.png"));
+ case SP_MediaSeekBackward:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-backward-32.png"));
+ case SP_MediaSkipForward:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-forward-32.png"));
+ case SP_MediaSkipBackward:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-backward-32.png"));
+ case SP_MediaVolume:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-16.png"));
+ case SP_MediaVolumeMuted:
+ return QPixmap(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-muted-16.png"));
+ case SP_LineEditClearButton:
+ return QPixmap(clearText16IconPath());
+#endif // QT_NO_IMAGEFORMAT_PNG
+ default:
+ break;
+ }
+
+#ifndef QT_NO_IMAGEFORMAT_XPM
+ switch (sp) {
+ case SP_TitleBarMenuButton:
+ return titleBarMenuCachedPixmapFromXPM();
+ case SP_TitleBarShadeButton:
+ return cachedPixmapFromXPM(qt_shade_xpm);
+ case SP_TitleBarUnshadeButton:
+ return cachedPixmapFromXPM(qt_unshade_xpm);
+ case SP_TitleBarNormalButton:
+ return cachedPixmapFromXPM(qt_normalizeup_xpm);
+ case SP_TitleBarMinButton:
+ return cachedPixmapFromXPM(qt_minimize_xpm);
+ case SP_TitleBarMaxButton:
+ return cachedPixmapFromXPM(qt_maximize_xpm);
+ case SP_TitleBarCloseButton:
+ return cachedPixmapFromXPM(qt_close_xpm);
+ case SP_TitleBarContextHelpButton:
+ return cachedPixmapFromXPM(qt_help_xpm);
+ case SP_DockWidgetCloseButton:
+ return cachedPixmapFromXPM(dock_widget_close_xpm);
+ case SP_MessageBoxInformation:
+ return cachedPixmapFromXPM(information_xpm);
+ case SP_MessageBoxWarning:
+ return cachedPixmapFromXPM(warning_xpm);
+ case SP_MessageBoxCritical:
+ return cachedPixmapFromXPM(critical_xpm);
+ case SP_MessageBoxQuestion:
+ return cachedPixmapFromXPM(question_xpm);
+ default:
+ break;
+ }
+#endif //QT_NO_IMAGEFORMAT_XPM
+
+#if !QT_CONFIG(imageformat_png) && !QT_CONFIG(imageformat_xpm)
+ Q_UNUSED(rtl);
+#endif
+
+ return QPixmap();
+}
+
+#if QT_CONFIG(imageformat_png)
+static inline QString iconResourcePrefix() { return QStringLiteral(":/qt-project.org/styles/commonstyle/images/"); }
+static inline QString iconPngSuffix() { return QStringLiteral(".png"); }
+
+static void addIconFiles(const QString &prefix, const int sizes[], size_t count, QIcon &icon)
+{
+ for (size_t i = 0; i < count; ++i)
+ icon.addFile(prefix + QString::number(sizes[i]) + iconPngSuffix());
+}
+
+static const int dockTitleIconSizes[] = {10, 16, 20, 32, 48, 64};
+static const int titleBarSizes[] = {16, 32, 48};
+static const int toolBarExtHSizes[] = {8, 16, 32};
+static const int toolBarExtVSizes[] = {5, 10, 20};
+#endif // imageformat_png
+
+/*!
+ \internal
+*/
+QIcon QCommonStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option) const
+{
+ QIcon icon;
+ const bool rtl = (option && option->direction == Qt::RightToLeft) || (!option && QGuiApplication::isRightToLeft());
+
+#ifdef Q_OS_WIN
+ switch (standardIcon) {
+ case SP_DriveCDIcon:
+ case SP_DriveDVDIcon:
+ case SP_DriveNetIcon:
+ case SP_DriveHDIcon:
+ case SP_DriveFDIcon:
+ case SP_FileIcon:
+ case SP_FileLinkIcon:
+ case SP_DesktopIcon:
+ case SP_ComputerIcon:
+ case SP_VistaShield:
+ case SP_MessageBoxInformation:
+ case SP_MessageBoxWarning:
+ case SP_MessageBoxCritical:
+ case SP_MessageBoxQuestion:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
+ for (int size = 16 ; size <= 32 ; size += 16) {
+ QPixmap pixmap = theme->standardPixmap(sp, QSizeF(size, size));
+ icon.addPixmap(pixmap, QIcon::Normal);
+ }
+ }
+ break;
+ case SP_DirIcon:
+ case SP_DirLinkIcon:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ QPlatformTheme::StandardPixmap spOff = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
+ QPlatformTheme::StandardPixmap spOn = standardIcon == SP_DirIcon ? QPlatformTheme::DirOpenIcon :
+ QPlatformTheme::DirLinkOpenIcon;
+ for (int size = 16 ; size <= 32 ; size += 16) {
+ QSizeF pixSize(size, size);
+ QPixmap pixmap = theme->standardPixmap(spOff, pixSize);
+ icon.addPixmap(pixmap, QIcon::Normal, QIcon::Off);
+ pixmap = theme->standardPixmap(spOn, pixSize);
+ icon.addPixmap(pixmap, QIcon::Normal, QIcon::On);
+ }
+ }
+ break;
+ case SP_LineEditClearButton:
+ icon = clearTextIcon(rtl);
+ break;
+ default:
+ break;
+ }
+ if (!icon.isNull())
+ return icon;
+
+#endif
+
+ if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty()) {
+ switch (standardIcon) {
+ case SP_DirHomeIcon:
+ icon = QIcon::fromTheme(QLatin1String("user-home"));
+ break;
+ case SP_MessageBoxInformation:
+ icon = QIcon::fromTheme(QLatin1String("dialog-information"));
+ break;
+ case SP_MessageBoxWarning:
+ icon = QIcon::fromTheme(QLatin1String("dialog-warning"));
+ break;
+ case SP_MessageBoxCritical:
+ icon = QIcon::fromTheme(QLatin1String("dialog-error"));
+ break;
+ case SP_MessageBoxQuestion:
+ icon = QIcon::fromTheme(QLatin1String("dialog-question"));
+ break;
+ case SP_DialogOpenButton:
+ case SP_DirOpenIcon:
+ icon = QIcon::fromTheme(QLatin1String("folder-open"));
+ break;
+ case SP_DialogSaveButton:
+ icon = QIcon::fromTheme(QLatin1String("document-save"));
+ break;
+ case SP_DialogApplyButton:
+ icon = QIcon::fromTheme(QLatin1String("dialog-ok-apply"));
+ break;
+ case SP_DialogYesButton:
+ case SP_DialogOkButton:
+ icon = QIcon::fromTheme(QLatin1String("dialog-ok"));
+ break;
+ case SP_DialogDiscardButton:
+ icon = QIcon::fromTheme(QLatin1String("edit-delete"));
+ break;
+ case SP_DialogResetButton:
+ icon = QIcon::fromTheme(QLatin1String("edit-clear"));
+ break;
+ case SP_DialogHelpButton:
+ icon = QIcon::fromTheme(QLatin1String("help-contents"));
+ break;
+ case SP_FileIcon:
+ icon = QIcon::fromTheme(QLatin1String("text-x-generic"));
+ break;
+ case SP_DirClosedIcon:
+ case SP_DirIcon:
+ icon = QIcon::fromTheme(QLatin1String("folder"));
+ break;
+ case SP_DriveFDIcon:
+ icon = QIcon::fromTheme(QLatin1String("floppy_unmount"));
+ break;
+ case SP_ComputerIcon:
+ icon = QIcon::fromTheme(QLatin1String("computer"),
+ QIcon::fromTheme(QLatin1String("system")));
+ break;
+ case SP_DesktopIcon:
+ icon = QIcon::fromTheme(QLatin1String("user-desktop"));
+ break;
+ case SP_TrashIcon:
+ icon = QIcon::fromTheme(QLatin1String("user-trash"));
+ break;
+ case SP_DriveCDIcon:
+ case SP_DriveDVDIcon:
+ icon = QIcon::fromTheme(QLatin1String("media-optical"));
+ break;
+ case SP_DriveHDIcon:
+ icon = QIcon::fromTheme(QLatin1String("drive-harddisk"));
+ break;
+ case SP_FileDialogToParent:
+ icon = QIcon::fromTheme(QLatin1String("go-up"));
+ break;
+ case SP_FileDialogNewFolder:
+ icon = QIcon::fromTheme(QLatin1String("folder-new"));
+ break;
+ case SP_ArrowUp:
+ icon = QIcon::fromTheme(QLatin1String("go-up"));
+ break;
+ case SP_ArrowDown:
+ icon = QIcon::fromTheme(QLatin1String("go-down"));
+ break;
+ case SP_ArrowRight:
+ icon = QIcon::fromTheme(QLatin1String("go-next"));
+ break;
+ case SP_ArrowLeft:
+ icon = QIcon::fromTheme(QLatin1String("go-previous"));
+ break;
+ case SP_DialogNoButton:
+ case SP_DialogCancelButton:
+ icon = QIcon::fromTheme(QLatin1String("dialog-cancel"),
+ QIcon::fromTheme(QLatin1String("process-stop")));
+ break;
+ case SP_DialogCloseButton:
+ icon = QIcon::fromTheme(QLatin1String("window-close"));
+ break;
+ case SP_FileDialogDetailedView:
+ icon = QIcon::fromTheme(QLatin1String("view-list-details"));
+ break;
+ case SP_FileDialogListView:
+ icon = QIcon::fromTheme(QLatin1String("view-list-icons"));
+ break;
+ case SP_BrowserReload:
+ icon = QIcon::fromTheme(QLatin1String("view-refresh"));
+ break;
+ case SP_BrowserStop:
+ icon = QIcon::fromTheme(QLatin1String("process-stop"));
+ break;
+ case SP_MediaPlay:
+ icon = QIcon::fromTheme(QLatin1String("media-playback-start"));
+ break;
+ case SP_MediaPause:
+ icon = QIcon::fromTheme(QLatin1String("media-playback-pause"));
+ break;
+ case SP_MediaStop:
+ icon = QIcon::fromTheme(QLatin1String("media-playback-stop"));
+ break;
+ case SP_MediaSeekForward:
+ icon = QIcon::fromTheme(QLatin1String("media-seek-forward"));
+ break;
+ case SP_MediaSeekBackward:
+ icon = QIcon::fromTheme(QLatin1String("media-seek-backward"));
+ break;
+ case SP_MediaSkipForward:
+ icon = QIcon::fromTheme(QLatin1String("media-skip-forward"));
+ break;
+ case SP_MediaSkipBackward:
+ icon = QIcon::fromTheme(QLatin1String("media-skip-backward"));
+ break;
+ case SP_MediaVolume:
+ icon = QIcon::fromTheme(QLatin1String("audio-volume-medium"));
+ break;
+ case SP_MediaVolumeMuted:
+ icon = QIcon::fromTheme(QLatin1String("audio-volume-muted"));
+ break;
+ case SP_ArrowForward:
+ if (rtl)
+ return QCommonStyle::standardIcon(SP_ArrowLeft, option);
+ return QCommonStyle::standardIcon(SP_ArrowRight, option);
+ case SP_ArrowBack:
+ if (rtl)
+ return QCommonStyle::standardIcon(SP_ArrowRight, option);
+ return QCommonStyle::standardIcon(SP_ArrowLeft, option);
+ case SP_FileLinkIcon:
+ {
+ QIcon linkIcon = QIcon::fromTheme(QLatin1String("emblem-symbolic-link"));
+ if (!linkIcon.isNull()) {
+ QIcon baseIcon = QCommonStyle::standardIcon(SP_FileIcon, option);
+ const QList<QSize> sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off);
+ const qreal devicePixelRatio = option ? dpr(option->window) : 1.;
+ for (int i = 0 ; i < sizes.size() ; ++i) {
+ int size = sizes[i].width();
+ QPixmap basePixmap = baseIcon.pixmap(QSize(size, size), devicePixelRatio);
+ QPixmap linkPixmap = linkIcon.pixmap(QSize(size / 2, size / 2), devicePixelRatio);
+ QPainter painter(&basePixmap);
+ painter.drawPixmap(size/2, size/2, linkPixmap);
+ icon.addPixmap(basePixmap);
+ }
+ }
+ }
+ break;
+ case SP_DirLinkIcon:
+ {
+ QIcon linkIcon = QIcon::fromTheme(QLatin1String("emblem-symbolic-link"));
+ if (!linkIcon.isNull()) {
+ QIcon baseIcon = QCommonStyle::standardIcon(SP_DirIcon, option);
+ const QList<QSize> sizes = baseIcon.availableSizes(QIcon::Normal, QIcon::Off);
+ const qreal devicePixelRatio = option ? dpr(option->window) : 1.;
+ for (int i = 0 ; i < sizes.size() ; ++i) {
+ int size = sizes[i].width();
+ QPixmap basePixmap = baseIcon.pixmap(QSize(size, size), devicePixelRatio);
+ QPixmap linkPixmap = linkIcon.pixmap(QSize(size / 2, size / 2), devicePixelRatio);
+ QPainter painter(&basePixmap);
+ painter.drawPixmap(size/2, size/2, linkPixmap);
+ icon.addPixmap(basePixmap);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ } // if (QGuiApplication::desktopSettingsAware() && !QIcon::themeName().isEmpty())
+
+ if (!icon.isNull())
+ return icon;
+
+#if defined(Q_OS_MAC)
+ if (QGuiApplication::desktopSettingsAware()) {
+ switch (standardIcon) {
+ case SP_DirIcon: {
+ // A rather special case
+ QIcon closeIcon = QCommonStyle::standardIcon(SP_DirClosedIcon, option);
+ QIcon openIcon = QCommonStyle::standardIcon(SP_DirOpenIcon, option);
+ closeIcon.addPixmap(openIcon.pixmap(16, 16), QIcon::Normal, QIcon::On);
+ closeIcon.addPixmap(openIcon.pixmap(32, 32), QIcon::Normal, QIcon::On);
+ closeIcon.addPixmap(openIcon.pixmap(64, 64), QIcon::Normal, QIcon::On);
+ closeIcon.addPixmap(openIcon.pixmap(128, 128), QIcon::Normal, QIcon::On);
+ return closeIcon;
+ }
+
+ case SP_TitleBarNormalButton:
+ case SP_TitleBarCloseButton: {
+ QIcon titleBarIcon;
+ if (standardIcon == SP_TitleBarCloseButton) {
+ titleBarIcon.addFile(QLatin1String(":/qt-project.org/styles/macstyle/images/closedock-16.png"));
+ titleBarIcon.addFile(QLatin1String(":/qt-project.org/styles/macstyle/images/closedock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
+ } else {
+ titleBarIcon.addFile(QLatin1String(":/qt-project.org/styles/macstyle/images/dockdock-16.png"));
+ titleBarIcon.addFile(QLatin1String(":/qt-project.org/styles/macstyle/images/dockdock-down-16.png"), QSize(16, 16), QIcon::Normal, QIcon::On);
+ }
+ return titleBarIcon;
+ }
+
+ case SP_MessageBoxQuestion:
+ case SP_MessageBoxInformation:
+ case SP_MessageBoxWarning:
+ case SP_MessageBoxCritical:
+ case SP_DesktopIcon:
+ case SP_TrashIcon:
+ case SP_ComputerIcon:
+ case SP_DriveFDIcon:
+ case SP_DriveHDIcon:
+ case SP_DriveCDIcon:
+ case SP_DriveDVDIcon:
+ case SP_DriveNetIcon:
+ case SP_DirOpenIcon:
+ case SP_DirClosedIcon:
+ case SP_DirLinkIcon:
+ case SP_FileLinkIcon:
+ case SP_FileIcon:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardIcon);
+ QIcon retIcon;
+ const QList<QSize> sizes = theme->themeHint(QPlatformTheme::IconPixmapSizes).value<QList<QSize> >();
+ for (const QSize &size : sizes) {
+ QPixmap mainIcon;
+ const QString cacheKey = QLatin1String("qt_mac_constructQIconFromIconRef") + QString::number(standardIcon) + QString::number(size.width());
+ if (standardIcon >= QStyle::SP_CustomBase) {
+ mainIcon = theme->standardPixmap(sp, QSizeF(size));
+ } else if (QPixmapCache::find(cacheKey, &mainIcon) == false) {
+ mainIcon = theme->standardPixmap(sp, QSizeF(size));
+ QPixmapCache::insert(cacheKey, mainIcon);
+ }
+
+ retIcon.addPixmap(mainIcon);
+ }
+ if (!retIcon.isNull())
+ return retIcon;
+ }
+
+ default:
+ break;
+ }
+ } // if (QGuiApplication::desktopSettingsAware())
+#endif // Q_OS_MAC
+
+ switch (standardIcon) {
+#ifndef QT_NO_IMAGEFORMAT_PNG
+ case SP_TitleBarMinButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-min-"),
+ titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
+ break;
+ case SP_TitleBarMaxButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-max-"),
+ titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
+ break;
+ case SP_TitleBarShadeButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-shade-"),
+ titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
+
+ break;
+ case SP_TitleBarUnshadeButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-unshade-"),
+ titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
+ break;
+ case SP_TitleBarContextHelpButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("titlebar-contexthelp-"),
+ titleBarSizes, sizeof(titleBarSizes)/sizeof(titleBarSizes[0]), icon);
+ break;
+ case SP_FileDialogNewFolder:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/newdirectory-128.png"), QSize(128, 128));
+ break;
+ case SP_FileDialogBack:
+ return QCommonStyle::standardIcon(SP_ArrowBack, option);
+ case SP_FileDialogToParent:
+ return QCommonStyle::standardIcon(SP_ArrowUp, option);
+ case SP_FileDialogDetailedView:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewdetailed-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewdetailed-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewdetailed-128.png"), QSize(128, 128));
+ break;
+ case SP_FileDialogInfoView:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/fileinfo-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/fileinfo-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/fileinfo-128.png"), QSize(128, 128));
+ break;
+ case SP_FileDialogContentsView:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filecontents-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filecontents-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filecontents-128.png"), QSize(128, 128));
+ break;
+ case SP_FileDialogListView:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewlist-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewlist-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/viewlist-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogOkButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-ok-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogCancelButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-cancel-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogHelpButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-help-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-help-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-help-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogOpenButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-open-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-open-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-open-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogSaveButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-save-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-save-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-save-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogCloseButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-close-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-close-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-close-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogApplyButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-apply-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogResetButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-clear-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogDiscardButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-delete-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogYesButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-yes-128.png"), QSize(128, 128));
+ break;
+ case SP_DialogNoButton:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-no-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-no-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/standardbutton-no-128.png"), QSize(128, 128));
+ break;
+ case SP_ArrowForward:
+ if (rtl)
+ return QCommonStyle::standardIcon(SP_ArrowLeft, option);
+ return QCommonStyle::standardIcon(SP_ArrowRight, option);
+ case SP_ArrowBack:
+ if (rtl)
+ return QCommonStyle::standardIcon(SP_ArrowRight, option);
+ return QCommonStyle::standardIcon(SP_ArrowLeft, option);
+ case SP_ArrowLeft:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/left-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/left-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/left-128.png"), QSize(128, 128));
+ break;
+ case SP_ArrowRight:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/right-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/right-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/right-128.png"), QSize(128, 128));
+ break;
+ case SP_ArrowUp:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/up-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/up-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/up-128.png"), QSize(128, 128));
+ break;
+ case SP_ArrowDown:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/down-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/down-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/down-128.png"), QSize(128, 128));
+ break;
+ case SP_DirHomeIcon:
+ case SP_DirIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dirclosed-16.png"),
+ QSize(), QIcon::Normal, QIcon::Off);
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-16.png"),
+ QSize(), QIcon::Normal, QIcon::On);
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dirclosed-32.png"),
+ QSize(32, 32), QIcon::Normal, QIcon::Off);
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-32.png"),
+ QSize(32, 32), QIcon::Normal, QIcon::On);
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dirclosed-128.png"),
+ QSize(128, 128), QIcon::Normal, QIcon::Off);
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/diropen-128.png"),
+ QSize(128, 128), QIcon::Normal, QIcon::On);
+ break;
+ case SP_DriveCDIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/cdr-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/cdr-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/cdr-128.png"), QSize(128, 128));
+ break;
+ case SP_DriveDVDIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dvd-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dvd-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/dvd-128.png"), QSize(128, 128));
+ break;
+ case SP_FileIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/file-128.png"), QSize(128, 128));
+ break;
+ case SP_FileLinkIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filelink-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filelink-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/filelink-128.png"), QSize(128, 128));
+ break;
+ case SP_TrashIcon:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/trash-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/trash-32.png"), QSize(32, 32));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/trash-128.png"), QSize(128, 128));
+ break;
+ case SP_BrowserReload:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/refresh-24.png"), QSize(24, 24));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/refresh-32.png"), QSize(32, 32));
+ break;
+ case SP_BrowserStop:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/stop-24.png"), QSize(24, 24));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/stop-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaPlay:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-play-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-play-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaPause:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-pause-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-pause-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaStop:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-stop-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-stop-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaSeekForward:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-forward-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-forward-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaSeekBackward:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-backward-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-seek-backward-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaSkipForward:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-forward-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-forward-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaSkipBackward:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-backward-16.png"), QSize(16, 16));
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-skip-backward-32.png"), QSize(32, 32));
+ break;
+ case SP_MediaVolume:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-16.png"), QSize(16, 16));
+ break;
+ case SP_MediaVolumeMuted:
+ icon.addFile(QLatin1String(":/qt-project.org/styles/commonstyle/images/media-volume-muted-16.png"), QSize(16, 16));
+ break;
+ case SP_TitleBarCloseButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("closedock-"),
+ dockTitleIconSizes, sizeof(dockTitleIconSizes)/sizeof(dockTitleIconSizes[0]), icon);
+ break;
+ case SP_TitleBarMenuButton:
+# ifndef QT_NO_IMAGEFORMAT_XPM
+ icon.addPixmap(titleBarMenuCachedPixmapFromXPM());
+# endif
+ icon.addFile(QLatin1String(":/qt-project.org/qmessagebox/images/qtlogo-64.png"));
+ break;
+ case SP_TitleBarNormalButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("normalizedockup-"),
+ dockTitleIconSizes, sizeof(dockTitleIconSizes)/sizeof(dockTitleIconSizes[0]), icon);
+ break;
+ case SP_ToolBarHorizontalExtensionButton: {
+ QString prefix = iconResourcePrefix() + QStringLiteral("toolbar-ext-h-");
+ if (rtl)
+ prefix += QStringLiteral("rtl-");
+ addIconFiles(prefix, toolBarExtHSizes, sizeof(toolBarExtHSizes)/sizeof(toolBarExtHSizes[0]), icon);
+ }
+ break;
+ case SP_ToolBarVerticalExtensionButton:
+ addIconFiles(iconResourcePrefix() + QStringLiteral("toolbar-ext-v-"),
+ toolBarExtVSizes, sizeof(toolBarExtVSizes)/sizeof(toolBarExtVSizes[0]), icon);
+ break;
+#endif // QT_NO_IMAGEFORMAT_PNG
+ default:
+ icon.addPixmap(proxy()->standardPixmap(standardIcon, option));
+ break;
+ }
+ return icon;
+}
+
+static inline uint qt_intensity(uint r, uint g, uint b)
+{
+ // 30% red, 59% green, 11% blue
+ return (77 * r + 150 * g + 28 * b) / 255;
+}
+
+/*! \reimp */
+QPixmap QCommonStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap,
+ const QStyleOption *opt) const
+{
+ switch (iconMode) {
+ case QIcon::Disabled: {
+ QImage im = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+
+ // Create a colortable based on the background (black -> bg -> white)
+ QColor bg = opt->palette.color(QPalette::Disabled, QPalette::Window);
+ int red = bg.red();
+ int green = bg.green();
+ int blue = bg.blue();
+ uchar reds[256], greens[256], blues[256];
+ for (int i=0; i<128; ++i) {
+ reds[i] = uchar((red * (i<<1)) >> 8);
+ greens[i] = uchar((green * (i<<1)) >> 8);
+ blues[i] = uchar((blue * (i<<1)) >> 8);
+ }
+ for (int i=0; i<128; ++i) {
+ reds[i+128] = uchar(qMin(red + (i << 1), 255));
+ greens[i+128] = uchar(qMin(green + (i << 1), 255));
+ blues[i+128] = uchar(qMin(blue + (i << 1), 255));
+ }
+
+ int intensity = qt_intensity(red, green, blue);
+ const int factor = 191;
+
+ // High intensity colors needs dark shifting in the color table, while
+ // low intensity colors needs light shifting. This is to increase the
+ // perceived contrast.
+ if ((red - factor > green && red - factor > blue)
+ || (green - factor > red && green - factor > blue)
+ || (blue - factor > red && blue - factor > green))
+ intensity = qMin(255, intensity + 91);
+ else if (intensity <= 128)
+ intensity -= 51;
+
+ for (int y=0; y<im.height(); ++y) {
+ QRgb *scanLine = (QRgb*)im.scanLine(y);
+ for (int x=0; x<im.width(); ++x) {
+ QRgb pixel = *scanLine;
+ // Calculate color table index, taking intensity adjustment
+ // and a magic offset into account.
+ uint ci = uint(qGray(pixel)/3 + (130 - intensity / 3));
+ *scanLine = qRgba(reds[ci], greens[ci], blues[ci], qAlpha(pixel));
+ ++scanLine;
+ }
+ }
+
+ return QPixmap::fromImage(im);
+ }
+ case QIcon::Selected: {
+ QImage img = pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+ QColor color = opt->palette.color(QPalette::Normal, QPalette::Highlight);
+ color.setAlphaF(0.3f);
+ QPainter painter(&img);
+ painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
+ painter.fillRect(0, 0, img.width(), img.height(), color);
+ painter.end();
+ return QPixmap::fromImage(img); }
+ case QIcon::Active:
+ return pixmap;
+ default:
+ break;
+ }
+ return pixmap;
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcommonstyle.cpp"
diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle.h b/src/quicknativestyle/qstyle/qquickcommonstyle.h
new file mode 100644
index 0000000000..894194a044
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickcommonstyle.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMMONSTYLE_H
+#define QCOMMONSTYLE_H
+
+#include "qquickstyle.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+class QCommonStylePrivate;
+
+class QCommonStyle: public QStyle
+{
+ Q_OBJECT
+
+public:
+ QCommonStyle();
+ ~QCommonStyle() override;
+
+ void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const override;
+ void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p) const override;
+ void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const override;
+
+ QRect subElementRect(SubElement r, const QStyleOption *opt) const override;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc) const override;
+
+ QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const override;
+ QFont font(ControlElement element, const QStyle::State state) const override;
+ QMargins ninePatchMargins(ControlElement ce, const QStyleOption *opt, const QSize &imageSize) const override;
+ QMargins ninePatchMargins(ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const override;
+
+ int pixelMetric(PixelMetric m, const QStyleOption *opt = nullptr) const override;
+ int styleHint(StyleHint sh, const QStyleOption *opt = nullptr, QStyleHintReturn *shret = nullptr) const override;
+
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *opt = nullptr) const override;
+ QPixmap standardPixmap(StandardPixmap sp, const QStyleOption *opt = nullptr) const override;
+ QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const override;
+
+ SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const override;
+
+protected:
+ QCommonStyle(QCommonStylePrivate &dd);
+
+private:
+ Q_DECLARE_PRIVATE(QCommonStyle)
+ Q_DISABLE_COPY(QCommonStyle)
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QCOMMONSTYLE_H
diff --git a/src/quicknativestyle/qstyle/qquickcommonstyle_p.h b/src/quicknativestyle/qstyle/qquickcommonstyle_p.h
new file mode 100644
index 0000000000..ba2b868928
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickcommonstyle_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOMMONSTYLE_P_H
+#define QCOMMONSTYLE_P_H
+
+#include "qquickcommonstyle.h"
+#include "qquickstyle_p.h"
+#include "qquickstyleoption.h"
+
+QT_BEGIN_NAMESPACE
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+class QTextOption;
+
+namespace QQC2 {
+
+class QCommonStylePrivate : public QStylePrivate
+{
+ Q_DECLARE_PUBLIC(QCommonStyle)
+public:
+
+ ~QCommonStylePrivate()
+ {
+ delete cachedOption;
+ }
+
+ QString calculateElidedText(const QString &text, const QTextOption &textOption,
+ const QFont &font, const QRect &textRect, const Qt::Alignment valign,
+ Qt::TextElideMode textElideMode, int flags,
+ bool lastVisibleLineShouldBeElided, QPointF *paintStartPosition) const;
+ void viewItemDrawText(QPainter *p, const QStyleOptionViewItem *option, const QRect &rect) const;
+ void viewItemLayout(const QStyleOptionViewItem *opt, QRect *checkRect,
+ QRect *pixmapRect, QRect *textRect, bool sizehint) const;
+ QSize viewItemSize(const QStyleOptionViewItem *option, int role) const;
+
+ mutable QRect decorationRect, displayRect, checkRect;
+ mutable QStyleOptionViewItem *cachedOption = nullptr;
+ bool isViewItemCached(const QStyleOptionViewItem &option) const {
+ return cachedOption
+ && option.index == cachedOption->index
+ && option.state == cachedOption->state
+ && option.rect == cachedOption->rect
+ && option.text == cachedOption->text
+ && option.direction == cachedOption->direction
+ && option.displayAlignment == cachedOption->displayAlignment
+ && option.decorationAlignment == cachedOption->decorationAlignment
+ && option.decorationPosition == cachedOption->decorationPosition
+ && option.decorationSize == cachedOption->decorationSize
+ && option.features == cachedOption->features
+ && option.icon.isNull() == cachedOption->icon.isNull()
+ && option.font == cachedOption->font
+ && option.viewItemPosition == cachedOption->viewItemPosition;
+ }
+ QString toolButtonElideText(const QStyleOptionToolButton *toolbutton,
+ const QRect &textRect, int flags) const;
+
+ mutable QIcon tabBarcloseButtonIcon;
+ virtual void tabLayout(const QStyleOptionTab *opt, QRect *textRect, QRect *pixmapRect) const;
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif //QCOMMONSTYLE_P_H
diff --git a/src/quicknativestyle/qstyle/qquickcommonstylepixmaps_p.h b/src/quicknativestyle/qstyle/qquickcommonstylepixmaps_p.h
new file mode 100644
index 0000000000..59f1afac6d
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickcommonstylepixmaps_p.h
@@ -0,0 +1,532 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_IMAGEFORMAT_XPM
+
+//
+// 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
+
+namespace QQC2 {
+
+static const char * const check_list_controller_xpm[] = {
+"16 16 4 1",
+" c None",
+". c #000000000000",
+"X c #FFFFFFFF0000",
+"o c #C71BC30BC71B",
+" ",
+" ",
+" .......... ",
+" .XXXXXXXX. ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" .XXXXXXXX.oo ",
+" ..........oo ",
+" oooooooooo ",
+" oooooooooo ",
+" ",
+" "};
+
+
+static const char * const tb_extension_arrow_v_xpm[] = {
+ "5 8 3 1",
+ " c None",
+ ". c #000000",
+ "+ c none",
+ ".+++.",
+ "..+..",
+ "+...+",
+ "++.++",
+ ".+++.",
+ "..+..",
+ "+...+",
+ "++.++"
+};
+
+static const char * const tb_extension_arrow_h_xpm[] = {
+ "8 5 3 1",
+ " c None",
+ ". c #000000",
+ "+ c none",
+ "..++..++",
+ "+..++..+",
+ "++..++..",
+ "+..++..+",
+ "..++..++",
+};
+
+static const char * const filedialog_start_xpm[]={
+ "16 15 8 1",
+ "a c #cec6bd",
+ "# c #000000",
+ "e c #ffff00",
+ "b c #999999",
+ "f c #cccccc",
+ "d c #dcdcdc",
+ "c c #ffffff",
+ ". c None",
+ ".....######aaaaa",
+ "...bb#cccc##aaaa",
+ "..bcc#cccc#d#aaa",
+ ".bcef#cccc#dd#aa",
+ ".bcfe#cccc#####a",
+ ".bcef#ccccccccc#",
+ "bbbbbbbbbbbbccc#",
+ "bccccccccccbbcc#",
+ "bcefefefefee#bc#",
+ ".bcefefefefef#c#",
+ ".bcfefefefefe#c#",
+ "..bcfefefefeeb##",
+ "..bbbbbbbbbbbbb#",
+ "...#############",
+ "................"};
+
+static const char * const filedialog_end_xpm[]={
+ "16 15 9 1",
+ "d c #a0a0a0",
+ "c c #c3c3c3",
+ "# c #cec6bd",
+ ". c #000000",
+ "f c #ffff00",
+ "e c #999999",
+ "g c #cccccc",
+ "b c #ffffff",
+ "a c None",
+ "......####aaaaaa",
+ ".bbbb..###aaaaaa",
+ ".bbbb.c.##aaaaaa",
+ ".bbbb....ddeeeea",
+ ".bbbbbbb.bbbbbe.",
+ ".bbbbbbb.bcfgfe.",
+ "eeeeeeeeeeeeefe.",
+ "ebbbbbbbbbbeege.",
+ "ebfgfgfgfgff.ee.",
+ "aebfgfgfgfgfg.e.",
+ "aebgfgfgfgfgf.e.",
+ "aaebgfgfgfgffe..",
+ "aaeeeeeeeeeeeee.",
+ "aaa.............",
+ "aaaaaaaaaaaaaaaa"};
+
+
+/* XPM */
+static const char * const qt_menu_xpm[] = {
+"16 16 72 1",
+" c None",
+". c #65AF36",
+"+ c #66B036",
+"@ c #77B94C",
+"# c #A7D28C",
+"$ c #BADBA4",
+"% c #A4D088",
+"& c #72B646",
+"* c #9ACB7A",
+"= c #7FBD56",
+"- c #85C05F",
+"; c #F4F9F0",
+"> c #FFFFFF",
+", c #E5F1DC",
+"' c #ECF5E7",
+") c #7ABA50",
+"! c #83BF5C",
+"~ c #AED595",
+"{ c #D7EACA",
+"] c #A9D28D",
+"^ c #BCDDA8",
+"/ c #C4E0B1",
+"( c #81BE59",
+"_ c #D0E7C2",
+": c #D4E9C6",
+"< c #6FB542",
+"[ c #6EB440",
+"} c #88C162",
+"| c #98CA78",
+"1 c #F4F9F1",
+"2 c #8FC56C",
+"3 c #F1F8EC",
+"4 c #E8F3E1",
+"5 c #D4E9C7",
+"6 c #74B748",
+"7 c #80BE59",
+"8 c #73B747",
+"9 c #6DB43F",
+"0 c #CBE4BA",
+"a c #80BD58",
+"b c #6DB33F",
+"c c #FEFFFE",
+"d c #68B138",
+"e c #F9FCF7",
+"f c #91C66F",
+"g c #E8F3E0",
+"h c #DCEDD0",
+"i c #91C66E",
+"j c #A3CF86",
+"k c #C9E3B8",
+"l c #B0D697",
+"m c #E3F0DA",
+"n c #95C873",
+"o c #E6F2DE",
+"p c #9ECD80",
+"q c #BEDEAA",
+"r c #C7E2B6",
+"s c #79BA4F",
+"t c #6EB441",
+"u c #BCDCA7",
+"v c #FAFCF8",
+"w c #F6FAF3",
+"x c #84BF5D",
+"y c #EDF6E7",
+"z c #FAFDF9",
+"A c #88C263",
+"B c #98CA77",
+"C c #CDE5BE",
+"D c #67B037",
+"E c #D9EBCD",
+"F c #6AB23C",
+"G c #77B94D",
+" .++++++++++++++",
+".+++++++++++++++",
+"+++@#$%&+++*=+++",
+"++-;>,>')+!>~+++",
+"++{>]+^>/(_>:~<+",
+"+[>>}+|>123>456+",
+"+7>>8+->>90>~+++",
+"+a>>b+a>c[0>~+++",
+"+de>=+f>g+0>~+++",
+"++h>i+j>k+0>~+++",
+"++l>mno>p+q>rst+",
+"++duv>wl++xy>zA+",
+"++++B>Cb++++&D++",
+"+++++0zE++++++++",
+"++++++FG+++++++.",
+"++++++++++++++. "};
+
+static const char * const qt_close_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"..........",
+".##....##.",
+"..##..##..",
+"...####...",
+"....##....",
+"...####...",
+"..##..##..",
+".##....##.",
+"..........",
+".........."};
+
+static const char * const qt_maximize_xpm[]={
+"10 10 2 1",
+"# c #000000",
+". c None",
+"#########.",
+"#########.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#.......#.",
+"#########.",
+".........."};
+
+static const char * const qt_minimize_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"..........",
+"..........",
+"..........",
+"..........",
+"..........",
+"..........",
+"..........",
+".#######..",
+".#######..",
+".........."};
+
+static const char * const qt_normalizeup_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"...######.",
+"...######.",
+"...#....#.",
+".######.#.",
+".######.#.",
+".#....###.",
+".#....#...",
+".#....#...",
+".######...",
+".........."};
+
+static const char * const qt_help_xpm[] = {
+"10 10 2 1",
+". c None",
+"# c #000000",
+"..........",
+"..######..",
+".##....##.",
+"......##..",
+".....##...",
+"....##....",
+"....##....",
+"..........",
+"....##....",
+".........."};
+
+static const char * const qt_shade_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"..........",
+"..........",
+"..........",
+"..........",
+"....#.....",
+"...###....",
+"..#####...",
+".#######..",
+"..........",
+".........."};
+
+static const char * const qt_unshade_xpm[] = {
+"10 10 2 1",
+"# c #000000",
+". c None",
+"..........",
+"..........",
+"..........",
+".#######..",
+"..#####...",
+"...###....",
+"....#.....",
+"..........",
+"..........",
+".........."};
+
+static const char * const dock_widget_close_xpm[] = {
+"8 8 2 1",
+"# c #000000",
+". c None",
+"........",
+".##..##.",
+"..####..",
+"...##...",
+"..####..",
+".##..##.",
+"........",
+"........"};
+
+/* XPM */
+static const char * const information_xpm[]={
+"32 32 5 1",
+". c None",
+"c c #000000",
+"* c #999999",
+"a c #ffffff",
+"b c #0000ff",
+"...........********.............",
+"........***aaaaaaaa***..........",
+"......**aaaaaaaaaaaaaa**........",
+".....*aaaaaaaaaaaaaaaaaa*.......",
+"....*aaaaaaaabbbbaaaaaaaac......",
+"...*aaaaaaaabbbbbbaaaaaaaac.....",
+"..*aaaaaaaaabbbbbbaaaaaaaaac....",
+".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
+".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
+"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
+"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
+"...caaaaaaabbbbbbbbbaaaaaac****.",
+"....caaaaaaaaaaaaaaaaaaaac****..",
+".....caaaaaaaaaaaaaaaaaac****...",
+"......ccaaaaaaaaaaaaaacc****....",
+".......*cccaaaaaaaaccc*****.....",
+"........***cccaaaac*******......",
+"..........****caaac*****........",
+".............*caaac**...........",
+"...............caac**...........",
+"................cac**...........",
+".................cc**...........",
+"..................***...........",
+"...................**..........."};
+/* XPM */
+static const char* const warning_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #ffff00",
+"* c #000000",
+"b c #999999",
+".............***................",
+"............*aaa*...............",
+"...........*aaaaa*b.............",
+"...........*aaaaa*bb............",
+"..........*aaaaaaa*bb...........",
+"..........*aaaaaaa*bb...........",
+".........*aaaaaaaaa*bb..........",
+".........*aaaaaaaaa*bb..........",
+"........*aaaaaaaaaaa*bb.........",
+"........*aaaa***aaaa*bb.........",
+".......*aaaa*****aaaa*bb........",
+".......*aaaa*****aaaa*bb........",
+"......*aaaaa*****aaaaa*bb.......",
+"......*aaaaa*****aaaaa*bb.......",
+".....*aaaaaa*****aaaaaa*bb......",
+".....*aaaaaa*****aaaaaa*bb......",
+"....*aaaaaaaa***aaaaaaaa*bb.....",
+"....*aaaaaaaa***aaaaaaaa*bb.....",
+"...*aaaaaaaaa***aaaaaaaaa*bb....",
+"...*aaaaaaaaaa*aaaaaaaaaa*bb....",
+"..*aaaaaaaaaaa*aaaaaaaaaaa*bb...",
+"..*aaaaaaaaaaaaaaaaaaaaaaa*bb...",
+".*aaaaaaaaaaaa**aaaaaaaaaaa*bb..",
+".*aaaaaaaaaaa****aaaaaaaaaa*bb..",
+"*aaaaaaaaaaaa****aaaaaaaaaaa*bb.",
+"*aaaaaaaaaaaaa**aaaaaaaaaaaa*bb.",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaa*bbb",
+".*aaaaaaaaaaaaaaaaaaaaaaaaa*bbbb",
+"..*************************bbbbb",
+"....bbbbbbbbbbbbbbbbbbbbbbbbbbb.",
+".....bbbbbbbbbbbbbbbbbbbbbbbbb.."};
+/* XPM */
+static const char* const critical_xpm[]={
+"32 32 4 1",
+". c None",
+"a c #999999",
+"* c #ff0000",
+"b c #ffffff",
+"...........********.............",
+".........************...........",
+".......****************.........",
+"......******************........",
+".....********************a......",
+"....**********************a.....",
+"...************************a....",
+"..*******b**********b*******a...",
+"..******bbb********bbb******a...",
+".******bbbbb******bbbbb******a..",
+".*******bbbbb****bbbbb*******a..",
+"*********bbbbb**bbbbb*********a.",
+"**********bbbbbbbbbb**********a.",
+"***********bbbbbbbb***********aa",
+"************bbbbbb************aa",
+"************bbbbbb************aa",
+"***********bbbbbbbb***********aa",
+"**********bbbbbbbbbb**********aa",
+"*********bbbbb**bbbbb*********aa",
+".*******bbbbb****bbbbb*******aa.",
+".******bbbbb******bbbbb******aa.",
+"..******bbb********bbb******aaa.",
+"..*******b**********b*******aa..",
+"...************************aaa..",
+"....**********************aaa...",
+"....a********************aaa....",
+".....a******************aaa.....",
+"......a****************aaa......",
+".......aa************aaaa.......",
+".........aa********aaaaa........",
+"...........aaaaaaaaaaa..........",
+".............aaaaaaa............"};
+/* XPM */
+static const char *const question_xpm[] = {
+"32 32 5 1",
+". c None",
+"c c #000000",
+"* c #999999",
+"a c #ffffff",
+"b c #0000ff",
+"...........********.............",
+"........***aaaaaaaa***..........",
+"......**aaaaaaaaaaaaaa**........",
+".....*aaaaaaaaaaaaaaaaaa*.......",
+"....*aaaaaaaaaaaaaaaaaaaac......",
+"...*aaaaaaaabbbbbbaaaaaaaac.....",
+"..*aaaaaaaabaaabbbbaaaaaaaac....",
+".*aaaaaaaabbaaaabbbbaaaaaaaac...",
+".*aaaaaaaabbbbaabbbbaaaaaaaac*..",
+"*aaaaaaaaabbbbaabbbbaaaaaaaaac*.",
+"*aaaaaaaaaabbaabbbbaaaaaaaaaac*.",
+"*aaaaaaaaaaaaabbbbaaaaaaaaaaac**",
+"*aaaaaaaaaaaaabbbaaaaaaaaaaaac**",
+"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**",
+"*aaaaaaaaaaaaabbaaaaaaaaaaaaac**",
+"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac**",
+".*aaaaaaaaaaaabbaaaaaaaaaaaac***",
+".*aaaaaaaaaaabbbbaaaaaaaaaaac***",
+"..*aaaaaaaaaabbbbaaaaaaaaaac***.",
+"...caaaaaaaaaabbaaaaaaaaaac****.",
+"....caaaaaaaaaaaaaaaaaaaac****..",
+".....caaaaaaaaaaaaaaaaaac****...",
+"......ccaaaaaaaaaaaaaacc****....",
+".......*cccaaaaaaaaccc*****.....",
+"........***cccaaaac*******......",
+"..........****caaac*****........",
+".............*caaac**...........",
+"...............caac**...........",
+"................cac**...........",
+".................cc**...........",
+"..................***...........",
+"...................**..........."};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_IMAGEFORMAT_XPM
diff --git a/src/quicknativestyle/qstyle/qquickdrawutil.cpp b/src/quicknativestyle/qstyle/qquickdrawutil.cpp
new file mode 100644
index 0000000000..d5290a7bea
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickdrawutil.cpp
@@ -0,0 +1,1145 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdrawutil.h"
+
+#include "qbitmap.h"
+#include "qpixmapcache.h"
+#include "qpainter.h"
+#include "qpalette.h"
+#include <private/qpaintengineex_p.h>
+#include <qvarlengtharray.h>
+#include <qmath.h>
+#include <private/qhexstring_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+namespace {
+class PainterStateGuard {
+ Q_DISABLE_COPY_MOVE(PainterStateGuard)
+public:
+ explicit PainterStateGuard(QPainter *p) : m_painter(p) {}
+ ~PainterStateGuard()
+ {
+ for ( ; m_level > 0; --m_level)
+ m_painter->restore();
+ }
+
+ void save()
+ {
+ m_painter->save();
+ ++m_level;
+ }
+
+ void restore()
+ {
+ m_painter->restore();
+ --m_level;
+ }
+
+private:
+ QPainter *m_painter;
+ int m_level= 0;
+};
+} // namespace
+
+/*!
+ \headerfile <qdrawutil.h>
+ \title Drawing Utility Functions
+
+ \sa QPainter
+*/
+
+/*!
+ \fn void qDrawShadeLine(QPainter *painter, int x1, int y1, int x2, int y2,
+ const QPalette &palette, bool sunken,
+ int lineWidth, int midLineWidth)
+ \relates <qdrawutil.h>
+
+ Draws a horizontal (\a y1 == \a y2) or vertical (\a x1 == \a x2)
+ shaded line using the given \a painter. Note that nothing is
+ drawn if \a y1 != \a y2 and \a x1 != \a x2 (i.e. the line is
+ neither horizontal nor vertical).
+
+ The provided \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors). The given \a lineWidth
+ specifies the line width for each of the lines; it is not the
+ total line width. The given \a midLineWidth specifies the width of
+ a middle line drawn in the QPalette::mid() color.
+
+ The line appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to
+ make widgets that follow the current GUI style.
+
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded line:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 0
+
+ \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
+*/
+
+void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
+ const QPalette &pal, bool sunken,
+ int lineWidth, int midLineWidth)
+{
+ if (Q_UNLIKELY(!p || lineWidth < 0 || midLineWidth < 0)) {
+ qWarning("qDrawShadeLine: Invalid parameters");
+ return;
+ }
+ int tlw = lineWidth*2 + midLineWidth; // total line width
+ QPen oldPen = p->pen(); // save pen
+ if (sunken)
+ p->setPen(pal.color(QPalette::Dark));
+ else
+ p->setPen(pal.light().color());
+ QPolygon a;
+ int i;
+ if (y1 == y2) { // horizontal line
+ int y = y1 - tlw/2;
+ if (x1 > x2) { // swap x1 and x2
+ int t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+ x2--;
+ for (i=0; i<lineWidth; i++) { // draw top shadow
+ a.setPoints(3, x1+i, y+tlw-1-i,
+ x1+i, y+i,
+ x2-i, y+i);
+ p->drawPolyline(a);
+ }
+ if (midLineWidth > 0) {
+ p->setPen(pal.mid().color());
+ for (i=0; i<midLineWidth; i++) // draw lines in the middle
+ p->drawLine(x1+lineWidth, y+lineWidth+i,
+ x2-lineWidth, y+lineWidth+i);
+ }
+ if (sunken)
+ p->setPen(pal.light().color());
+ else
+ p->setPen(pal.dark().color());
+ for (i=0; i<lineWidth; i++) { // draw bottom shadow
+ a.setPoints(3, x1+i, y+tlw-i-1,
+ x2-i, y+tlw-i-1,
+ x2-i, y+i+1);
+ p->drawPolyline(a);
+ }
+ }
+ else if (x1 == x2) { // vertical line
+ int x = x1 - tlw/2;
+ if (y1 > y2) { // swap y1 and y2
+ int t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+ y2--;
+ for (i=0; i<lineWidth; i++) { // draw left shadow
+ a.setPoints(3, x+i, y2,
+ x+i, y1+i,
+ x+tlw-1, y1+i);
+ p->drawPolyline(a);
+ }
+ if (midLineWidth > 0) {
+ p->setPen(pal.mid().color());
+ for (i=0; i<midLineWidth; i++) // draw lines in the middle
+ p->drawLine(x+lineWidth+i, y1+lineWidth, x+lineWidth+i, y2);
+ }
+ if (sunken)
+ p->setPen(pal.light().color());
+ else
+ p->setPen(pal.dark().color());
+ for (i=0; i<lineWidth; i++) { // draw right shadow
+ a.setPoints(3, x+lineWidth, y2-i,
+ x+tlw-i-1, y2-i,
+ x+tlw-i-1, y1+lineWidth);
+ p->drawPolyline(a);
+ }
+ }
+ p->setPen(oldPen);
+}
+
+/*!
+ \fn void qDrawShadeRect(QPainter *painter, int x, int y, int width, int height,
+ const QPalette &palette, bool sunken,
+ int lineWidth, int midLineWidth,
+ const QBrush *fill)
+ \relates <qdrawutil.h>
+
+ Draws the shaded rectangle beginning at (\a x, \a y) with the
+ given \a width and \a height using the provided \a painter.
+
+ The provide \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors. The given \a lineWidth
+ specifies the line width for each of the lines; it is not the
+ total line width. The \a midLineWidth specifies the width of a
+ middle line drawn in the QPalette::mid() color. The rectangle's
+ interior is filled with the \a fill brush unless \a fill is 0.
+
+ The rectangle appears sunken if \a sunken is true, otherwise
+ raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 1
+
+ \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
+*/
+
+void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken,
+ int lineWidth, int midLineWidth,
+ const QBrush *fill)
+{
+ if (w == 0 || h == 0)
+ return;
+ if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0 || midLineWidth < 0)) {
+ qWarning("qDrawShadeRect: Invalid parameters");
+ return;
+ }
+
+ PainterStateGuard painterGuard(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ painterGuard.save();
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ midLineWidth = qRound(devicePixelRatio * midLineWidth);
+ }
+
+ QPen oldPen = p->pen();
+ if (sunken)
+ p->setPen(pal.dark().color());
+ else
+ p->setPen(pal.light().color());
+ int x1=x, y1=y, x2=x+w-1, y2=y+h-1;
+
+ if (lineWidth == 1 && midLineWidth == 0) {// standard shade rectangle
+ p->drawRect(x1, y1, w-2, h-2);
+ if (sunken)
+ p->setPen(pal.light().color());
+ else
+ p->setPen(pal.dark().color());
+ QLineF lines[4] = { QLineF(x1+1, y1+1, x2-2, y1+1),
+ QLineF(x1+1, y1+2, x1+1, y2-2),
+ QLineF(x1, y2, x2, y2),
+ QLineF(x2,y1, x2,y2-1) };
+ p->drawLines(lines, 4); // draw bottom/right lines
+ } else { // more complicated
+ int m = lineWidth+midLineWidth;
+ int i, j=0, k=m;
+ for (i=0; i<lineWidth; i++) { // draw top shadow
+ QLineF lines[4] = { QLineF(x1+i, y2-i, x1+i, y1+i),
+ QLineF(x1+i, y1+i, x2-i, y1+i),
+ QLineF(x1+k, y2-k, x2-k, y2-k),
+ QLineF(x2-k, y2-k, x2-k, y1+k) };
+ p->drawLines(lines, 4);
+ k++;
+ }
+ p->setPen(pal.mid().color());
+ j = lineWidth*2;
+ for (i=0; i<midLineWidth; i++) { // draw lines in the middle
+ p->drawRect(x1+lineWidth+i, y1+lineWidth+i, w-j-1, h-j-1);
+ j += 2;
+ }
+ if (sunken)
+ p->setPen(pal.light().color());
+ else
+ p->setPen(pal.dark().color());
+ k = m;
+ for (i=0; i<lineWidth; i++) { // draw bottom shadow
+ QLineF lines[4] = { QLineF(x1+1+i, y2-i, x2-i, y2-i),
+ QLineF(x2-i, y2-i, x2-i, y1+i+1),
+ QLineF(x1+k, y2-k, x1+k, y1+k),
+ QLineF(x1+k, y1+k, x2-k, y1+k) };
+ p->drawLines(lines, 4);
+ k++;
+ }
+ }
+ if (fill) {
+ QBrush oldBrush = p->brush();
+ int tlw = lineWidth + midLineWidth;
+ p->setPen(Qt::NoPen);
+ p->setBrush(*fill);
+ p->drawRect(x+tlw, y+tlw, w-2*tlw, h-2*tlw);
+ p->setBrush(oldBrush);
+ }
+ p->setPen(oldPen); // restore pen
+}
+
+
+/*!
+ \fn void qDrawShadePanel(QPainter *painter, int x, int y, int width, int height,
+ const QPalette &palette, bool sunken,
+ int lineWidth, const QBrush *fill)
+ \relates <qdrawutil.h>
+
+ Draws the shaded panel beginning at (\a x, \a y) with the given \a
+ width and \a height using the provided \a painter and the given \a
+ lineWidth.
+
+ The given \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors). The panel's interior is filled
+ with the \a fill brush unless \a fill is 0.
+
+ The panel appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded panel:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 2
+
+ \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
+*/
+
+void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken,
+ int lineWidth, const QBrush *fill)
+{
+ if (w == 0 || h == 0)
+ return;
+ if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
+ qWarning("qDrawShadePanel: Invalid parameters");
+ }
+
+ PainterStateGuard painterGuard(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ painterGuard.save();
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ }
+
+ QColor shade = pal.dark().color();
+ QColor light = pal.light().color();
+ if (fill) {
+ if (fill->color() == shade)
+ shade = pal.shadow().color();
+ if (fill->color() == light)
+ light = pal.midlight().color();
+ }
+ QPen oldPen = p->pen(); // save pen
+ QVector<QLineF> lines;
+ lines.reserve(2*lineWidth);
+
+ if (sunken)
+ p->setPen(shade);
+ else
+ p->setPen(light);
+ int x1, y1, x2, y2;
+ int i;
+ x1 = x;
+ y1 = y2 = y;
+ x2 = x+w-2;
+ for (i=0; i<lineWidth; i++) { // top shadow
+ lines << QLineF(x1, y1++, x2--, y2++);
+ }
+ x2 = x1;
+ y1 = y+h-2;
+ for (i=0; i<lineWidth; i++) { // left shado
+ lines << QLineF(x1++, y1, x2++, y2--);
+ }
+ p->drawLines(lines);
+ lines.clear();
+ if (sunken)
+ p->setPen(light);
+ else
+ p->setPen(shade);
+ x1 = x;
+ y1 = y2 = y+h-1;
+ x2 = x+w-1;
+ for (i=0; i<lineWidth; i++) { // bottom shadow
+ lines << QLineF(x1++, y1--, x2, y2--);
+ }
+ x1 = x2;
+ y1 = y;
+ y2 = y+h-lineWidth-1;
+ for (i=0; i<lineWidth; i++) { // right shadow
+ lines << QLineF(x1--, y1++, x2--, y2);
+ }
+ p->drawLines(lines);
+ if (fill) // fill with fill color
+ p->fillRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2, *fill);
+ p->setPen(oldPen); // restore pen
+}
+
+
+/*!
+ \internal
+ This function draws a rectangle with two pixel line width.
+ It is called from qDrawWinButton() and qDrawWinPanel().
+
+ c1..c4 and fill are used:
+
+ 1 1 1 1 1 2
+ 1 3 3 3 4 2
+ 1 3 F F 4 2
+ 1 3 F F 4 2
+ 1 4 4 4 4 2
+ 2 2 2 2 2 2
+*/
+
+static void qDrawWinShades(QPainter *p,
+ int x, int y, int w, int h,
+ const QColor &c1, const QColor &c2,
+ const QColor &c3, const QColor &c4,
+ const QBrush *fill)
+{
+ if (w < 2 || h < 2) // can't do anything with that
+ return;
+
+ PainterStateGuard painterGuard(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ painterGuard.save();
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ }
+
+ QPen oldPen = p->pen();
+ QPoint a[3] = { QPoint(x, y+h-2), QPoint(x, y), QPoint(x+w-2, y) };
+ p->setPen(c1);
+ p->drawPolyline(a, 3);
+ QPoint b[3] = { QPoint(x, y+h-1), QPoint(x+w-1, y+h-1), QPoint(x+w-1, y) };
+ p->setPen(c2);
+ p->drawPolyline(b, 3);
+ if (w > 4 && h > 4) {
+ QPoint c[3] = { QPoint(x+1, y+h-3), QPoint(x+1, y+1), QPoint(x+w-3, y+1) };
+ p->setPen(c3);
+ p->drawPolyline(c, 3);
+ QPoint d[3] = { QPoint(x+1, y+h-2), QPoint(x+w-2, y+h-2), QPoint(x+w-2, y+1) };
+ p->setPen(c4);
+ p->drawPolyline(d, 3);
+ if (fill)
+ p->fillRect(QRect(x+2, y+2, w-4, h-4), *fill);
+ }
+ p->setPen(oldPen);
+}
+
+
+/*!
+ \fn void qDrawWinButton(QPainter *painter, int x, int y, int width, int height,
+ const QPalette &palette, bool sunken,
+ const QBrush *fill)
+ \relates <qdrawutil.h>
+
+ Draws the Windows-style button specified by the given point (\a x,
+ \a y}, \a width and \a height using the provided \a painter with a
+ line width of 2 pixels. The button's interior is filled with the
+ \a{fill} brush unless \a fill is 0.
+
+ The given \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors).
+
+ The button appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style()-> Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ \sa qDrawWinPanel(), QStyle
+*/
+
+void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken,
+ const QBrush *fill)
+{
+ if (sunken)
+ qDrawWinShades(p, x, y, w, h,
+ pal.shadow().color(), pal.light().color(), pal.dark().color(),
+ pal.button().color(), fill);
+ else
+ qDrawWinShades(p, x, y, w, h,
+ pal.light().color(), pal.shadow().color(), pal.button().color(),
+ pal.dark().color(), fill);
+}
+
+/*!
+ \fn void qDrawWinPanel(QPainter *painter, int x, int y, int width, int height,
+ const QPalette &palette, bool sunken,
+ const QBrush *fill)
+ \relates <qdrawutil.h>
+
+ Draws the Windows-style panel specified by the given point(\a x,
+ \a y), \a width and \a height using the provided \a painter with a
+ line width of 2 pixels. The button's interior is filled with the
+ \a fill brush unless \a fill is 0.
+
+ The given \a palette specifies the shading colors. The panel
+ appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded panel:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 3
+
+ \sa qDrawShadePanel(), qDrawWinButton(), QStyle
+*/
+
+void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken,
+ const QBrush *fill)
+{
+ if (sunken)
+ qDrawWinShades(p, x, y, w, h,
+ pal.dark().color(), pal.light().color(), pal.shadow().color(),
+ pal.midlight().color(), fill);
+ else
+ qDrawWinShades(p, x, y, w, h,
+ pal.light().color(), pal.shadow().color(), pal.midlight().color(),
+ pal.dark().color(), fill);
+}
+
+/*!
+ \fn void qDrawPlainRect(QPainter *painter, int x, int y, int width, int height, const QColor &lineColor,
+ int lineWidth, const QBrush *fill)
+ \relates <qdrawutil.h>
+
+ Draws the plain rectangle beginning at (\a x, \a y) with the given
+ \a width and \a height, using the specified \a painter, \a lineColor
+ and \a lineWidth. The rectangle's interior is filled with the \a
+ fill brush unless \a fill is 0.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a plain rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 4
+
+ \sa qDrawShadeRect(), QStyle
+*/
+
+void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &c,
+ int lineWidth, const QBrush *fill)
+{
+ if (w == 0 || h == 0)
+ return;
+ if (Q_UNLIKELY(w < 0 || h < 0 || lineWidth < 0)) {
+ qWarning("qDrawPlainRect: Invalid parameters");
+ }
+
+ PainterStateGuard painterGuard(p);
+ const qreal devicePixelRatio = p->device()->devicePixelRatioF();
+ if (!qFuzzyCompare(devicePixelRatio, qreal(1))) {
+ painterGuard.save();
+ const qreal inverseScale = qreal(1) / devicePixelRatio;
+ p->scale(inverseScale, inverseScale);
+ x = qRound(devicePixelRatio * x);
+ y = qRound(devicePixelRatio * y);
+ w = qRound(devicePixelRatio * w);
+ h = qRound(devicePixelRatio * h);
+ lineWidth = qRound(devicePixelRatio * lineWidth);
+ }
+
+ QPen oldPen = p->pen();
+ QBrush oldBrush = p->brush();
+ p->setPen(c);
+ p->setBrush(Qt::NoBrush);
+ for (int i=0; i<lineWidth; i++)
+ p->drawRect(x+i, y+i, w-i*2 - 1, h-i*2 - 1);
+ if (fill) { // fill with fill color
+ p->setPen(Qt::NoPen);
+ p->setBrush(*fill);
+ p->drawRect(x+lineWidth, y+lineWidth, w-lineWidth*2, h-lineWidth*2);
+ }
+ p->setPen(oldPen);
+ p->setBrush(oldBrush);
+}
+
+/*****************************************************************************
+ Overloaded functions.
+ *****************************************************************************/
+
+/*!
+ \fn void qDrawShadeLine(QPainter *painter, const QPoint &p1, const QPoint &p2,
+ const QPalette &palette, bool sunken, int lineWidth, int midLineWidth)
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws a horizontal or vertical shaded line between \a p1 and \a p2
+ using the given \a painter. Note that nothing is drawn if the line
+ between the points would be neither horizontal nor vertical.
+
+ The provided \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors). The given \a lineWidth
+ specifies the line width for each of the lines; it is not the
+ total line width. The given \a midLineWidth specifies the width of
+ a middle line drawn in the QPalette::mid() color.
+
+ The line appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to
+ make widgets that follow the current GUI style.
+
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded line:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 5
+
+ \sa qDrawShadeRect(), qDrawShadePanel(), QStyle
+*/
+
+void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
+ const QPalette &pal, bool sunken,
+ int lineWidth, int midLineWidth)
+{
+ qDrawShadeLine(p, p1.x(), p1.y(), p2.x(), p2.y(), pal, sunken,
+ lineWidth, midLineWidth);
+}
+
+/*!
+ \fn void qDrawShadeRect(QPainter *painter, const QRect &rect, const QPalette &palette,
+ bool sunken, int lineWidth, int midLineWidth, const QBrush *fill)
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws the shaded rectangle specified by \a rect using the given \a painter.
+
+ The provide \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors. The given \a lineWidth
+ specifies the line width for each of the lines; it is not the
+ total line width. The \a midLineWidth specifies the width of a
+ middle line drawn in the QPalette::mid() color. The rectangle's
+ interior is filled with the \a fill brush unless \a fill is 0.
+
+ The rectangle appears sunken if \a sunken is true, otherwise
+ raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 6
+
+ \sa qDrawShadeLine(), qDrawShadePanel(), qDrawPlainRect(), QStyle
+*/
+
+void qDrawShadeRect(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken,
+ int lineWidth, int midLineWidth,
+ const QBrush *fill)
+{
+ qDrawShadeRect(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
+ lineWidth, midLineWidth, fill);
+}
+
+/*!
+ \fn void qDrawShadePanel(QPainter *painter, const QRect &rect, const QPalette &palette,
+ bool sunken, int lineWidth, const QBrush *fill)
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws the shaded panel at the rectangle specified by \a rect using the
+ given \a painter and the given \a lineWidth.
+
+ The given \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors). The panel's interior is filled
+ with the \a fill brush unless \a fill is 0.
+
+ The panel appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded panel:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 7
+
+ \sa qDrawWinPanel(), qDrawShadeLine(), qDrawShadeRect(), QStyle
+*/
+
+void qDrawShadePanel(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken,
+ int lineWidth, const QBrush *fill)
+{
+ qDrawShadePanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken,
+ lineWidth, fill);
+}
+
+/*!
+ \fn void qDrawWinButton(QPainter *painter, const QRect &rect, const QPalette &palette,
+ bool sunken, const QBrush *fill)
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws the Windows-style button at the rectangle specified by \a rect using
+ the given \a painter with a line width of 2 pixels. The button's interior
+ is filled with the \a{fill} brush unless \a fill is 0.
+
+ The given \a palette specifies the shading colors (\l
+ {QPalette::light()}{light}, \l {QPalette::dark()}{dark} and \l
+ {QPalette::mid()}{middle} colors).
+
+ The button appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style()-> Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ \sa qDrawWinPanel(), QStyle
+*/
+
+void qDrawWinButton(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken, const QBrush *fill)
+{
+ qDrawWinButton(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
+}
+
+/*!
+ \fn void qDrawWinPanel(QPainter *painter, const QRect &rect, const QPalette &palette,
+ bool sunken, const QBrush *fill)
+ \overload
+
+ Draws the Windows-style panel at the rectangle specified by \a rect using
+ the given \a painter with a line width of 2 pixels. The button's interior
+ is filled with the \a fill brush unless \a fill is 0.
+
+ The given \a palette specifies the shading colors. The panel
+ appears sunken if \a sunken is true, otherwise raised.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a shaded panel:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 8
+
+ \sa qDrawShadePanel(), qDrawWinButton(), QStyle
+*/
+
+void qDrawWinPanel(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken, const QBrush *fill)
+{
+ qDrawWinPanel(p, r.x(), r.y(), r.width(), r.height(), pal, sunken, fill);
+}
+
+/*!
+ \fn void qDrawPlainRect(QPainter *painter, const QRect &rect, const QColor &lineColor, int lineWidth, const QBrush *fill)
+ \relates <qdrawutil.h>
+ \overload
+
+ Draws the plain rectangle specified by \a rect using the given \a painter,
+ \a lineColor and \a lineWidth. The rectangle's interior is filled with the
+ \a fill brush unless \a fill is 0.
+
+ \warning This function does not look at QWidget::style() or
+ QApplication::style(). Use the drawing functions in QStyle to make
+ widgets that follow the current GUI style.
+
+ Alternatively you can use a QFrame widget and apply the
+ QFrame::setFrameStyle() function to display a plain rectangle:
+
+ \snippet code/src_gui_painting_qdrawutil.cpp 9
+
+ \sa qDrawShadeRect(), QStyle
+*/
+
+void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &c,
+ int lineWidth, const QBrush *fill)
+{
+ qDrawPlainRect(p, r.x(), r.y(), r.width(), r.height(), c,
+ lineWidth, fill);
+}
+
+
+/*!
+ \class QTileRules
+ \since 4.6
+
+ \inmodule QtWidgets
+
+ \brief The QTileRules class provides the rules used to draw a
+ pixmap or image split into nine segments.
+
+ Spliiting is similar to \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}.
+
+ \sa Qt::TileRule, QMargins
+*/
+
+/*! \fn QTileRules::QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
+ Constructs a QTileRules with the given \a horizontalRule and
+ \a verticalRule.
+ */
+
+/*! \fn QTileRules::QTileRules(Qt::TileRule rule)
+ Constructs a QTileRules with the given \a rule used for both
+ the horizontal rule and the vertical rule.
+ */
+
+/*!
+ \fn void qDrawBorderPixmap(QPainter *painter, const QRect &target, const QMargins &margins, const QPixmap &pixmap)
+ \relates <qdrawutil.h>
+ \since 4.6
+
+ \brief The qDrawBorderPixmap function is for drawing a pixmap into
+ the margins of a rectangle.
+
+ Draws the given \a pixmap into the given \a target rectangle, using the
+ given \a painter. The pixmap will be split into nine segments and drawn
+ according to the \a margins structure.
+*/
+
+typedef QVarLengthArray<QPainter::PixmapFragment, 16> QPixmapFragmentsArray;
+
+/*!
+ \since 4.6
+
+ Draws the indicated \a sourceRect rectangle from the given \a pixmap into
+ the given \a targetRect rectangle, using the given \a painter. The pixmap
+ will be split into nine segments according to the given \a targetMargins
+ and \a sourceMargins structures. Finally, the pixmap will be drawn
+ according to the given \a rules.
+
+ This function is used to draw a scaled pixmap, similar to
+ \l{http://www.w3.org/TR/css3-background/}{CSS3 border-images}
+
+ \sa Qt::TileRule, QTileRules, QMargins
+*/
+
+void qDrawBorderPixmap(QPainter *painter, const QRect &targetRect, const QMargins &targetMargins,
+ const QPixmap &pixmap, const QRect &sourceRect,const QMargins &sourceMargins,
+ const QTileRules &rules
+#ifndef Q_CLANG_QDOC
+ , QDrawBorderPixmap::DrawingHints hints
+#endif
+ )
+{
+ QPainter::PixmapFragment d;
+ d.opacity = 1.0;
+ d.rotation = 0.0;
+
+ QPixmapFragmentsArray opaqueData;
+ QPixmapFragmentsArray translucentData;
+
+ // source center
+ const int sourceCenterTop = sourceRect.top() + sourceMargins.top();
+ const int sourceCenterLeft = sourceRect.left() + sourceMargins.left();
+ const int sourceCenterBottom = sourceRect.bottom() - sourceMargins.bottom() + 1;
+ const int sourceCenterRight = sourceRect.right() - sourceMargins.right() + 1;
+ const int sourceCenterWidth = sourceCenterRight - sourceCenterLeft;
+ const int sourceCenterHeight = sourceCenterBottom - sourceCenterTop;
+ // target center
+ const int targetCenterTop = targetRect.top() + targetMargins.top();
+ const int targetCenterLeft = targetRect.left() + targetMargins.left();
+ const int targetCenterBottom = targetRect.bottom() - targetMargins.bottom() + 1;
+ const int targetCenterRight = targetRect.right() - targetMargins.right() + 1;
+ const int targetCenterWidth = targetCenterRight - targetCenterLeft;
+ const int targetCenterHeight = targetCenterBottom - targetCenterTop;
+
+ QVarLengthArray<qreal, 16> xTarget; // x-coordinates of target rectangles
+ QVarLengthArray<qreal, 16> yTarget; // y-coordinates of target rectangles
+
+ int columns = 3;
+ int rows = 3;
+ if (rules.horizontal != Qt::StretchTile && sourceCenterWidth != 0)
+ columns = qMax(3, 2 + qCeil(targetCenterWidth / qreal(sourceCenterWidth)));
+ if (rules.vertical != Qt::StretchTile && sourceCenterHeight != 0)
+ rows = qMax(3, 2 + qCeil(targetCenterHeight / qreal(sourceCenterHeight)));
+
+ xTarget.resize(columns + 1);
+ yTarget.resize(rows + 1);
+
+ bool oldAA = painter->testRenderHint(QPainter::Antialiasing);
+ if (painter->paintEngine()->type() != QPaintEngine::OpenGL
+ && painter->paintEngine()->type() != QPaintEngine::OpenGL2
+ && oldAA && painter->combinedTransform().type() != QTransform::TxNone) {
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ }
+
+ xTarget[0] = targetRect.left();
+ xTarget[1] = targetCenterLeft;
+ xTarget[columns - 1] = targetCenterRight;
+ xTarget[columns] = targetRect.left() + targetRect.width();
+
+ yTarget[0] = targetRect.top();
+ yTarget[1] = targetCenterTop;
+ yTarget[rows - 1] = targetCenterBottom;
+ yTarget[rows] = targetRect.top() + targetRect.height();
+
+ qreal dx = targetCenterWidth;
+ qreal dy = targetCenterHeight;
+
+ switch (rules.horizontal) {
+ case Qt::StretchTile:
+ dx = targetCenterWidth;
+ break;
+ case Qt::RepeatTile:
+ dx = sourceCenterWidth;
+ break;
+ case Qt::RoundTile:
+ dx = targetCenterWidth / qreal(columns - 2);
+ break;
+ }
+
+ for (int i = 2; i < columns - 1; ++i)
+ xTarget[i] = xTarget[i - 1] + dx;
+
+ switch (rules.vertical) {
+ case Qt::StretchTile:
+ dy = targetCenterHeight;
+ break;
+ case Qt::RepeatTile:
+ dy = sourceCenterHeight;
+ break;
+ case Qt::RoundTile:
+ dy = targetCenterHeight / qreal(rows - 2);
+ break;
+ }
+
+ for (int i = 2; i < rows - 1; ++i)
+ yTarget[i] = yTarget[i - 1] + dy;
+
+ // corners
+ if (targetMargins.top() > 0 && targetMargins.left() > 0 && sourceMargins.top() > 0 && sourceMargins.left() > 0) { // top left
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceRect.top();
+ d.width = sourceMargins.left();
+ d.height = sourceMargins.top();
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueTopLeft)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.top() > 0 && targetMargins.right() > 0 && sourceMargins.top() > 0 && sourceMargins.right() > 0) { // top right
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceRect.top();
+ d.width = sourceMargins.right();
+ d.height = sourceMargins.top();
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueTopRight)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.bottom() > 0 && targetMargins.left() > 0 && sourceMargins.bottom() > 0 && sourceMargins.left() > 0) { // bottom left
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.y =(0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceMargins.left();
+ d.height = sourceMargins.bottom();
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueBottomLeft)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+ if (targetMargins.bottom() > 0 && targetMargins.right() > 0 && sourceMargins.bottom() > 0 && sourceMargins.right() > 0) { // bottom right
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceMargins.right();
+ d.height = sourceMargins.bottom();
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ if (hints & QDrawBorderPixmap::OpaqueBottomRight)
+ opaqueData.append(d);
+ else
+ translucentData.append(d);
+ }
+
+ // horizontal edges
+ if (targetCenterWidth > 0 && sourceCenterWidth > 0) {
+ if (targetMargins.top() > 0 && sourceMargins.top() > 0) { // top
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueTop ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceRect.top();
+ d.width = sourceCenterWidth;
+ d.height = sourceMargins.top();
+ d.y = (0.5 * (yTarget[1] + yTarget[0]));
+ d.scaleX = dx / d.width;
+ d.scaleY = qreal(yTarget[1] - yTarget[0]) / d.height;
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
+ }
+ if (targetMargins.bottom() > 0 && sourceMargins.bottom() > 0) { // bottom
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueBottom ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceCenterBottom;
+ d.width = sourceCenterWidth;
+ d.height = sourceMargins.bottom();
+ d.y = (0.5 * (yTarget[rows] + yTarget[rows - 1]));
+ d.scaleX = dx / d.width;
+ d.scaleY = qreal(yTarget[rows] - yTarget[rows - 1]) / d.height;
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = ((xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX);
+ }
+ }
+
+ // vertical edges
+ if (targetCenterHeight > 0 && sourceCenterHeight > 0) {
+ if (targetMargins.left() > 0 && sourceMargins.left() > 0) { // left
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueLeft ? opaqueData : translucentData;
+ d.sourceLeft = sourceRect.left();
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceMargins.left();
+ d.height = sourceCenterHeight;
+ d.x = (0.5 * (xTarget[1] + xTarget[0]));
+ d.scaleX = qreal(xTarget[1] - xTarget[0]) / d.width;
+ d.scaleY = dy / d.height;
+ for (int i = 1; i < rows - 1; ++i) {
+ d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
+ data.append(d);
+ }
+ if (rules.vertical == Qt::RepeatTile)
+ data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
+ }
+ if (targetMargins.right() > 0 && sourceMargins.right() > 0) { // right
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueRight ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterRight;
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceMargins.right();
+ d.height = sourceCenterHeight;
+ d.x = (0.5 * (xTarget[columns] + xTarget[columns - 1]));
+ d.scaleX = qreal(xTarget[columns] - xTarget[columns - 1]) / d.width;
+ d.scaleY = dy / d.height;
+ for (int i = 1; i < rows - 1; ++i) {
+ d.y = (0.5 * (yTarget[i + 1] + yTarget[i]));
+ data.append(d);
+ }
+ if (rules.vertical == Qt::RepeatTile)
+ data[data.size() - 1].height = ((yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY);
+ }
+ }
+
+ // center
+ if (targetCenterWidth > 0 && targetCenterHeight > 0 && sourceCenterWidth > 0 && sourceCenterHeight > 0) {
+ QPixmapFragmentsArray &data = hints & QDrawBorderPixmap::OpaqueCenter ? opaqueData : translucentData;
+ d.sourceLeft = sourceCenterLeft;
+ d.sourceTop = sourceCenterTop;
+ d.width = sourceCenterWidth;
+ d.height = sourceCenterHeight;
+ d.scaleX = dx / d.width;
+ d.scaleY = dy / d.height;
+
+ qreal repeatWidth = (xTarget[columns - 1] - xTarget[columns - 2]) / d.scaleX;
+ qreal repeatHeight = (yTarget[rows - 1] - yTarget[rows - 2]) / d.scaleY;
+
+ for (int j = 1; j < rows - 1; ++j) {
+ d.y = (0.5 * (yTarget[j + 1] + yTarget[j]));
+ for (int i = 1; i < columns - 1; ++i) {
+ d.x = (0.5 * (xTarget[i + 1] + xTarget[i]));
+ data.append(d);
+ }
+ if (rules.horizontal == Qt::RepeatTile)
+ data[data.size() - 1].width = repeatWidth;
+ }
+ if (rules.vertical == Qt::RepeatTile) {
+ for (int i = 1; i < columns - 1; ++i)
+ data[data.size() - i].height = repeatHeight;
+ }
+ }
+
+ if (opaqueData.size())
+ painter->drawPixmapFragments(opaqueData.data(), opaqueData.size(), pixmap, QPainter::OpaqueHint);
+ if (translucentData.size())
+ painter->drawPixmapFragments(translucentData.data(), translucentData.size(), pixmap);
+
+ if (oldAA)
+ painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/qquickdrawutil.h b/src/quicknativestyle/qstyle/qquickdrawutil.h
new file mode 100644
index 0000000000..4f7a6c2ecd
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickdrawutil.h
@@ -0,0 +1,170 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDRAWUTIL_H
+#define QDRAWUTIL_H
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qstring.h> // char*->QString conversion
+#include <QtCore/qmargins.h>
+#include <QtGui/qpixmap.h>
+
+QT_BEGIN_NAMESPACE
+
+
+class QPainter;
+class QPalette;
+class QPoint;
+class QColor;
+class QBrush;
+class QRect;
+
+namespace QQC2 {
+
+//
+// Standard shade drawing
+//
+
+void qDrawShadeLine(QPainter *p, int x1, int y1, int x2, int y2,
+ const QPalette &pal, bool sunken = true,
+ int lineWidth = 1, int midLineWidth = 0);
+
+void qDrawShadeLine(QPainter *p, const QPoint &p1, const QPoint &p2,
+ const QPalette &pal, bool sunken = true,
+ int lineWidth = 1, int midLineWidth = 0);
+
+void qDrawShadeRect(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken = false,
+ int lineWidth = 1, int midLineWidth = 0,
+ const QBrush *fill = nullptr);
+
+void qDrawShadeRect(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken = false,
+ int lineWidth = 1, int midLineWidth = 0,
+ const QBrush *fill = nullptr);
+
+void qDrawShadePanel(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken = false,
+ int lineWidth = 1, const QBrush *fill = nullptr);
+
+void qDrawShadePanel(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken = false,
+ int lineWidth = 1, const QBrush *fill = nullptr);
+
+void qDrawWinButton(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken = false,
+ const QBrush *fill = nullptr);
+
+void qDrawWinButton(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken = false,
+ const QBrush *fill = nullptr);
+
+void qDrawWinPanel(QPainter *p, int x, int y, int w, int h,
+ const QPalette &pal, bool sunken = false,
+ const QBrush *fill = nullptr);
+
+void qDrawWinPanel(QPainter *p, const QRect &r,
+ const QPalette &pal, bool sunken = false,
+ const QBrush *fill = nullptr);
+
+void qDrawPlainRect(QPainter *p, int x, int y, int w, int h, const QColor &,
+ int lineWidth = 1, const QBrush *fill = nullptr);
+
+void qDrawPlainRect(QPainter *p, const QRect &r, const QColor &,
+ int lineWidth = 1, const QBrush *fill = nullptr);
+
+
+
+struct QTileRules
+{
+ inline QTileRules(Qt::TileRule horizontalRule, Qt::TileRule verticalRule)
+ : horizontal(horizontalRule), vertical(verticalRule) {}
+ inline QTileRules(Qt::TileRule rule = Qt::StretchTile)
+ : horizontal(rule), vertical(rule) {}
+ Qt::TileRule horizontal;
+ Qt::TileRule vertical;
+};
+
+#ifndef Q_CLANG_QDOC
+// For internal use only.
+namespace QDrawBorderPixmap
+{
+ enum DrawingHint
+ {
+ OpaqueTopLeft = 0x0001,
+ OpaqueTop = 0x0002,
+ OpaqueTopRight = 0x0004,
+ OpaqueLeft = 0x0008,
+ OpaqueCenter = 0x0010,
+ OpaqueRight = 0x0020,
+ OpaqueBottomLeft = 0x0040,
+ OpaqueBottom = 0x0080,
+ OpaqueBottomRight = 0x0100,
+ OpaqueCorners = OpaqueTopLeft | OpaqueTopRight | OpaqueBottomLeft | OpaqueBottomRight,
+ OpaqueEdges = OpaqueTop | OpaqueLeft | OpaqueRight | OpaqueBottom,
+ OpaqueFrame = OpaqueCorners | OpaqueEdges,
+ OpaqueAll = OpaqueCenter | OpaqueFrame
+ };
+
+ Q_DECLARE_FLAGS(DrawingHints, DrawingHint)
+}
+#endif
+
+void qDrawBorderPixmap(QPainter *painter,
+ const QRect &targetRect,
+ const QMargins &targetMargins,
+ const QPixmap &pixmap,
+ const QRect &sourceRect,
+ const QMargins &sourceMargins,
+ const QTileRules &rules = QTileRules()
+#ifndef Q_CLANG_QDOC
+ , QDrawBorderPixmap::DrawingHints hints = QDrawBorderPixmap::DrawingHints()
+#endif
+ );
+
+inline void qDrawBorderPixmap(QPainter *painter,
+ const QRect &target,
+ const QMargins &margins,
+ const QPixmap &pixmap)
+{
+ qDrawBorderPixmap(painter, target, margins, pixmap, pixmap.rect(), margins);
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QDRAWUTIL_H
diff --git a/src/quicknativestyle/qstyle/qquicknativestyle.cpp b/src/quicknativestyle/qstyle/qquicknativestyle.cpp
new file mode 100644
index 0000000000..7a2030e06d
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquicknativestyle.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicknativestyle.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+QStyle *QQuickNativeStyle::s_style = nullptr;
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/qquicknativestyle.h b/src/quicknativestyle/qstyle/qquicknativestyle.h
new file mode 100644
index 0000000000..13c313f0d8
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquicknativestyle.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKNATIVESTYLE_H
+#define QQUICKNATIVESTYLE_H
+
+#include "qquickstyle.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+class QQuickNativeStyle
+{
+public:
+ static void setStyle(QStyle *style)
+ {
+ if (s_style)
+ delete s_style;
+ s_style = style;
+ }
+
+ inline static QStyle *style()
+ {
+ return s_style;
+ }
+
+private:
+ static QStyle *s_style;
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QQUICKNATIVESTYLE_H
diff --git a/src/quicknativestyle/qstyle/qquickstyle.cpp b/src/quicknativestyle/qstyle/qquickstyle.cpp
new file mode 100644
index 0000000000..2278fb6532
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstyle.cpp
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyle.h"
+#include "qquickstyle_p.h"
+#include "qquickstyleoption.h"
+
+#include <QtGui/qpainter.h>
+#include <QtGui/qbitmap.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qpa/qplatformtheme.h>
+
+#include <QtGui/private/qguiapplication_p.h>
+
+#ifndef QT_NO_DEBUG
+# include <QtCore/qdebug.h>
+#endif
+
+#include <limits.h>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+/*!
+ Constructs a style object.
+*/
+QStyle::QStyle()
+ : QObject(*new QStylePrivate)
+{
+ Q_D(QStyle);
+ d->proxyStyle = this;
+}
+
+/*!
+ \internal
+
+ Constructs a style object.
+*/
+QStyle::QStyle(QStylePrivate &dd)
+ : QObject(dd)
+{
+ Q_D(QStyle);
+ d->proxyStyle = this;
+}
+
+/*!
+ Destroys the style object.
+*/
+QStyle::~QStyle()
+{
+}
+
+/*!
+ \fn QRect QStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rectangle, int alignment, bool enabled, const QString &text) const
+
+ Returns the area within the given \a rectangle in which to draw
+ the provided \a text according to the specified font \a metrics
+ and \a alignment. The \a enabled parameter indicates whether or
+ not the associated item is enabled.
+
+ If the given \a rectangle is larger than the area needed to render
+ the \a text, the rectangle that is returned will be offset within
+ \a rectangle according to the specified \a alignment. For
+ example, if \a alignment is Qt::AlignCenter, the returned
+ rectangle will be centered within \a rectangle. If the given \a
+ rectangle is smaller than the area needed, the returned rectangle
+ will be the smallest rectangle large enough to render the \a text.
+
+ \sa Qt::Alignment
+*/
+QRect QStyle::itemTextRect(const QFontMetrics &metrics, const QRect &rect, int alignment, bool enabled,
+ const QString &text) const
+{
+ QRect result;
+ int x, y, w, h;
+ rect.getRect(&x, &y, &w, &h);
+ if (!text.isEmpty()) {
+ result = metrics.boundingRect(x, y, w, h, alignment, text);
+ if (!enabled && proxy()->styleHint(SH_EtchDisabledText)) {
+ result.setWidth(result.width()+1);
+ result.setHeight(result.height()+1);
+ }
+ } else {
+ result = QRect(x, y, w, h);
+ }
+ return result;
+}
+
+/*!
+ \fn QRect QStyle::itemPixmapRect(const QRect &rectangle, int alignment, const QPixmap &pixmap) const
+
+ Returns the area within the given \a rectangle in which to draw
+ the specified \a pixmap according to the defined \a alignment.
+*/
+QRect QStyle::itemPixmapRect(const QRect &rect, int alignment, const QPixmap &pixmap) const
+{
+ QRect result;
+ int x, y, w, h;
+ rect.getRect(&x, &y, &w, &h);
+
+ const int pixmapWidth = pixmap.width()/pixmap.devicePixelRatio();
+ const int pixmapHeight = pixmap.height()/pixmap.devicePixelRatio();
+
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += h/2 - pixmapHeight/2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += h - pixmapHeight;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += w - pixmapWidth;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += w/2 - pixmapWidth/2;
+ else if ((alignment & Qt::AlignLeft) != Qt::AlignLeft && QGuiApplication::isRightToLeft())
+ x += w - pixmapWidth;
+ result = QRect(x, y, pixmapWidth, pixmapHeight);
+ return result;
+}
+
+/*!
+ \fn void QStyle::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString& text, QPalette::ColorRole textRole) const
+
+ Draws the given \a text in the specified \a rectangle using the
+ provided \a painter and \a palette.
+
+ The text is drawn using the painter's pen, and aligned and wrapped
+ according to the specified \a alignment. If an explicit \a
+ textRole is specified, the text is drawn using the \a palette's
+ color for the given role. The \a enabled parameter indicates
+ whether or not the item is enabled; when reimplementing this
+ function, the \a enabled parameter should influence how the item is
+ drawn.
+
+ \sa Qt::Alignment, drawItemPixmap()
+*/
+void QStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal,
+ bool enabled, const QString& text, QPalette::ColorRole textRole) const
+{
+ if (text.isEmpty())
+ return;
+ QPen savedPen;
+ if (textRole != QPalette::NoRole) {
+ savedPen = painter->pen();
+ painter->setPen(QPen(pal.brush(textRole), savedPen.widthF()));
+ }
+ if (!enabled) {
+ if (proxy()->styleHint(SH_DitherDisabledText)) {
+ QRect br;
+ painter->drawText(rect, alignment, text, &br);
+ painter->fillRect(br, QBrush(painter->background().color(), Qt::Dense5Pattern));
+ return;
+ } else if (proxy()->styleHint(SH_EtchDisabledText)) {
+ QPen pen = painter->pen();
+ painter->setPen(pal.light().color());
+ painter->drawText(rect.adjusted(1, 1, 1, 1), alignment, text);
+ painter->setPen(pen);
+ }
+ }
+ painter->drawText(rect, alignment, text);
+ if (textRole != QPalette::NoRole)
+ painter->setPen(savedPen);
+}
+
+/*!
+ \fn void QStyle::drawItemPixmap(QPainter *painter, const QRect &rectangle, int alignment,
+ const QPixmap &pixmap) const
+
+ Draws the given \a pixmap in the specified \a rectangle, according
+ to the specified \a alignment, using the provided \a painter.
+
+ \sa drawItemText()
+*/
+
+void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
+ const QPixmap &pixmap) const
+{
+ qreal scale = pixmap.devicePixelRatio();
+ QRect aligned = alignedRect(QGuiApplication::layoutDirection(), QFlag(alignment), pixmap.size() / scale, rect);
+ QRect inter = aligned.intersected(rect);
+
+ painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), inter.width() * scale, inter.height() *scale);
+}
+
+/*!
+ \fn QRect QStyle::visualRect(Qt::LayoutDirection direction, const QRect &boundingRectangle, const QRect &logicalRectangle)
+
+ Returns the given \a logicalRectangle converted to screen
+ coordinates based on the specified \a direction. The \a
+ boundingRectangle is used when performing the translation.
+
+ This function is provided to support right-to-left desktops, and
+ is typically used in implementations of the subControlRect()
+ function.
+
+ \sa QWidget::layoutDirection
+*/
+QRect QStyle::visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect)
+{
+ if (direction == Qt::LeftToRight)
+ return logicalRect;
+ QRect rect = logicalRect;
+ rect.translate(2 * (boundingRect.right() - logicalRect.right()) +
+ logicalRect.width() - boundingRect.width(), 0);
+ return rect;
+}
+
+/*!
+ \fn QPoint QStyle::visualPos(Qt::LayoutDirection direction, const QRect &boundingRectangle, const QPoint &logicalPosition)
+
+ Returns the given \a logicalPosition converted to screen
+ coordinates based on the specified \a direction. The \a
+ boundingRectangle is used when performing the translation.
+
+ \sa QWidget::layoutDirection
+*/
+QPoint QStyle::visualPos(Qt::LayoutDirection direction, const QRect &boundingRect, const QPoint &logicalPos)
+{
+ if (direction == Qt::LeftToRight)
+ return logicalPos;
+ return QPoint(boundingRect.right() - logicalPos.x(), logicalPos.y());
+}
+
+/*!
+ Returns a new rectangle of the specified \a size that is aligned to the given \a
+ rectangle according to the specified \a alignment and \a direction.
+ */
+QRect QStyle::alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
+{
+ alignment = visualAlignment(direction, alignment);
+ int x = rectangle.x();
+ int y = rectangle.y();
+ int w = size.width();
+ int h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += rectangle.size().height()/2 - h/2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rectangle.size().height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rectangle.size().width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += rectangle.size().width()/2 - w/2;
+ return QRect(x, y, w, h);
+}
+
+/*!
+ Transforms an \a alignment of Qt::AlignLeft or Qt::AlignRight
+ without Qt::AlignAbsolute into Qt::AlignLeft or Qt::AlignRight with
+ Qt::AlignAbsolute according to the layout \a direction. The other
+ alignment flags are left untouched.
+
+ If no horizontal alignment was specified, the function returns the
+ default alignment for the given layout \a direction.
+
+ QWidget::layoutDirection
+*/
+Qt::Alignment QStyle::visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment)
+{
+ return QGuiApplicationPrivate::visualAlignment(direction, alignment);
+}
+
+/*!
+ Converts the given \a logicalValue to a pixel position. The \a min
+ parameter maps to 0, \a max maps to \a span and other values are
+ distributed evenly in-between.
+
+ This function can handle the entire integer range without
+ overflow, providing that \a span is less than 4096.
+
+ By default, this function assumes that the maximum value is on the
+ right for horizontal items and on the bottom for vertical items.
+ Set the \a upsideDown parameter to true to reverse this behavior.
+
+ \sa sliderValueFromPosition()
+*/
+
+int QStyle::sliderPositionFromValue(int min, int max, int logicalValue, int span, bool upsideDown)
+{
+ if (span <= 0 || logicalValue < min || max <= min)
+ return 0;
+ if (logicalValue > max)
+ return upsideDown ? span : min;
+
+ uint range = max - min;
+ uint p = upsideDown ? max - logicalValue : logicalValue - min;
+
+ if (range > (uint)INT_MAX/4096) {
+ double dpos = (double(p))/(double(range)/span);
+ return int(dpos);
+ } else if (range > (uint)span) {
+ return (2 * p * span + range) / (2*range);
+ } else {
+ uint div = span / range;
+ uint mod = span % range;
+ return p * div + (2 * p * mod + range) / (2 * range);
+ }
+ // equiv. to (p * span) / range + 0.5
+ // no overflow because of this implicit assumption:
+ // span <= 4096
+}
+
+/*!
+ \fn int QStyle::sliderValueFromPosition(int min, int max, int position, int span, bool upsideDown)
+
+ Converts the given pixel \a position to a logical value. 0 maps to
+ the \a min parameter, \a span maps to \a max and other values are
+ distributed evenly in-between.
+
+ This function can handle the entire integer range without
+ overflow.
+
+ By default, this function assumes that the maximum value is on the
+ right for horizontal items and on the bottom for vertical
+ items. Set the \a upsideDown parameter to true to reverse this
+ behavior.
+
+ \sa sliderPositionFromValue()
+*/
+
+int QStyle::sliderValueFromPosition(int min, int max, int pos, int span, bool upsideDown)
+{
+ if (span <= 0 || pos <= 0)
+ return upsideDown ? max : min;
+ if (pos >= span)
+ return upsideDown ? min : max;
+
+ uint range = max - min;
+
+ if ((uint)span > range) {
+ int tmp = (2 * pos * range + span) / (2 * span);
+ return upsideDown ? max - tmp : tmp + min;
+ } else {
+ uint div = range / span;
+ uint mod = range % span;
+ int tmp = pos * div + (2 * pos * mod + span) / (2 * span);
+ return upsideDown ? max - tmp : tmp + min;
+ }
+ // equiv. to min + (pos*range)/span + 0.5
+ // no overflow because of this implicit assumption:
+ // pos <= span < sqrt(INT_MAX+0.0625)+0.25 ~ sqrt(INT_MAX)
+}
+
+/*!
+ Returns the style's standard palette.
+
+ Note that on systems that support system colors, the style's
+ standard palette is not used. In particular, the Windows
+ Vista and Mac styles do not use the standard palette, but make
+ use of native theme engines. With these styles, you should not set
+ the palette with QApplication::setPalette().
+
+ \sa QApplication::setPalette()
+ */
+QPalette QStyle::standardPalette() const
+{
+ QColor background = QColor(0xd4, 0xd0, 0xc8); // win 2000 grey
+
+ QColor light(background.lighter());
+ QColor dark(background.darker());
+ QColor mid(Qt::gray);
+ QPalette palette(Qt::black, background, light, dark, mid, Qt::black, Qt::white);
+ palette.setBrush(QPalette::Disabled, QPalette::WindowText, dark);
+ palette.setBrush(QPalette::Disabled, QPalette::Text, dark);
+ palette.setBrush(QPalette::Disabled, QPalette::ButtonText, dark);
+ palette.setBrush(QPalette::Disabled, QPalette::Base, background);
+ return palette;
+}
+
+//Windows and KDE allow menus to cover the taskbar, while GNOME and macOS don't
+bool QStylePrivate::useFullScreenForPopup()
+{
+ auto theme = QGuiApplicationPrivate::platformTheme();
+ return theme && theme->themeHint(QPlatformTheme::UseFullScreenForPopupMenu).toBool();
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstyle.cpp"
diff --git a/src/quicknativestyle/qstyle/qquickstyle.h b/src/quicknativestyle/qstyle/qquickstyle.h
new file mode 100644
index 0000000000..38a0dcf5bd
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstyle.h
@@ -0,0 +1,839 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTYLE_H
+#define QSTYLE_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qsize.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/qicon.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAction;
+class QDebug;
+class QFontMetrics;
+
+namespace QQC2 {
+
+class QStyleHintReturn;
+class QStyleOption;
+class QStyleOptionComplex;
+class QStylePrivate;
+
+class QStyle : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QStyle)
+
+protected:
+ QStyle(QStylePrivate &dd);
+
+public:
+ QStyle();
+ virtual ~QStyle();
+
+ enum StateFlag {
+ State_None = 0x00000000,
+ State_Enabled = 0x00000001,
+ State_Raised = 0x00000002,
+ State_Sunken = 0x00000004,
+ State_Off = 0x00000008,
+ State_NoChange = 0x00000010,
+ State_On = 0x00000020,
+ State_DownArrow = 0x00000040,
+ State_Horizontal = 0x00000080,
+ State_HasFocus = 0x00000100,
+ State_Top = 0x00000200,
+ State_Bottom = 0x00000400,
+ State_FocusAtBorder = 0x00000800,
+ State_AutoRaise = 0x00001000,
+ State_MouseOver = 0x00002000,
+ State_UpArrow = 0x00004000,
+ State_Selected = 0x00008000,
+ State_Active = 0x00010000,
+ State_Window = 0x00020000,
+ State_Open = 0x00040000,
+ State_Children = 0x00080000,
+ State_Item = 0x00100000,
+ State_Sibling = 0x00200000,
+ State_Editing = 0x00400000,
+ State_KeyboardFocusChange = 0x00800000,
+#ifdef QT_KEYPAD_NAVIGATION
+ State_HasEditFocus = 0x01000000,
+#endif
+ State_ReadOnly = 0x02000000,
+ State_Small = 0x04000000,
+ State_Mini = 0x08000000
+ };
+ Q_ENUM(StateFlag)
+ Q_DECLARE_FLAGS(State, StateFlag)
+
+ enum PrimitiveElement {
+ PE_Frame,
+ PE_FrameDefaultButton,
+ PE_FrameDockWidget,
+ PE_FrameFocusRect,
+ PE_FrameGroupBox,
+ PE_FrameLineEdit,
+ PE_FrameMenu,
+ PE_FrameStatusBarItem,
+ PE_FrameTabWidget,
+ PE_FrameWindow,
+ PE_FrameButtonBevel,
+ PE_FrameButtonTool,
+ PE_FrameTabBarBase,
+
+ PE_PanelButtonCommand,
+ PE_PanelButtonBevel,
+ PE_PanelButtonTool,
+ PE_PanelMenuBar,
+ PE_PanelToolBar,
+ PE_PanelLineEdit,
+
+ PE_IndicatorArrowDown,
+ PE_IndicatorArrowLeft,
+ PE_IndicatorArrowRight,
+ PE_IndicatorArrowUp,
+ PE_IndicatorBranch,
+ PE_IndicatorButtonDropDown,
+ PE_IndicatorItemViewItemCheck,
+ PE_IndicatorCheckBox,
+ PE_IndicatorDockWidgetResizeHandle,
+ PE_IndicatorHeaderArrow,
+ PE_IndicatorMenuCheckMark,
+ PE_IndicatorProgressChunk,
+ PE_IndicatorRadioButton,
+ PE_IndicatorSpinDown,
+ PE_IndicatorSpinMinus,
+ PE_IndicatorSpinPlus,
+ PE_IndicatorSpinUp,
+ PE_IndicatorToolBarHandle,
+ PE_IndicatorToolBarSeparator,
+ PE_PanelTipLabel,
+ PE_IndicatorTabTear,
+ PE_IndicatorTabTearLeft = PE_IndicatorTabTear,
+ PE_PanelScrollAreaCorner,
+
+ PE_Widget,
+
+ PE_IndicatorColumnViewArrow,
+ PE_IndicatorItemViewItemDrop,
+
+ PE_PanelItemViewItem,
+ PE_PanelItemViewRow, // ### Qt 6: remove
+
+ PE_PanelStatusBar,
+
+ PE_IndicatorTabClose,
+ PE_PanelMenu,
+
+ PE_IndicatorTabTearRight,
+
+ // do not add any values below/greater this
+ PE_CustomBase = 0xf000000
+ };
+ Q_ENUM(PrimitiveElement)
+
+ enum ControlElement {
+ CE_PushButton,
+ CE_PushButtonBevel,
+ CE_PushButtonLabel,
+
+ CE_CheckBox,
+ CE_CheckBoxLabel,
+
+ CE_RadioButton,
+ CE_RadioButtonLabel,
+
+ CE_TabBarTab,
+ CE_TabBarTabShape,
+ CE_TabBarTabLabel,
+
+ CE_ProgressBar,
+ CE_ProgressBarGroove,
+ CE_ProgressBarContents,
+ CE_ProgressBarLabel,
+
+ CE_MenuItem,
+ CE_MenuScroller,
+ CE_MenuVMargin,
+ CE_MenuHMargin,
+ CE_MenuTearoff,
+ CE_MenuEmptyArea,
+
+ CE_MenuBarItem,
+ CE_MenuBarEmptyArea,
+
+ CE_ToolButtonLabel,
+
+ CE_Header,
+ CE_HeaderSection,
+ CE_HeaderLabel,
+
+ CE_ToolBoxTab,
+ CE_SizeGrip,
+ CE_Splitter,
+ CE_RubberBand,
+ CE_DockWidgetTitle,
+
+ CE_ScrollBarAddLine,
+ CE_ScrollBarSubLine,
+ CE_ScrollBarAddPage,
+ CE_ScrollBarSubPage,
+ CE_ScrollBarSlider,
+ CE_ScrollBarFirst,
+ CE_ScrollBarLast,
+
+ CE_FocusFrame,
+ CE_ComboBoxLabel,
+
+ CE_ToolBar,
+ CE_ToolBoxTabShape,
+ CE_ToolBoxTabLabel,
+ CE_HeaderEmptyArea,
+
+ CE_ColumnViewGrip,
+
+ CE_ItemViewItem,
+
+ CE_ShapedFrame,
+
+ // do not add any values below/greater than this
+ CE_CustomBase = 0xf0000000
+ };
+ Q_ENUM(ControlElement)
+
+ enum SubElement {
+ SE_PushButtonContents,
+ SE_PushButtonFocusRect,
+
+ SE_CheckBoxIndicator,
+ SE_CheckBoxContents,
+ SE_CheckBoxFocusRect,
+ SE_CheckBoxClickRect,
+
+ SE_RadioButtonIndicator,
+ SE_RadioButtonContents,
+ SE_RadioButtonFocusRect,
+ SE_RadioButtonClickRect,
+
+ SE_ComboBoxFocusRect,
+
+ SE_SliderFocusRect,
+
+ SE_ProgressBarGroove,
+ SE_ProgressBarContents,
+ SE_ProgressBarLabel,
+
+ SE_ToolBoxTabContents,
+
+ SE_HeaderLabel,
+ SE_HeaderArrow,
+
+ SE_TabWidgetTabBar,
+ SE_TabWidgetTabPane,
+ SE_TabWidgetTabContents,
+ SE_TabWidgetLeftCorner,
+ SE_TabWidgetRightCorner,
+
+ SE_ItemViewItemCheckIndicator,
+ SE_TabBarTearIndicator,
+ SE_TabBarTearIndicatorLeft = SE_TabBarTearIndicator,
+
+ SE_TreeViewDisclosureItem,
+
+ SE_LineEditContents,
+ SE_FrameContents,
+
+ SE_DockWidgetCloseButton,
+ SE_DockWidgetFloatButton,
+ SE_DockWidgetTitleBarText,
+ SE_DockWidgetIcon,
+
+ SE_CheckBoxLayoutItem,
+ SE_ComboBoxLayoutItem,
+ SE_DateTimeEditLayoutItem,
+ SE_LabelLayoutItem,
+ SE_ProgressBarLayoutItem,
+ SE_PushButtonLayoutItem,
+ SE_RadioButtonLayoutItem,
+ SE_SliderLayoutItem,
+ SE_ScrollBarLayoutItem,
+ SE_SpinBoxLayoutItem,
+ SE_ToolButtonLayoutItem,
+
+ SE_FrameLayoutItem,
+ SE_GroupBoxLayoutItem,
+ SE_TabWidgetLayoutItem,
+
+ SE_ItemViewItemDecoration,
+ SE_ItemViewItemText,
+ SE_ItemViewItemFocusRect,
+
+ SE_TabBarTabLeftButton,
+ SE_TabBarTabRightButton,
+ SE_TabBarTabText,
+
+ SE_ShapedFrameContents,
+
+ SE_ToolBarHandle,
+
+ SE_TabBarScrollLeftButton,
+ SE_TabBarScrollRightButton,
+ SE_TabBarTearIndicatorRight,
+
+ // do not add any values below/greater than this
+ SE_CustomBase = 0xf0000000
+ };
+ Q_ENUM(SubElement)
+
+ enum ComplexControl {
+ CC_SpinBox,
+ CC_ComboBox,
+ CC_ScrollBar,
+ CC_Slider,
+ CC_ToolButton,
+ CC_TitleBar,
+ CC_Dial,
+ CC_GroupBox,
+ CC_MdiControls,
+
+ // do not add any values below/greater than this
+ CC_CustomBase = 0xf0000000
+ };
+ Q_ENUM(ComplexControl)
+
+ enum SubControl {
+ SC_None = 0x00000000,
+
+ SC_ScrollBarAddLine = 0x00000001,
+ SC_ScrollBarSubLine = 0x00000002,
+ SC_ScrollBarAddPage = 0x00000004,
+ SC_ScrollBarSubPage = 0x00000008,
+ SC_ScrollBarFirst = 0x00000010,
+ SC_ScrollBarLast = 0x00000020,
+ SC_ScrollBarSlider = 0x00000040,
+ SC_ScrollBarGroove = 0x00000080,
+
+ SC_SpinBoxUp = 0x00000001,
+ SC_SpinBoxDown = 0x00000002,
+ SC_SpinBoxFrame = 0x00000004,
+ SC_SpinBoxEditField = 0x00000008,
+
+ SC_ComboBoxFrame = 0x00000001,
+ SC_ComboBoxEditField = 0x00000002,
+ SC_ComboBoxArrow = 0x00000004,
+ SC_ComboBoxListBoxPopup = 0x00000008,
+
+ SC_SliderGroove = 0x00000001,
+ SC_SliderHandle = 0x00000002,
+ SC_SliderTickmarks = 0x00000004,
+
+ SC_ToolButton = 0x00000001,
+ SC_ToolButtonMenu = 0x00000002,
+
+ SC_TitleBarSysMenu = 0x00000001,
+ SC_TitleBarMinButton = 0x00000002,
+ SC_TitleBarMaxButton = 0x00000004,
+ SC_TitleBarCloseButton = 0x00000008,
+ SC_TitleBarNormalButton = 0x00000010,
+ SC_TitleBarShadeButton = 0x00000020,
+ SC_TitleBarUnshadeButton = 0x00000040,
+ SC_TitleBarContextHelpButton = 0x00000080,
+ SC_TitleBarLabel = 0x00000100,
+
+ SC_DialGroove = 0x00000001,
+ SC_DialHandle = 0x00000002,
+ SC_DialTickmarks = 0x00000004,
+
+ SC_GroupBoxCheckBox = 0x00000001,
+ SC_GroupBoxLabel = 0x00000002,
+ SC_GroupBoxContents = 0x00000004,
+ SC_GroupBoxFrame = 0x00000008,
+
+ SC_MdiMinButton = 0x00000001,
+ SC_MdiNormalButton = 0x00000002,
+ SC_MdiCloseButton = 0x00000004,
+
+ SC_CustomBase = 0xf0000000,
+ SC_All = 0xffffffff
+ };
+ Q_ENUM(SubControl)
+ Q_DECLARE_FLAGS(SubControls, SubControl)
+
+ enum PixelMetric {
+ PM_ButtonMargin,
+ PM_ButtonDefaultIndicator,
+ PM_MenuButtonIndicator,
+ PM_ButtonShiftHorizontal,
+ PM_ButtonShiftVertical,
+
+ PM_DefaultFrameWidth,
+ PM_SpinBoxFrameWidth,
+ PM_ComboBoxFrameWidth,
+
+ PM_MaximumDragDistance,
+
+ PM_ScrollBarExtent,
+ PM_ScrollBarSliderMin,
+
+ PM_SliderThickness, // total slider thickness
+ PM_SliderControlThickness, // thickness of the business part
+ PM_SliderLength, // total length of slider
+ PM_SliderTickmarkOffset, //
+ PM_SliderSpaceAvailable, // available space for slider to move
+
+ PM_DockWidgetSeparatorExtent,
+ PM_DockWidgetHandleExtent,
+ PM_DockWidgetFrameWidth,
+
+ PM_TabBarTabOverlap,
+ PM_TabBarTabHSpace,
+ PM_TabBarTabVSpace,
+ PM_TabBarBaseHeight,
+ PM_TabBarBaseOverlap,
+
+ PM_ProgressBarChunkWidth,
+
+ PM_SplitterWidth,
+ PM_TitleBarHeight,
+
+ PM_MenuScrollerHeight,
+ PM_MenuHMargin,
+ PM_MenuVMargin,
+ PM_MenuPanelWidth,
+ PM_MenuTearoffHeight,
+ PM_MenuDesktopFrameWidth,
+
+ PM_MenuBarPanelWidth,
+ PM_MenuBarItemSpacing,
+ PM_MenuBarVMargin,
+ PM_MenuBarHMargin,
+
+ PM_IndicatorWidth,
+ PM_IndicatorHeight,
+ PM_ExclusiveIndicatorWidth,
+ PM_ExclusiveIndicatorHeight,
+
+ PM_DialogButtonsSeparator,
+ PM_DialogButtonsButtonWidth,
+ PM_DialogButtonsButtonHeight,
+
+ PM_MdiSubWindowFrameWidth,
+ PM_MdiSubWindowMinimizedWidth,
+
+ PM_HeaderMargin,
+ PM_HeaderMarkSize,
+ PM_HeaderGripMargin,
+ PM_TabBarTabShiftHorizontal,
+ PM_TabBarTabShiftVertical,
+ PM_TabBarScrollButtonWidth,
+
+ PM_ToolBarFrameWidth,
+ PM_ToolBarHandleExtent,
+ PM_ToolBarItemSpacing,
+ PM_ToolBarItemMargin,
+ PM_ToolBarSeparatorExtent,
+ PM_ToolBarExtensionExtent,
+
+ PM_SpinBoxSliderHeight,
+
+ PM_DefaultTopLevelMargin,
+ PM_DefaultChildMargin,
+ PM_DefaultLayoutSpacing,
+
+ PM_ToolBarIconSize,
+ PM_ListViewIconSize,
+ PM_IconViewIconSize,
+ PM_SmallIconSize,
+ PM_LargeIconSize,
+
+ PM_FocusFrameVMargin,
+ PM_FocusFrameHMargin,
+
+ PM_ToolTipLabelFrameWidth,
+ PM_CheckBoxLabelSpacing,
+ PM_TabBarIconSize,
+ PM_SizeGripSize,
+ PM_DockWidgetTitleMargin,
+ PM_MessageBoxIconSize,
+ PM_ButtonIconSize,
+
+ PM_DockWidgetTitleBarButtonMargin,
+
+ PM_RadioButtonLabelSpacing,
+ PM_LayoutLeftMargin,
+ PM_LayoutTopMargin,
+ PM_LayoutRightMargin,
+ PM_LayoutBottomMargin,
+ PM_LayoutHorizontalSpacing,
+ PM_LayoutVerticalSpacing,
+ PM_TabBar_ScrollButtonOverlap,
+
+ PM_TextCursorWidth,
+
+ PM_TabCloseIndicatorWidth,
+ PM_TabCloseIndicatorHeight,
+
+ PM_ScrollView_ScrollBarSpacing,
+ PM_ScrollView_ScrollBarOverlap,
+ PM_SubMenuOverlap,
+ PM_TreeViewIndentation,
+
+ PM_HeaderDefaultSectionSizeHorizontal,
+ PM_HeaderDefaultSectionSizeVertical,
+
+ PM_TitleBarButtonIconSize,
+ PM_TitleBarButtonSize,
+
+ PM_PushButtonFocusFrameRadius,
+ PM_CheckBoxFocusFrameRadius,
+ PM_ComboBoxFocusFrameRadius,
+ PM_DialFocusFrameRadius,
+ PM_RadioButtonFocusFrameRadius,
+ PM_SliderFocusFrameRadius,
+ PM_SpinBoxFocusFrameRadius,
+ PM_TextAreaFocusFrameRadius,
+ PM_TextFieldFocusFrameRadius,
+
+ // do not add any values below/greater than this
+ PM_CustomBase = 0xf0000000
+ };
+ Q_ENUM(PixelMetric)
+
+ enum ContentsType {
+ CT_PushButton,
+ CT_CheckBox,
+ CT_RadioButton,
+ CT_ToolButton,
+ CT_ComboBox,
+ CT_Splitter,
+ CT_ProgressBar,
+ CT_MenuItem,
+ CT_MenuBarItem,
+ CT_MenuBar,
+ CT_Menu,
+ CT_TabBarTab,
+ CT_Slider,
+ CT_Dial,
+ CT_ScrollBar,
+ CT_LineEdit,
+ CT_SpinBox,
+ CT_SizeGrip,
+ CT_TabWidget,
+ CT_DialogButtons,
+ CT_HeaderSection,
+ CT_GroupBox,
+ CT_MdiControls,
+ CT_ItemViewItem,
+ CT_Frame,
+ // do not add any values below/greater than this
+ CT_CustomBase = 0xf0000000
+ };
+ Q_ENUM(ContentsType)
+
+ enum RequestSoftwareInputPanel {
+ RSIP_OnMouseClickAndAlreadyFocused,
+ RSIP_OnMouseClick
+ };
+ Q_ENUM(RequestSoftwareInputPanel)
+
+ enum StyleHint {
+ SH_EtchDisabledText,
+ SH_DitherDisabledText,
+ SH_ScrollBar_MiddleClickAbsolutePosition,
+ SH_ScrollBar_ScrollWhenPointerLeavesControl,
+ SH_TabBar_SelectMouseType,
+ SH_TabBar_Alignment,
+ SH_Header_ArrowAlignment,
+ SH_Slider_SnapToValue,
+ SH_Slider_SloppyKeyEvents,
+ SH_ProgressDialog_CenterCancelButton,
+ SH_ProgressDialog_TextLabelAlignment,
+ SH_PrintDialog_RightAlignButtons,
+ SH_MainWindow_SpaceBelowMenuBar,
+ SH_FontDialog_SelectAssociatedText,
+ SH_Menu_AllowActiveAndDisabled,
+ SH_Menu_SpaceActivatesItem,
+ SH_Menu_SubMenuPopupDelay,
+ SH_ScrollView_FrameOnlyAroundContents,
+ SH_MenuBar_AltKeyNavigation,
+ SH_ComboBox_ListMouseTracking,
+ SH_Menu_MouseTracking,
+ SH_MenuBar_MouseTracking,
+ SH_ItemView_ChangeHighlightOnFocus,
+ SH_Widget_ShareActivation,
+ SH_Workspace_FillSpaceOnMaximize,
+ SH_ComboBox_Popup,
+ SH_TitleBar_NoBorder,
+ SH_Slider_StopMouseOverSlider,
+ SH_BlinkCursorWhenTextSelected,
+ SH_RichText_FullWidthSelection,
+ SH_Menu_Scrollable,
+ SH_GroupBox_TextLabelVerticalAlignment,
+ SH_GroupBox_TextLabelColor,
+ SH_Menu_SloppySubMenus,
+ SH_Table_GridLineColor,
+ SH_LineEdit_PasswordCharacter,
+ SH_DialogButtons_DefaultButton,
+ SH_ToolBox_SelectedPageTitleBold,
+ SH_TabBar_PreferNoArrows,
+ SH_ScrollBar_LeftClickAbsolutePosition,
+ SH_ListViewExpand_SelectMouseType,
+ SH_UnderlineShortcut,
+ SH_SpinBox_AnimateButton,
+ SH_SpinBox_KeyPressAutoRepeatRate,
+ SH_SpinBox_ClickAutoRepeatRate,
+ SH_Menu_FillScreenWithScroll,
+ SH_ToolTipLabel_Opacity,
+ SH_DrawMenuBarSeparator,
+ SH_TitleBar_ModifyNotification,
+ SH_Button_FocusPolicy,
+ SH_MessageBox_UseBorderForButtonSpacing,
+ SH_TitleBar_AutoRaise,
+ SH_ToolButton_PopupDelay,
+ SH_FocusFrame_Mask,
+ SH_RubberBand_Mask,
+ SH_WindowFrame_Mask,
+ SH_SpinControls_DisableOnBounds,
+ SH_Dial_BackgroundRole,
+ SH_ComboBox_LayoutDirection,
+ SH_ItemView_EllipsisLocation,
+ SH_ItemView_ShowDecorationSelected,
+ SH_ItemView_ActivateItemOnSingleClick,
+ SH_ScrollBar_ContextMenu,
+ SH_ScrollBar_RollBetweenButtons,
+ SH_Slider_AbsoluteSetButtons,
+ SH_Slider_PageSetButtons,
+ SH_Menu_KeyboardSearch,
+ SH_TabBar_ElideMode,
+ SH_DialogButtonLayout,
+ SH_ComboBox_PopupFrameStyle,
+ SH_MessageBox_TextInteractionFlags,
+ SH_DialogButtonBox_ButtonsHaveIcons,
+ SH_SpellCheckUnderlineStyle,
+ SH_MessageBox_CenterButtons,
+ SH_Menu_SelectionWrap,
+ SH_ItemView_MovementWithoutUpdatingSelection,
+ SH_ToolTip_Mask,
+ SH_FocusFrame_AboveWidget,
+ SH_TextControl_FocusIndicatorTextCharFormat,
+ SH_WizardStyle,
+ SH_ItemView_ArrowKeysNavigateIntoChildren,
+ SH_Menu_Mask,
+ SH_Menu_FlashTriggeredItem,
+ SH_Menu_FadeOutOnHide,
+ SH_SpinBox_ClickAutoRepeatThreshold,
+ SH_ItemView_PaintAlternatingRowColorsForEmptyArea,
+ SH_FormLayoutWrapPolicy,
+ SH_TabWidget_DefaultTabPosition,
+ SH_ToolBar_Movable,
+ SH_FormLayoutFieldGrowthPolicy,
+ SH_FormLayoutFormAlignment,
+ SH_FormLayoutLabelAlignment,
+ SH_ItemView_DrawDelegateFrame,
+ SH_TabBar_CloseButtonPosition,
+ SH_DockWidget_ButtonsHaveFrame,
+ SH_ToolButtonStyle,
+ SH_RequestSoftwareInputPanel,
+ SH_ScrollBar_Transient,
+ SH_Menu_SupportsSections,
+ SH_ToolTip_WakeUpDelay,
+ SH_ToolTip_FallAsleepDelay,
+ SH_Widget_Animate,
+ SH_Splitter_OpaqueResize,
+ // Whether we should use a native popup.
+ // Only supported for non-editable combo boxes on Mac OS X so far.
+ SH_ComboBox_UseNativePopup,
+ SH_LineEdit_PasswordMaskDelay,
+ SH_TabBar_ChangeCurrentDelay,
+ SH_Menu_SubMenuUniDirection,
+ SH_Menu_SubMenuUniDirectionFailCount,
+ SH_Menu_SubMenuSloppySelectOtherActions,
+ SH_Menu_SubMenuSloppyCloseTimeout,
+ SH_Menu_SubMenuResetWhenReenteringParent,
+ SH_Menu_SubMenuDontStartSloppyOnLeave,
+ SH_ItemView_ScrollMode,
+ SH_TitleBar_ShowToolTipsOnButtons,
+ SH_Widget_Animation_Duration,
+ SH_ComboBox_AllowWheelScrolling,
+ SH_SpinBox_ButtonsInsideFrame,
+ SH_SpinBox_StepModifier,
+ // Add new style hint values here
+
+ SH_CustomBase = 0xf0000000
+ };
+ Q_ENUM(StyleHint)
+
+ enum StandardPixmap {
+ SP_TitleBarMenuButton,
+ SP_TitleBarMinButton,
+ SP_TitleBarMaxButton,
+ SP_TitleBarCloseButton,
+ SP_TitleBarNormalButton,
+ SP_TitleBarShadeButton,
+ SP_TitleBarUnshadeButton,
+ SP_TitleBarContextHelpButton,
+ SP_DockWidgetCloseButton,
+ SP_MessageBoxInformation,
+ SP_MessageBoxWarning,
+ SP_MessageBoxCritical,
+ SP_MessageBoxQuestion,
+ SP_DesktopIcon,
+ SP_TrashIcon,
+ SP_ComputerIcon,
+ SP_DriveFDIcon,
+ SP_DriveHDIcon,
+ SP_DriveCDIcon,
+ SP_DriveDVDIcon,
+ SP_DriveNetIcon,
+ SP_DirOpenIcon,
+ SP_DirClosedIcon,
+ SP_DirLinkIcon,
+ SP_DirLinkOpenIcon,
+ SP_FileIcon,
+ SP_FileLinkIcon,
+ SP_ToolBarHorizontalExtensionButton,
+ SP_ToolBarVerticalExtensionButton,
+ SP_FileDialogStart,
+ SP_FileDialogEnd,
+ SP_FileDialogToParent,
+ SP_FileDialogNewFolder,
+ SP_FileDialogDetailedView,
+ SP_FileDialogInfoView,
+ SP_FileDialogContentsView,
+ SP_FileDialogListView,
+ SP_FileDialogBack,
+ SP_DirIcon,
+ SP_DialogOkButton,
+ SP_DialogCancelButton,
+ SP_DialogHelpButton,
+ SP_DialogOpenButton,
+ SP_DialogSaveButton,
+ SP_DialogCloseButton,
+ SP_DialogApplyButton,
+ SP_DialogResetButton,
+ SP_DialogDiscardButton,
+ SP_DialogYesButton,
+ SP_DialogNoButton,
+ SP_ArrowUp,
+ SP_ArrowDown,
+ SP_ArrowLeft,
+ SP_ArrowRight,
+ SP_ArrowBack,
+ SP_ArrowForward,
+ SP_DirHomeIcon,
+ SP_CommandLink,
+ SP_VistaShield,
+ SP_BrowserReload,
+ SP_BrowserStop,
+ SP_MediaPlay,
+ SP_MediaStop,
+ SP_MediaPause,
+ SP_MediaSkipForward,
+ SP_MediaSkipBackward,
+ SP_MediaSeekForward,
+ SP_MediaSeekBackward,
+ SP_MediaVolume,
+ SP_MediaVolumeMuted,
+ SP_LineEditClearButton,
+ SP_DialogYesToAllButton,
+ SP_DialogNoToAllButton,
+ SP_DialogSaveAllButton,
+ SP_DialogAbortButton,
+ SP_DialogRetryButton,
+ SP_DialogIgnoreButton,
+ SP_RestoreDefaultsButton,
+ // do not add any values below/greater than this
+ SP_CustomBase = 0xf0000000
+ };
+ Q_ENUM(StandardPixmap)
+
+ virtual QRect itemTextRect(const QFontMetrics &fm, const QRect &r, int flags, bool enabled, const QString &text) const;
+ virtual QRect itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const;
+ virtual QRect subElementRect(SubElement subElement, const QStyleOption *option) const = 0;
+ virtual QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc) const = 0;
+
+ virtual QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const = 0;
+ virtual QFont font(ControlElement element, const QStyle::State state) const = 0;
+ virtual QMargins ninePatchMargins(ControlElement ce, const QStyleOption *opt, const QSize &imageSize) const = 0;
+ virtual QMargins ninePatchMargins(ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const = 0;
+
+ virtual SubControl hitTestComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt) const = 0;
+
+ virtual int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr) const = 0;
+ virtual int styleHint(StyleHint stylehint, const QStyleOption *opt = nullptr, QStyleHintReturn* returnData = nullptr) const = 0;
+
+ virtual void drawItemText(QPainter *painter, const QRect &rect,
+ int flags, const QPalette &pal, bool enabled,
+ const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const;
+ virtual void drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const;
+ virtual void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const = 0;
+ virtual void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p) const = 0;
+ virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const = 0;
+
+ virtual QPalette standardPalette() const;
+ virtual QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt = nullptr) const = 0;
+ virtual QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr) const = 0;
+ virtual QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const = 0;
+
+ static QRect visualRect(Qt::LayoutDirection direction, const QRect &boundingRect, const QRect &logicalRect);
+ static QPoint visualPos(Qt::LayoutDirection direction, const QRect &boundingRect, const QPoint &logicalPos);
+ static int sliderPositionFromValue(int min, int max, int val, int space, bool upsideDown = false);
+ static int sliderValueFromPosition(int min, int max, int pos, int space, bool upsideDown = false);
+ static Qt::Alignment visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment);
+ static QRect alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle);
+
+ // TODO: Remove the concept of proxy (but keep it for now until everything builds)
+ const QStyle *proxy() const { return this; }
+
+private:
+ Q_DISABLE_COPY(QStyle)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyle::State)
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyle::SubControls)
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QSTYLE_H
diff --git a/src/quicknativestyle/qstyle/qquickstyle_p.h b/src/quicknativestyle/qstyle/qquickstyle_p.h
new file mode 100644
index 0000000000..46f5374099
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstyle_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTYLE_P_H
+#define QSTYLE_P_H
+
+#include "qquickstyle.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtGui/qguiapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qstyle_*.cpp. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+// Private class
+
+namespace QQC2 {
+
+class QStylePrivate: public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QStyle)
+
+public:
+ static bool useFullScreenForPopup();
+ mutable int layoutSpacingIndex = -1;
+ QStyle *proxyStyle;
+};
+
+inline QImage styleCacheImage(const QSize &size)
+{
+ const qreal pixelRatio = qApp->devicePixelRatio();
+ QImage cacheImage = QImage(size * pixelRatio, QImage::Format_ARGB32_Premultiplied);
+ cacheImage.setDevicePixelRatio(pixelRatio);
+ return cacheImage;
+}
+
+inline QPixmap styleCachePixmap(const QSize &size)
+{
+ const qreal pixelRatio = qApp->devicePixelRatio();
+ QPixmap cachePixmap = QPixmap(size * pixelRatio);
+ cachePixmap.setDevicePixelRatio(pixelRatio);
+ return cachePixmap;
+}
+
+#define BEGIN_STYLE_PIXMAPCACHE(a) \
+ QRect rect = option->rect; \
+ QPixmap internalPixmapCache; \
+ QImage imageCache; \
+ QPainter *p = painter; \
+ QString unique = QStyleHelper::uniqueName((a), option, option->rect.size()); \
+ int txType = painter->deviceTransform().type() | painter->worldTransform().type(); \
+ bool doPixmapCache = (!option->rect.isEmpty()) \
+ && ((txType <= QTransform::TxTranslate) || (painter->deviceTransform().type() == QTransform::TxScale)); \
+ if (doPixmapCache && QPixmapCache::find(unique, &internalPixmapCache)) { \
+ painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
+ } else { \
+ if (doPixmapCache) { \
+ rect.setRect(0, 0, option->rect.width(), option->rect.height()); \
+ imageCache = styleCacheImage(option->rect.size()); \
+ imageCache.fill(0); \
+ p = new QPainter(&imageCache); \
+ }
+
+#define END_STYLE_PIXMAPCACHE \
+ if (doPixmapCache) { \
+ p->end(); \
+ delete p; \
+ internalPixmapCache = QPixmap::fromImage(imageCache); \
+ painter->drawPixmap(option->rect.topLeft(), internalPixmapCache); \
+ QPixmapCache::insert(unique, internalPixmapCache); \
+ } \
+ }
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif //QSTYLE_P_H
diff --git a/src/quicknativestyle/qstyle/qquickstylehelper.cpp b/src/quicknativestyle/qstyle/qquickstylehelper.cpp
new file mode 100644
index 0000000000..fdc60b6468
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstylehelper.cpp
@@ -0,0 +1,439 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstylehelper_p.h"
+#include "qquickstyleoption.h"
+#include "qquickstyle_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qwindow.h>
+#include <QtGui/private/qhighdpiscaling_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qmath_p.h>
+#include <QtGui/private/qhexstring_p.h>
+
+#include <qmetaobject.h>
+#include <qstringbuilder.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_GUI_EXPORT int qt_defaultDpiX();
+
+namespace QQC2 {
+
+namespace QStyleHelper {
+
+QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size)
+{
+ const QStyleOptionComplex *complexOption = qstyleoption_cast<const QStyleOptionComplex *>(option);
+ QString tmp = key % HexString<uint>(option->state)
+ % HexString<uint>(option->direction)
+ % HexString<uint>(complexOption ? uint(complexOption->activeSubControls) : 0u)
+ % HexString<quint64>(option->palette.cacheKey())
+ % HexString<uint>(size.width())
+ % HexString<uint>(size.height());
+
+ if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) {
+ tmp = tmp % HexString<uint>(spinBox->buttonSymbols)
+ % HexString<uint>(spinBox->stepEnabled)
+ % QLatin1Char(spinBox->frame ? '1' : '0'); ;
+ }
+
+ return tmp;
+}
+
+#ifdef Q_OS_DARWIN
+static const qreal qstyleBaseDpi = 72;
+#else
+static const qreal qstyleBaseDpi = 96;
+#endif
+
+qreal dpi(const QStyleOption *option)
+{
+#ifndef Q_OS_DARWIN
+ // Prioritize the application override, except for on macOS where
+ // we have historically not supported the AA_Use96Dpi flag.
+ if (QCoreApplication::testAttribute(Qt::AA_Use96Dpi))
+ return 96;
+#endif
+
+ // Expect that QStyleOption::QFontMetrics::QFont has the correct DPI set
+ if (option)
+ return option->fontMetrics.fontDpi();
+
+ return qstyleBaseDpi;
+}
+
+qreal dpiScaled(qreal value, qreal dpi)
+{
+ return value * dpi / qstyleBaseDpi;
+}
+
+qreal dpiScaled(qreal value, const QPaintDevice *device)
+{
+ return dpiScaled(value, device->logicalDpiX());
+}
+
+qreal dpiScaled(qreal value, const QStyleOption *option)
+{
+ return dpiScaled(value, dpi(option));
+}
+
+#if QT_CONFIG(accessibility)
+bool isInstanceOf(QObject *obj, QAccessible::Role role)
+{
+ bool match = false;
+ QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(obj);
+ match = iface && iface->role() == role;
+ return match;
+}
+
+// Searches for an ancestor of a particular accessible role
+bool hasAncestor(QObject *obj, QAccessible::Role role)
+{
+ bool found = false;
+ QObject *parent = obj ? obj->parent() : nullptr;
+ while (parent && !found) {
+ if (isInstanceOf(parent, role))
+ found = true;
+ parent = parent->parent();
+ }
+ return found;
+}
+#endif
+
+int calcBigLineSize(int radius)
+{
+ int bigLineSize = radius / 6;
+ if (bigLineSize < 4)
+ bigLineSize = 4;
+ if (bigLineSize > radius / 2)
+ bigLineSize = radius / 2;
+ return bigLineSize;
+}
+
+static QPointF calcRadialPos(const QStyleOptionSlider *dial, qreal offset)
+{
+ const int width = dial->rect.width();
+ const int height = dial->rect.height();
+ const int r = qMin(width, height) / 2;
+ const int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition);
+ qreal a = 0;
+ if (dial->maximum == dial->minimum)
+ a = Q_PI / 2;
+ else if (dial->dialWrapping)
+ a = Q_PI * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Q_PI
+ / (dial->maximum - dial->minimum);
+ else
+ a = (Q_PI * 8 - (currentSliderPosition - dial->minimum) * 10 * Q_PI
+ / (dial->maximum - dial->minimum)) / 6;
+ qreal xc = width / 2.0;
+ qreal yc = height / 2.0;
+ qreal len = r - QStyleHelper::calcBigLineSize(r) - 3;
+ qreal back = offset * len;
+ QPointF pos(QPointF(xc + back * qCos(a), yc - back * qSin(a)));
+ return pos;
+}
+
+qreal angle(const QPointF &p1, const QPointF &p2)
+{
+ static const qreal rad_factor = 180 / Q_PI;
+ qreal _angle = 0;
+
+ if (p1.x() == p2.x()) {
+ if (p1.y() < p2.y())
+ _angle = 270;
+ else
+ _angle = 90;
+ } else {
+ qreal x1, x2, y1, y2;
+
+ if (p1.x() <= p2.x()) {
+ x1 = p1.x(); y1 = p1.y();
+ x2 = p2.x(); y2 = p2.y();
+ } else {
+ x2 = p1.x(); y2 = p1.y();
+ x1 = p2.x(); y1 = p2.y();
+ }
+
+ qreal m = -(y2 - y1) / (x2 - x1);
+ _angle = qAtan(m) * rad_factor;
+
+ if (p1.x() < p2.x())
+ _angle = 180 - _angle;
+ else
+ _angle = -_angle;
+ }
+ return _angle;
+}
+
+QPolygonF calcLines(const QStyleOptionSlider *dial)
+{
+ QPolygonF poly;
+ int width = dial->rect.width();
+ int height = dial->rect.height();
+ qreal r = qMin(width, height) / 2;
+ int bigLineSize = calcBigLineSize(int(r));
+
+ qreal xc = width / 2 + 0.5;
+ qreal yc = height / 2 + 0.5;
+ const int ns = dial->tickInterval;
+ if (!ns) // Invalid values may be set by Qt Designer.
+ return poly;
+ int notches = (dial->maximum + ns - 1 - dial->minimum) / ns;
+ if (notches <= 0)
+ return poly;
+ if (dial->maximum < dial->minimum || dial->maximum - dial->minimum > 1000) {
+ int maximum = dial->minimum + 1000;
+ notches = (maximum + ns - 1 - dial->minimum) / ns;
+ }
+
+ poly.resize(2 + 2 * notches);
+ int smallLineSize = bigLineSize / 2;
+ for (int i = 0; i <= notches; ++i) {
+ qreal angle = dial->dialWrapping ? Q_PI * 3 / 2 - i * 2 * Q_PI / notches
+ : (Q_PI * 8 - i * 10 * Q_PI / notches) / 6;
+ qreal s = qSin(angle);
+ qreal c = qCos(angle);
+ if (i == 0 || (((ns * i) % (dial->pageStep ? dial->pageStep : 1)) == 0)) {
+ poly[2 * i] = QPointF(xc + (r - bigLineSize) * c,
+ yc - (r - bigLineSize) * s);
+ poly[2 * i + 1] = QPointF(xc + r * c, yc - r * s);
+ } else {
+ poly[2 * i] = QPointF(xc + (r - 1 - smallLineSize) * c,
+ yc - (r - 1 - smallLineSize) * s);
+ poly[2 * i + 1] = QPointF(xc + (r - 1) * c, yc -(r - 1) * s);
+ }
+ }
+ return poly;
+}
+
+// This will draw a nice and shiny QDial for us. We don't want
+// all the shinyness in QWindowsStyle, hence we place it here
+
+void drawDial(const QStyleOptionSlider *option, QPainter *painter)
+{
+ QPalette pal = option->palette;
+ QColor buttonColor = pal.button().color();
+ const int width = option->rect.width();
+ const int height = option->rect.height();
+ const bool enabled = option->state & QStyle::State_Enabled;
+ qreal r = qMin(width, height) / 2;
+ r -= r/50;
+ const qreal penSize = r/20.0;
+
+ painter->save();
+ painter->setRenderHint(QPainter::Antialiasing);
+
+ // Draw notches
+ if (option->subControls & QStyle::SC_DialTickmarks) {
+ painter->setPen(option->palette.dark().color().darker(120));
+ painter->drawLines(QStyleHelper::calcLines(option));
+ }
+
+ // setting color before BEGIN_STYLE_PIXMAPCACHE since
+ // otherwise it is not set when the image is in the cache
+ buttonColor.setHsv(buttonColor .hue(),
+ qMin(140, buttonColor .saturation()),
+ qMax(180, buttonColor.value()));
+
+ // Cache dial background
+ BEGIN_STYLE_PIXMAPCACHE(QString::fromLatin1("qdial"))
+ p->setRenderHint(QPainter::Antialiasing);
+
+ const qreal d_ = r / 6;
+ const qreal dx = option->rect.x() + d_ + (width - 2 * r) / 2 + 1;
+ const qreal dy = option->rect.y() + d_ + (height - 2 * r) / 2 + 1;
+
+ QRectF br = QRectF(dx + 0.5, dy + 0.5,
+ int(r * 2 - 2 * d_ - 2),
+ int(r * 2 - 2 * d_ - 2));
+
+ if (enabled) {
+ // Drop shadow
+ qreal shadowSize = qMax(1.0, penSize/2.0);
+ QRectF shadowRect= br.adjusted(-2*shadowSize, -2*shadowSize,
+ 2*shadowSize, 2*shadowSize);
+ QRadialGradient shadowGradient(shadowRect.center().x(),
+ shadowRect.center().y(), shadowRect.width()/2.0,
+ shadowRect.center().x(), shadowRect.center().y());
+ shadowGradient.setColorAt(qreal(0.91), QColor(0, 0, 0, 40));
+ shadowGradient.setColorAt(qreal(1.0), Qt::transparent);
+ p->setBrush(shadowGradient);
+ p->setPen(Qt::NoPen);
+ p->translate(shadowSize, shadowSize);
+ p->drawEllipse(shadowRect);
+ p->translate(-shadowSize, -shadowSize);
+
+ // Main gradient
+ QRadialGradient gradient(br.center().x() - br.width()/3, dy,
+ br.width()*1.3, br.center().x(),
+ br.center().y() - br.height()/2);
+ gradient.setColorAt(0, buttonColor.lighter(110));
+ gradient.setColorAt(qreal(0.5), buttonColor);
+ gradient.setColorAt(qreal(0.501), buttonColor.darker(102));
+ gradient.setColorAt(1, buttonColor.darker(115));
+ p->setBrush(gradient);
+ } else {
+ p->setBrush(Qt::NoBrush);
+ }
+
+ p->setPen(QPen(buttonColor.darker(280)));
+ p->drawEllipse(br);
+ p->setBrush(Qt::NoBrush);
+ p->setPen(buttonColor.lighter(110));
+ p->drawEllipse(br.adjusted(1, 1, -1, -1));
+
+ if (option->state & QStyle::State_HasFocus) {
+ QColor highlight = pal.highlight().color();
+ highlight.setHsv(highlight.hue(),
+ qMin(160, highlight.saturation()),
+ qMax(230, highlight.value()));
+ highlight.setAlpha(127);
+ p->setPen(QPen(highlight, 2.0));
+ p->setBrush(Qt::NoBrush);
+ p->drawEllipse(br.adjusted(-1, -1, 1, 1));
+ }
+
+ END_STYLE_PIXMAPCACHE
+
+ QPointF dp = calcRadialPos(option, qreal(0.70));
+ buttonColor = buttonColor.lighter(104);
+ buttonColor.setAlphaF(0.8f);
+ const qreal ds = r/qreal(7.0);
+ QRectF dialRect(dp.x() - ds, dp.y() - ds, 2*ds, 2*ds);
+ QRadialGradient dialGradient(dialRect.center().x() + dialRect.width()/2,
+ dialRect.center().y() + dialRect.width(),
+ dialRect.width()*2,
+ dialRect.center().x(), dialRect.center().y());
+ dialGradient.setColorAt(1, buttonColor.darker(140));
+ dialGradient.setColorAt(qreal(0.4), buttonColor.darker(120));
+ dialGradient.setColorAt(0, buttonColor.darker(110));
+ if (penSize > 3.0) {
+ painter->setPen(QPen(QColor(0, 0, 0, 25), penSize));
+ painter->drawLine(calcRadialPos(option, qreal(0.90)), calcRadialPos(option, qreal(0.96)));
+ }
+
+ painter->setBrush(dialGradient);
+ painter->setPen(QColor(255, 255, 255, 150));
+ painter->drawEllipse(dialRect.adjusted(-1, -1, 1, 1));
+ painter->setPen(QColor(0, 0, 0, 80));
+ painter->drawEllipse(dialRect);
+ painter->restore();
+}
+
+void drawBorderPixmap(const QPixmap &pixmap, QPainter *painter, const QRect &rect,
+ int left, int top, int right,
+ int bottom)
+{
+ QSize size = pixmap.size();
+ //painter->setRenderHint(QPainter::SmoothPixmapTransform);
+
+ //top
+ if (top > 0) {
+ painter->drawPixmap(QRect(rect.left() + left, rect.top(), rect.width() -right - left, top), pixmap,
+ QRect(left, 0, size.width() -right - left, top));
+
+ //top-left
+ if(left > 0)
+ painter->drawPixmap(QRect(rect.left(), rect.top(), left, top), pixmap,
+ QRect(0, 0, left, top));
+
+ //top-right
+ if (right > 0)
+ painter->drawPixmap(QRect(rect.left() + rect.width() - right, rect.top(), right, top), pixmap,
+ QRect(size.width() - right, 0, right, top));
+ }
+
+ //left
+ if (left > 0)
+ painter->drawPixmap(QRect(rect.left(), rect.top()+top, left, rect.height() - top - bottom), pixmap,
+ QRect(0, top, left, size.height() - bottom - top));
+
+ //center
+ painter->drawPixmap(QRect(rect.left() + left, rect.top()+top, rect.width() -right - left,
+ rect.height() - bottom - top), pixmap,
+ QRect(left, top, size.width() -right -left,
+ size.height() - bottom - top));
+ //right
+ if (right > 0)
+ painter->drawPixmap(QRect(rect.left() +rect.width() - right, rect.top()+top, right, rect.height() - top - bottom), pixmap,
+ QRect(size.width() - right, top, right, size.height() - bottom - top));
+
+ //bottom
+ if (bottom > 0) {
+ painter->drawPixmap(QRect(rect.left() +left, rect.top() + rect.height() - bottom,
+ rect.width() - right - left, bottom), pixmap,
+ QRect(left, size.height() - bottom,
+ size.width() - right - left, bottom));
+ //bottom-left
+ if (left > 0)
+ painter->drawPixmap(QRect(rect.left(), rect.top() + rect.height() - bottom, left, bottom), pixmap,
+ QRect(0, size.height() - bottom, left, bottom));
+
+ //bottom-right
+ if (right > 0)
+ painter->drawPixmap(QRect(rect.left() + rect.width() - right, rect.top() + rect.height() - bottom, right, bottom), pixmap,
+ QRect(size.width() - right, size.height() - bottom, right, bottom));
+
+ }
+}
+
+WidgetSizePolicy widgetSizePolicy(const QStyleOption *opt)
+{
+ if (opt && opt->state & QStyle::State_Mini)
+ return SizeMini;
+ else if (opt && opt->state & QStyle::State_Small)
+ return SizeSmall;
+
+ return SizeDefault;
+}
+
+QColor backgroundColor(const QPalette &pal)
+{
+// if (qobject_cast<const QScrollBar *>(widget) && widget->parent() &&
+// qobject_cast<const QAbstractScrollArea *>(widget->parent()->parent()))
+// return widget->parentWidget()->parentWidget()->palette().color(QPalette::Base);
+ return pal.color(QPalette::Base);
+}
+
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/qquickstylehelper_p.h b/src/quicknativestyle/qstyle/qquickstylehelper_p.h
new file mode 100644
index 0000000000..d2a9636be9
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstylehelper_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qpoint.h>
+#include <QtCore/qstring.h>
+#include <QtGui/qpaintdevice.h>
+#include <QtGui/qpolygon.h>
+#include <QtCore/qstringbuilder.h>
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+#ifndef QSTYLEHELPER_P_H
+#define QSTYLEHELPER_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.
+//
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QPainter;
+class QPixmap;
+
+namespace QQC2 {
+
+class QStyleOptionSlider;
+class QStyleOption;
+
+namespace QStyleHelper
+{
+ QString uniqueName(const QString &key, const QStyleOption *option, const QSize &size);
+
+ qreal dpi(const QStyleOption *option);
+ qreal dpiScaled(qreal value, qreal dpi);
+ qreal dpiScaled(qreal value, const QPaintDevice *device);
+ qreal dpiScaled(qreal value, const QStyleOption *option);
+
+ qreal angle(const QPointF &p1, const QPointF &p2);
+ QPolygonF calcLines(const QStyleOptionSlider *dial);
+ int calcBigLineSize(int radius);
+ void drawDial(const QStyleOptionSlider *dial, QPainter *painter);
+
+ void drawBorderPixmap(const QPixmap &pixmap, QPainter *painter, const QRect &rect,
+ int left = 0, int top = 0, int right = 0,
+ int bottom = 0);
+
+#if QT_CONFIG(accessibility)
+ bool isInstanceOf(QObject *obj, QAccessible::Role role);
+ bool hasAncestor(QObject *obj, QAccessible::Role role);
+#endif
+ QColor backgroundColor(const QPalette &pal);
+
+ enum WidgetSizePolicy { SizeLarge = 0, SizeSmall = 1, SizeMini = 2, SizeDefault = -1 };
+ WidgetSizePolicy widgetSizePolicy(const QStyleOption *opt);
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QSTYLEHELPER_P_H
diff --git a/src/quicknativestyle/qstyle/qquickstyleoption.cpp b/src/quicknativestyle/qstyle/qquickstyleoption.cpp
new file mode 100644
index 0000000000..c34dddd7e1
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstyleoption.cpp
@@ -0,0 +1,652 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstyleoption.h"
+
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+QStyleOption::QStyleOption(int version, int type)
+ : version(version), type(type), state(QStyle::State_None),
+ direction(QGuiApplication::layoutDirection()), fontMetrics(QFont()),
+ styleObject(nullptr), control(nullptr), window(nullptr)
+{
+}
+
+/*!
+ Destroys this style option object.
+*/
+QStyleOption::~QStyleOption()
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+QStyleOption::QStyleOption(const QStyleOption &other)
+ : version(Version), type(Type), state(other.state),
+ direction(other.direction), rect(other.rect), fontMetrics(other.fontMetrics),
+ palette(other.palette), styleObject(other.styleObject),
+ control(other.control), window(other.window)
+{
+}
+
+/*!
+ Assign \a other to this QStyleOption.
+*/
+QStyleOption &QStyleOption::operator=(const QStyleOption &other)
+{
+ control = other.control;
+ window = other.window;
+ state = other.state;
+ direction = other.direction;
+ rect = other.rect;
+ fontMetrics = other.fontMetrics;
+ palette = other.palette;
+ styleObject = other.styleObject;
+ return *this;
+}
+
+/*!
+ Constructs a QStyleOptionFocusRect, initializing the members
+ variables to their default values.
+*/
+QStyleOptionFocusRect::QStyleOptionFocusRect()
+ : QStyleOption(Version, SO_FocusRect)
+{
+ state |= QStyle::State_KeyboardFocusChange; // assume we had one, will be corrected in initFrom()
+}
+
+/*!
+ \internal
+*/
+QStyleOptionFocusRect::QStyleOptionFocusRect(int versionIn)
+ : QStyleOption(versionIn, SO_FocusRect)
+{
+ state |= QStyle::State_KeyboardFocusChange; // assume we had one, will be corrected in initFrom()
+}
+
+/*!
+ Constructs a QStyleOptionFrame, initializing the members
+ variables to their default values.
+*/
+QStyleOptionFrame::QStyleOptionFrame()
+ : QStyleOption(Version, SO_Frame), lineWidth(0), midLineWidth(0),
+ features(None), frameShape(NoFrame)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionFrame::QStyleOptionFrame(int versionIn)
+ : QStyleOption(versionIn, SO_Frame), lineWidth(0), midLineWidth(0),
+ features(None)
+{
+}
+
+/*!
+ Constructs a QStyleOptionGroupBox, initializing the members
+ variables to their default values.
+*/
+QStyleOptionGroupBox::QStyleOptionGroupBox()
+ : QStyleOptionComplex(Version, Type), features(QStyleOptionFrame::None),
+ textAlignment(Qt::AlignLeft), lineWidth(0), midLineWidth(0)
+{
+}
+
+QStyleOptionGroupBox::QStyleOptionGroupBox(int versionIn)
+ : QStyleOptionComplex(versionIn, Type), features(QStyleOptionFrame::None),
+ textAlignment(Qt::AlignLeft), lineWidth(0), midLineWidth(0)
+{
+}
+
+/*!
+ Constructs a QStyleOptionHeader, initializing the members
+ variables to their default values.
+*/
+QStyleOptionHeader::QStyleOptionHeader()
+ : QStyleOption(QStyleOptionHeader::Version, SO_Header),
+ section(0), textAlignment(Qt::AlignLeft), iconAlignment(Qt::AlignLeft),
+ position(QStyleOptionHeader::Beginning),
+ selectedPosition(QStyleOptionHeader::NotAdjacent), sortIndicator(None),
+ orientation(Qt::Horizontal)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionHeader::QStyleOptionHeader(int versionIn)
+ : QStyleOption(versionIn, SO_Header),
+ section(0), textAlignment(Qt::AlignLeft), iconAlignment(Qt::AlignLeft),
+ position(QStyleOptionHeader::Beginning),
+ selectedPosition(QStyleOptionHeader::NotAdjacent), sortIndicator(None),
+ orientation(Qt::Horizontal)
+{
+}
+
+/*!
+ Constructs a QStyleOptionButton, initializing the members
+ variables to their default values.
+*/
+QStyleOptionButton::QStyleOptionButton()
+ : QStyleOption(QStyleOptionButton::Version, SO_Button), features(None)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionButton::QStyleOptionButton(int versionIn)
+ : QStyleOption(versionIn, SO_Button), features(None)
+{
+}
+
+/*!
+ Constructs a QStyleOptionToolBar, initializing the members
+ variables to their default values.
+*/
+QStyleOptionToolBar::QStyleOptionToolBar()
+ : QStyleOption(Version, SO_ToolBar), positionOfLine(OnlyOne), positionWithinLine(OnlyOne),
+ toolBarArea(Qt::TopToolBarArea), features(None), lineWidth(0), midLineWidth(0)
+{
+}
+
+/*!
+ \fn QStyleOptionToolBar::QStyleOptionToolBar(const QStyleOptionToolBar &other)
+
+ Constructs a copy of the \a other style option.
+*/
+QStyleOptionToolBar::QStyleOptionToolBar(int versionIn)
+: QStyleOption(versionIn, SO_ToolBar), positionOfLine(OnlyOne), positionWithinLine(OnlyOne),
+ toolBarArea(Qt::TopToolBarArea), features(None), lineWidth(0), midLineWidth(0)
+{
+
+}
+
+/*!
+ Constructs a QStyleOptionTab object, initializing the members
+ variables to their default values.
+*/
+QStyleOptionTab::QStyleOptionTab()
+ : QStyleOption(QStyleOptionTab::Version, SO_Tab),
+ row(0),
+ position(Beginning),
+ selectedPosition(NotAdjacent), cornerWidgets(QStyleOptionTab::NoCornerWidgets),
+ documentMode(false),
+ features(QStyleOptionTab::None)
+{
+}
+
+QStyleOptionTab::QStyleOptionTab(int versionIn)
+ : QStyleOption(versionIn, SO_Tab),
+ row(0),
+ position(Beginning),
+ selectedPosition(NotAdjacent), cornerWidgets(QStyleOptionTab::NoCornerWidgets),
+ documentMode(false),
+ features(QStyleOptionTab::None)
+{
+}
+
+/*!
+ Constructs a QStyleOptionTabV4 object, initializing the members
+ variables to their default values.
+ */
+QStyleOptionTabV4::QStyleOptionTabV4() : QStyleOptionTab(QStyleOptionTabV4::Version)
+{
+}
+
+/*!
+ Constructs a QStyleOptionProgressBar, initializing the members
+ variables to their default values.
+*/
+QStyleOptionProgressBar::QStyleOptionProgressBar()
+ : QStyleOption(QStyleOptionProgressBar::Version, SO_ProgressBar),
+ minimum(0), maximum(0), progress(0), textAlignment(Qt::AlignLeft), textVisible(false),
+ invertedAppearance(false), bottomToTop(false)
+{
+}
+
+QStyleOptionProgressBar::QStyleOptionProgressBar(int versionIn)
+ : QStyleOption(versionIn, SO_ProgressBar),
+ minimum(0), maximum(0), progress(0), textAlignment(Qt::AlignLeft), textVisible(false),
+ invertedAppearance(false), bottomToTop(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionMenuItem, initializing the members
+ variables to their default values.
+*/
+QStyleOptionMenuItem::QStyleOptionMenuItem()
+ : QStyleOption(QStyleOptionMenuItem::Version, SO_MenuItem), menuItemType(Normal),
+ checkType(NotCheckable), checked(false), menuHasCheckableItems(true), maxIconWidth(0), tabWidth(0)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionMenuItem::QStyleOptionMenuItem(int versionIn)
+ : QStyleOption(versionIn, SO_MenuItem), menuItemType(Normal),
+ checkType(NotCheckable), checked(false), menuHasCheckableItems(true), maxIconWidth(0), tabWidth(0)
+{
+}
+
+/*!
+ Constructs a QStyleOptionComplex of the specified \a type and \a
+ version, initializing the member variables to their default
+ values. This constructor is usually called by subclasses.
+*/
+QStyleOptionComplex::QStyleOptionComplex(int versionIn, int typeIn)
+ : QStyleOption(versionIn, typeIn), subControls(QStyle::SC_All), activeSubControls(QStyle::SC_None)
+{
+}
+
+
+/*!
+ Constructs a QStyleOptionSlider, initializing the members
+ variables to their default values.
+*/
+QStyleOptionSlider::QStyleOptionSlider()
+ : QStyleOptionComplex(Version, SO_Slider), orientation(Qt::Horizontal), minimum(0), maximum(0),
+ tickPosition(NoTicks), tickInterval(0), upsideDown(false),
+ sliderPosition(0), sliderValue(0), singleStep(0), pageStep(0), notchTarget(0.0),
+ dialWrapping(false)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionSlider::QStyleOptionSlider(int versionIn)
+ : QStyleOptionComplex(versionIn, SO_Slider), orientation(Qt::Horizontal), minimum(0), maximum(0),
+ tickPosition(NoTicks), tickInterval(0), upsideDown(false),
+ sliderPosition(0), sliderValue(0), singleStep(0), pageStep(0), notchTarget(0.0),
+ dialWrapping(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionSpinBox, initializing the members
+ variables to their default values.
+*/
+QStyleOptionSpinBox::QStyleOptionSpinBox()
+ : QStyleOptionComplex(Version, SO_SpinBox), buttonSymbols(UpDownArrows),
+ stepEnabled(StepNone), frame(false)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionSpinBox::QStyleOptionSpinBox(int versionIn)
+ : QStyleOptionComplex(versionIn, SO_SpinBox), buttonSymbols(UpDownArrows),
+ stepEnabled(StepNone), frame(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionDockWidget, initializing the member
+ variables to their default values.
+*/
+QStyleOptionDockWidget::QStyleOptionDockWidget()
+ : QStyleOption(Version, SO_DockWidget), closable(false),
+ movable(false), floatable(false), verticalTitleBar(false)
+{
+}
+
+/*!
+ \internal
+*/
+QStyleOptionDockWidget::QStyleOptionDockWidget(int versionIn)
+ : QStyleOption(versionIn, SO_DockWidget), closable(false),
+ movable(false), floatable(false), verticalTitleBar(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionToolButton, initializing the members
+ variables to their default values.
+*/
+QStyleOptionToolButton::QStyleOptionToolButton()
+ : QStyleOptionComplex(Version, SO_ToolButton), features(None), arrowType(Qt::DownArrow)
+ , toolButtonStyle(Qt::ToolButtonIconOnly)
+{
+}
+
+QStyleOptionToolButton::QStyleOptionToolButton(int versionIn)
+ : QStyleOptionComplex(versionIn, SO_ToolButton), features(None), arrowType(Qt::DownArrow)
+ , toolButtonStyle(Qt::ToolButtonIconOnly)
+
+{
+}
+
+/*!
+ Creates a QStyleOptionComboBox, initializing the members variables
+ to their default values.
+*/
+QStyleOptionComboBox::QStyleOptionComboBox()
+ : QStyleOptionComplex(Version, SO_ComboBox), editable(false), frame(true)
+{
+}
+
+QStyleOptionComboBox::QStyleOptionComboBox(int versionIn)
+ : QStyleOptionComplex(versionIn, SO_ComboBox), editable(false), frame(true)
+{
+}
+
+/*!
+ Creates a QStyleOptionToolBox, initializing the members variables
+ to their default values.
+*/
+QStyleOptionToolBox::QStyleOptionToolBox()
+ : QStyleOption(Version, SO_ToolBox), position(Beginning), selectedPosition(NotAdjacent)
+{
+}
+
+QStyleOptionToolBox::QStyleOptionToolBox(int versionIn)
+ : QStyleOption(versionIn, SO_ToolBox), position(Beginning), selectedPosition(NotAdjacent)
+{
+}
+
+
+/*!
+ Creates a QStyleOptionRubberBand, initializing the members
+ variables to their default values.
+*/
+QStyleOptionRubberBand::QStyleOptionRubberBand()
+ : QStyleOption(Version, SO_RubberBand), opaque(false), shape(Line)
+{
+}
+
+QStyleOptionRubberBand::QStyleOptionRubberBand(int versionIn)
+ : QStyleOption(versionIn, SO_RubberBand), opaque(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionTitleBar, initializing the members
+ variables to their default values.
+*/
+QStyleOptionTitleBar::QStyleOptionTitleBar()
+ : QStyleOptionComplex(Version, SO_TitleBar), titleBarState(0)
+{
+}
+
+QStyleOptionTitleBar::QStyleOptionTitleBar(int versionIn)
+ : QStyleOptionComplex(versionIn, SO_TitleBar), titleBarState(0)
+{
+}
+
+/*!
+ Constructs a QStyleOptionViewItem, initializing the members
+ variables to their default values.
+*/
+QStyleOptionViewItem::QStyleOptionViewItem()
+ : QStyleOption(Version, SO_ViewItem),
+ displayAlignment(Qt::AlignLeft), decorationAlignment(Qt::AlignLeft),
+ textElideMode(Qt::ElideMiddle), decorationPosition(Left),
+ showDecorationSelected(false), features(None),
+ checkState(Qt::Unchecked), viewItemPosition(QStyleOptionViewItem::Invalid)
+{
+}
+
+QStyleOptionViewItem::QStyleOptionViewItem(int versionIn)
+ : QStyleOption(versionIn, SO_ViewItem),
+ displayAlignment(Qt::AlignLeft), decorationAlignment(Qt::AlignLeft),
+ textElideMode(Qt::ElideMiddle), decorationPosition(Left),
+ showDecorationSelected(false), features(None),
+ checkState(Qt::Unchecked), viewItemPosition(QStyleOptionViewItem::Invalid)
+{
+}
+
+/*!
+ Constructs a QStyleOptionTabWidgetFrame, initializing the members
+ variables to their default values.
+*/
+QStyleOptionTabWidgetFrame::QStyleOptionTabWidgetFrame()
+ : QStyleOption(Version, SO_TabWidgetFrame), lineWidth(0), midLineWidth(0), shape(QStyleOptionTab::RoundedNorth)
+{
+}
+
+QStyleOptionTabWidgetFrame::QStyleOptionTabWidgetFrame(int versionIn)
+ : QStyleOption(versionIn, SO_TabWidgetFrame), lineWidth(0), midLineWidth(0)
+{
+}
+
+/*!
+ Construct a QStyleOptionTabBarBase, initializing the members
+ vaiables to their default values.
+*/
+QStyleOptionTabBarBase::QStyleOptionTabBarBase()
+ : QStyleOption(Version, SO_TabBarBase), documentMode(false), shape(QStyleOptionTab::RoundedNorth)
+{
+}
+
+QStyleOptionTabBarBase::QStyleOptionTabBarBase(int versionIn)
+ : QStyleOption(versionIn, SO_TabBarBase), documentMode(false)
+{
+}
+
+/*!
+ Constructs a QStyleOptionSizeGrip.
+*/
+QStyleOptionSizeGrip::QStyleOptionSizeGrip()
+ : QStyleOptionComplex(Version, Type), corner(Qt::BottomRightCorner)
+{
+}
+
+QStyleOptionSizeGrip::QStyleOptionSizeGrip(int versionIn)
+ : QStyleOptionComplex(versionIn, Type), corner(Qt::BottomRightCorner)
+{
+}
+
+/*!
+ Constructs a QStyleOptionGraphicsItem.
+*/
+QStyleOptionGraphicsItem::QStyleOptionGraphicsItem()
+ : QStyleOption(Version, Type), levelOfDetail(1)
+{
+}
+
+QStyleOptionGraphicsItem::QStyleOptionGraphicsItem(int versionIn)
+ : QStyleOption(versionIn, Type), levelOfDetail(1)
+{
+}
+
+/*!
+ \since 4.6
+
+ Returns the level of detail from the \a worldTransform.
+
+ Its value represents the maximum value of the height and
+ width of a unity rectangle, mapped using the \a worldTransform
+ of the painter used to draw the item. By default, if no
+ transformations are applied, its value is 1. If zoomed out 1:2, the level
+ of detail will be 0.5, and if zoomed in 2:1, its value is 2.
+
+ \sa QGraphicsScene::minimumRenderSize()
+*/
+qreal QStyleOptionGraphicsItem::levelOfDetailFromTransform(const QTransform &worldTransform)
+{
+ if (worldTransform.type() <= QTransform::TxTranslate)
+ return 1; // Translation only? The LOD is 1.
+
+ // Two unit vectors.
+ QLineF v1(0, 0, 1, 0);
+ QLineF v2(0, 0, 0, 1);
+ // LOD is the transformed area of a 1x1 rectangle.
+ return qSqrt(worldTransform.map(v1).length() * worldTransform.map(v2).length());
+}
+
+/*!
+ Constructs a QStyleHintReturn with version \a version and type \a
+ type.
+
+ The version has no special meaning for QStyleHintReturn; it can be
+ used by subclasses to distinguish between different version of
+ the same hint type.
+
+ \sa QStyleOption::version, QStyleOption::type
+*/
+QStyleHintReturn::QStyleHintReturn(int versionIn, int type)
+ : version(versionIn), type(type)
+{
+}
+
+/*!
+ \internal
+*/
+
+QStyleHintReturn::~QStyleHintReturn()
+{
+}
+
+/*!
+ Constructs a QStyleHintReturnMask. The member variables are
+ initialized to default values.
+*/
+QStyleHintReturnMask::QStyleHintReturnMask() : QStyleHintReturn(Version, Type)
+{
+}
+
+QStyleHintReturnMask::~QStyleHintReturnMask()
+{
+}
+
+/*!
+ Constructs a QStyleHintReturnVariant. The member variables are
+ initialized to default values.
+*/
+QStyleHintReturnVariant::QStyleHintReturnVariant() : QStyleHintReturn(Version, Type)
+{
+}
+
+QStyleHintReturnVariant::~QStyleHintReturnVariant()
+{
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug debug, const QStyleOption::OptionType &optionType)
+{
+#if !defined(QT_NO_DEBUG)
+ switch (optionType) {
+ case QStyleOption::SO_Default:
+ debug << "SO_Default"; break;
+ case QStyleOption::SO_FocusRect:
+ debug << "SO_FocusRect"; break;
+ case QStyleOption::SO_Button:
+ debug << "SO_Button"; break;
+ case QStyleOption::SO_Tab:
+ debug << "SO_Tab"; break;
+ case QStyleOption::SO_MenuItem:
+ debug << "SO_MenuItem"; break;
+ case QStyleOption::SO_Frame:
+ debug << "SO_Frame"; break;
+ case QStyleOption::SO_ProgressBar:
+ debug << "SO_ProgressBar"; break;
+ case QStyleOption::SO_ToolBox:
+ debug << "SO_ToolBox"; break;
+ case QStyleOption::SO_Header:
+ debug << "SO_Header"; break;
+ case QStyleOption::SO_DockWidget:
+ debug << "SO_DockWidget"; break;
+ case QStyleOption::SO_ViewItem:
+ debug << "SO_ViewItem"; break;
+ case QStyleOption::SO_TabWidgetFrame:
+ debug << "SO_TabWidgetFrame"; break;
+ case QStyleOption::SO_TabBarBase:
+ debug << "SO_TabBarBase"; break;
+ case QStyleOption::SO_RubberBand:
+ debug << "SO_RubberBand"; break;
+ case QStyleOption::SO_Complex:
+ debug << "SO_Complex"; break;
+ case QStyleOption::SO_Slider:
+ debug << "SO_Slider"; break;
+ case QStyleOption::SO_SpinBox:
+ debug << "SO_SpinBox"; break;
+ case QStyleOption::SO_ToolButton:
+ debug << "SO_ToolButton"; break;
+ case QStyleOption::SO_ComboBox:
+ debug << "SO_ComboBox"; break;
+ case QStyleOption::SO_TitleBar:
+ debug << "SO_TitleBar"; break;
+ case QStyleOption::SO_CustomBase:
+ debug << "SO_CustomBase"; break;
+ case QStyleOption::SO_GroupBox:
+ debug << "SO_GroupBox"; break;
+ case QStyleOption::SO_ToolBar:
+ debug << "SO_ToolBar"; break;
+ case QStyleOption::SO_ComplexCustomBase:
+ debug << "SO_ComplexCustomBase"; break;
+ case QStyleOption::SO_SizeGrip:
+ debug << "SO_SizeGrip"; break;
+ case QStyleOption::SO_GraphicsItem:
+ debug << "SO_GraphicsItem"; break;
+ }
+#else
+ Q_UNUSED(optionType);
+#endif
+ return debug;
+}
+
+QDebug operator<<(QDebug debug, const QStyleOption &option)
+{
+#if !defined(QT_NO_DEBUG)
+ debug << "QStyleOption(";
+ debug << QStyleOption::OptionType(option.type);
+ debug << ',' << (option.direction == Qt::RightToLeft ? "RightToLeft" : "LeftToRight");
+ debug << ',' << option.state;
+ debug << ',' << option.rect;
+ debug << ',' << option.styleObject;
+ debug << ')';
+#else
+ Q_UNUSED(option);
+#endif
+ return debug;
+}
+#endif
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/qquickstyleoption.h b/src/quicknativestyle/qstyle/qquickstyleoption.h
new file mode 100644
index 0000000000..0aeddab8d0
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qquickstyleoption.h
@@ -0,0 +1,796 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSTYLEOPTION_H
+#define QSTYLEOPTION_H
+
+#include "qquickstyle.h"
+
+#include <QtCore/qlocale.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qabstractitemmodel.h>
+
+#include <QtGui/qicon.h>
+#include <QtGui/qfontmetrics.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+
+namespace QQC2 {
+
+class QStyleOption
+{
+public:
+ enum OptionType {
+ SO_Default, SO_FocusRect, SO_Button, SO_Tab, SO_MenuItem,
+ SO_Frame, SO_ProgressBar, SO_ToolBox, SO_Header,
+ SO_DockWidget, SO_ViewItem, SO_TabWidgetFrame,
+ SO_TabBarBase, SO_RubberBand, SO_ToolBar, SO_GraphicsItem,
+
+ SO_Complex = 0xf0000, SO_Slider, SO_SpinBox, SO_ToolButton, SO_ComboBox,
+ SO_TitleBar, SO_GroupBox, SO_SizeGrip,
+
+ SO_CustomBase = 0xf00,
+ SO_ComplexCustomBase = 0xf000000
+ };
+ Q_ENUMS(OptionType)
+
+ enum StyleOptionType { Type = SO_Default };
+ enum StyleOptionVersion { Version = 1 };
+
+ int version; // TODO: Remove version information
+ int type;
+ QStyle::State state;
+ Qt::LayoutDirection direction;
+ QRect rect;
+ QFontMetrics fontMetrics;
+ QPalette palette;
+ QObject *styleObject;
+
+ // QQC2 additions. Remember to also update copy
+ // constructor and assignment operator when adding
+ // new variables here.
+ QQuickItem *control;
+ QWindow *window;
+
+ QStyleOption(int version = QStyleOption::Version, int type = SO_Default);
+ QStyleOption(const QStyleOption &other);
+ ~QStyleOption();
+
+ QStyleOption &operator=(const QStyleOption &other);
+};
+
+class QStyleOptionFocusRect : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_FocusRect };
+ enum StyleOptionVersion { Version = 1 };
+
+ QColor backgroundColor;
+
+ QStyleOptionFocusRect();
+ QStyleOptionFocusRect(const QStyleOptionFocusRect &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionFocusRect &operator=(const QStyleOptionFocusRect &) = default;
+
+protected:
+ QStyleOptionFocusRect(int version);
+};
+
+class QStyleOptionFrame : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_Frame };
+ enum StyleOptionVersion { Version = 3 };
+ enum FrameFeature {
+ None = 0x00,
+ Flat = 0x01,
+ Rounded = 0x02
+ };
+ Q_DECLARE_FLAGS(FrameFeatures, FrameFeature)
+ enum Shape {
+ NoFrame = 0, // no frame
+ Box = 0x0001, // rectangular box
+ Panel = 0x0002, // rectangular panel
+ WinPanel = 0x0003, // rectangular panel (Windows)
+ HLine = 0x0004, // horizontal line
+ VLine = 0x0005, // vertical line
+ StyledPanel = 0x0006 // rectangular panel depending on the GUI style
+ };
+ enum Shadow {
+ Plain = 0x0010, // plain line
+ Raised = 0x0020, // raised shadow effect
+ Sunken = 0x0030 // sunken shadow effect
+ };
+
+ int lineWidth;
+ int midLineWidth;
+ FrameFeatures features;
+ Shape frameShape;
+
+ QStyleOptionFrame();
+ QStyleOptionFrame(const QStyleOptionFrame &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionFrame &operator=(const QStyleOptionFrame &) = default;
+
+protected:
+ QStyleOptionFrame(int version);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionFrame::FrameFeatures)
+Q_DECLARE_MIXED_ENUM_OPERATORS_SYMMETRIC(int, QStyleOptionFrame::Shape, QStyleOptionFrame::Shadow)
+
+Q_DECL_DEPRECATED typedef QStyleOptionFrame QStyleOptionFrameV2;
+Q_DECL_DEPRECATED typedef QStyleOptionFrame QStyleOptionFrameV3;
+
+class QStyleOptionTab : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_Tab };
+ enum StyleOptionVersion { Version = 3 };
+
+ enum TabPosition { Beginning, Middle, End, OnlyOneTab };
+ enum SelectedPosition { NotAdjacent, NextIsSelected, PreviousIsSelected };
+ enum CornerWidget { NoCornerWidgets = 0x00, LeftCornerWidget = 0x01,
+ RightCornerWidget = 0x02 };
+ enum TabFeature { None = 0x00, HasFrame = 0x01 };
+ enum Shape { RoundedNorth, RoundedSouth, RoundedWest, RoundedEast,
+ TriangularNorth, TriangularSouth, TriangularWest, TriangularEast
+ };
+ Q_DECLARE_FLAGS(CornerWidgets, CornerWidget)
+ Q_DECLARE_FLAGS(TabFeatures, TabFeature)
+
+ QString text;
+ QIcon icon;
+ int row;
+ TabPosition position;
+ Shape shape = RoundedNorth;
+ SelectedPosition selectedPosition;
+ CornerWidgets cornerWidgets;
+ QSize iconSize;
+ bool documentMode;
+ QSize leftButtonSize;
+ QSize rightButtonSize;
+ TabFeatures features;
+
+ QStyleOptionTab();
+ QStyleOptionTab(const QStyleOptionTab &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionTab &operator=(const QStyleOptionTab &) = default;
+
+protected:
+ QStyleOptionTab(int version);
+};
+
+class QStyleOptionTabWidgetFrame : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_TabWidgetFrame };
+ enum StyleOptionVersion { Version = 2 };
+
+ int lineWidth;
+ int midLineWidth;
+ QStyleOptionTab::Shape shape;
+ QSize tabBarSize;
+ QSize rightCornerWidgetSize;
+ QSize leftCornerWidgetSize;
+ QRect tabBarRect;
+ QRect selectedTabRect;
+
+ QStyleOptionTabWidgetFrame();
+ inline QStyleOptionTabWidgetFrame(const QStyleOptionTabWidgetFrame &other)
+ : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionTabWidgetFrame &operator=(const QStyleOptionTabWidgetFrame &) = default;
+
+protected:
+ QStyleOptionTabWidgetFrame(int version);
+};
+
+Q_DECL_DEPRECATED typedef QStyleOptionTabWidgetFrame QStyleOptionTabWidgetFrameV2;
+
+
+class QStyleOptionTabBarBase : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_TabBarBase };
+
+ enum TabBarPosition { North, South, West, East };
+ enum ButtonPosition { LeftSide, RightSide };
+
+ QRect tabBarRect;
+ QRect selectedTabRect;
+ bool documentMode;
+ QStyleOptionTab::Shape shape;
+
+ QStyleOptionTabBarBase();
+ QStyleOptionTabBarBase(const QStyleOptionTabBarBase &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionTabBarBase &operator=(const QStyleOptionTabBarBase &) = default;
+
+protected:
+ QStyleOptionTabBarBase(int version);
+};
+
+class QStyleOptionHeader : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_Header };
+ enum StyleOptionVersion { Version = 1 };
+ enum SectionPosition { Beginning, Middle, End, OnlyOneSection };
+ enum SelectedPosition { NotAdjacent, NextIsSelected, PreviousIsSelected,
+ NextAndPreviousAreSelected };
+ enum SortIndicator { None, SortUp, SortDown };
+
+ int section;
+ QString text;
+ Qt::Alignment textAlignment;
+ QIcon icon;
+ Qt::Alignment iconAlignment;
+ SectionPosition position;
+ SelectedPosition selectedPosition;
+ SortIndicator sortIndicator;
+ Qt::Orientation orientation;
+
+ QStyleOptionHeader();
+ QStyleOptionHeader(const QStyleOptionHeader &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionHeader &operator=(const QStyleOptionHeader &) = default;
+
+protected:
+ QStyleOptionHeader(int version);
+};
+
+class QStyleOptionButton : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_Button };
+ enum StyleOptionVersion { Version = 1 };
+
+ enum ButtonFeature { None = 0x00, Flat = 0x01, HasMenu = 0x02, DefaultButton = 0x04,
+ AutoDefaultButton = 0x08, CommandLinkButton = 0x10 };
+ Q_DECLARE_FLAGS(ButtonFeatures, ButtonFeature)
+
+ ButtonFeatures features;
+ QString text;
+ QIcon icon;
+ QSize iconSize;
+
+ QStyleOptionButton();
+ QStyleOptionButton(const QStyleOptionButton &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionButton &operator=(const QStyleOptionButton &) = default;
+
+protected:
+ QStyleOptionButton(int version);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionButton::ButtonFeatures)
+
+class QStyleOptionTabV4 : public QStyleOptionTab
+{
+public:
+ enum StyleOptionVersion { Version = 4 };
+ QStyleOptionTabV4();
+ int tabIndex = -1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionTab::CornerWidgets)
+
+Q_DECL_DEPRECATED typedef QStyleOptionTab QStyleOptionTabV2;
+Q_DECL_DEPRECATED typedef QStyleOptionTab QStyleOptionTabV3;
+
+
+class QStyleOptionToolBar : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_ToolBar };
+ enum StyleOptionVersion { Version = 1 };
+ enum ToolBarPosition { Beginning, Middle, End, OnlyOne };
+ enum ToolBarFeature { None = 0x0, Movable = 0x1 };
+ Q_DECLARE_FLAGS(ToolBarFeatures, ToolBarFeature)
+
+ ToolBarPosition positionOfLine; // The toolbar line position
+ ToolBarPosition positionWithinLine; // The position within a toolbar
+ Qt::ToolBarArea toolBarArea; // The toolbar docking area
+ ToolBarFeatures features;
+ int lineWidth;
+ int midLineWidth;
+
+ QStyleOptionToolBar();
+ QStyleOptionToolBar(const QStyleOptionToolBar &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionToolBar &operator=(const QStyleOptionToolBar &) = default;
+
+protected:
+ QStyleOptionToolBar(int version);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionToolBar::ToolBarFeatures)
+
+class QStyleOptionProgressBar : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_ProgressBar };
+ enum StyleOptionVersion { Version = 2 };
+
+ int minimum;
+ int maximum;
+ int progress;
+ QString text;
+ Qt::Alignment textAlignment;
+ bool textVisible;
+ bool invertedAppearance;
+ bool bottomToTop;
+
+ QStyleOptionProgressBar();
+ QStyleOptionProgressBar(const QStyleOptionProgressBar &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionProgressBar &operator=(const QStyleOptionProgressBar &) = default;
+
+protected:
+ QStyleOptionProgressBar(int version);
+};
+
+class QStyleOptionMenuItem : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_MenuItem };
+ enum StyleOptionVersion { Version = 1 };
+
+ enum MenuItemType { Normal, DefaultItem, Separator, SubMenu, Scroller, TearOff, Margin,
+ EmptyArea };
+ enum CheckType { NotCheckable, Exclusive, NonExclusive };
+
+ MenuItemType menuItemType;
+ CheckType checkType;
+ bool checked;
+ bool menuHasCheckableItems;
+ QRect menuRect;
+ QString text;
+ QIcon icon;
+ int maxIconWidth;
+ int tabWidth; // ### Qt 6: rename to reservedShortcutWidth
+ QFont font;
+
+ QStyleOptionMenuItem();
+ QStyleOptionMenuItem(const QStyleOptionMenuItem &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionMenuItem &operator=(const QStyleOptionMenuItem &) = default;
+
+protected:
+ QStyleOptionMenuItem(int version);
+};
+
+class QStyleOptionDockWidget : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_DockWidget };
+ enum StyleOptionVersion { Version = 2 };
+
+ QString title;
+ bool closable;
+ bool movable;
+ bool floatable;
+ bool verticalTitleBar;
+
+ QStyleOptionDockWidget();
+ QStyleOptionDockWidget(const QStyleOptionDockWidget &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionDockWidget &operator=(const QStyleOptionDockWidget &) = default;
+
+protected:
+ QStyleOptionDockWidget(int version);
+};
+
+Q_DECL_DEPRECATED typedef QStyleOptionDockWidget QStyleOptionDockWidgetV2;
+
+class QStyleOptionViewItem : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_ViewItem };
+ enum StyleOptionVersion { Version = 4 };
+
+ enum Position { Left, Right, Top, Bottom };
+ enum ScrollMode { ScrollPerItem, ScrollPerPixel }; // Doesn't really belong in this class.
+
+ Qt::Alignment displayAlignment;
+ Qt::Alignment decorationAlignment;
+ Qt::TextElideMode textElideMode;
+ Position decorationPosition;
+ QSize decorationSize;
+ QFont font;
+ bool showDecorationSelected;
+
+ enum ViewItemFeature {
+ None = 0x00,
+ WrapText = 0x01,
+ Alternate = 0x02,
+ HasCheckIndicator = 0x04,
+ HasDisplay = 0x08,
+ HasDecoration = 0x10
+ };
+ Q_DECLARE_FLAGS(ViewItemFeatures, ViewItemFeature)
+
+ ViewItemFeatures features;
+
+ QLocale locale;
+
+ enum ViewItemPosition { Invalid, Beginning, Middle, End, OnlyOne };
+
+ QModelIndex index;
+ Qt::CheckState checkState;
+ QIcon icon;
+ QString text;
+ ViewItemPosition viewItemPosition;
+ QBrush backgroundBrush;
+
+ QStyleOptionViewItem();
+ QStyleOptionViewItem(const QStyleOptionViewItem &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionViewItem &operator=(const QStyleOptionViewItem &) = default;
+
+protected:
+ QStyleOptionViewItem(int version);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionViewItem::ViewItemFeatures)
+
+Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV2;
+Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV3;
+Q_DECL_DEPRECATED typedef QStyleOptionViewItem QStyleOptionViewItemV4;
+
+class QStyleOptionToolBox : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_ToolBox };
+ enum StyleOptionVersion { Version = 2 };
+
+ QString text;
+ QIcon icon;
+
+ enum TabPosition { Beginning, Middle, End, OnlyOneTab };
+ enum SelectedPosition { NotAdjacent, NextIsSelected, PreviousIsSelected };
+
+ TabPosition position;
+ SelectedPosition selectedPosition;
+
+ QStyleOptionToolBox();
+ QStyleOptionToolBox(const QStyleOptionToolBox &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionToolBox &operator=(const QStyleOptionToolBox &) = default;
+
+protected:
+ QStyleOptionToolBox(int version);
+};
+
+Q_DECL_DEPRECATED typedef QStyleOptionToolBox QStyleOptionToolBoxV2;
+
+class QStyleOptionRubberBand : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_RubberBand };
+ enum StyleOptionVersion { Version = 1 };
+ enum Shape { Line, Rectangle };
+
+ bool opaque;
+ Shape shape;
+
+ QStyleOptionRubberBand();
+ QStyleOptionRubberBand(const QStyleOptionRubberBand &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionRubberBand &operator=(const QStyleOptionRubberBand &) = default;
+
+protected:
+ QStyleOptionRubberBand(int version);
+};
+
+// -------------------------- Complex style options -------------------------------
+class QStyleOptionComplex : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_Complex };
+ enum StyleOptionVersion { Version = 1 };
+
+ QStyle::SubControls subControls;
+ QStyle::SubControls activeSubControls;
+
+ QStyleOptionComplex(int version = QStyleOptionComplex::Version, int type = SO_Complex);
+ QStyleOptionComplex(const QStyleOptionComplex &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionComplex &operator=(const QStyleOptionComplex &) = default;
+};
+
+class QStyleOptionSlider : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_Slider };
+ enum StyleOptionVersion { Version = 1 };
+ enum TickPosition {
+ NoTicks = 0,
+ TicksAbove = 1,
+ TicksLeft = TicksAbove,
+ TicksBelow = 2,
+ TicksRight = TicksBelow,
+ TicksBothSides = 3
+ };
+
+ Qt::Orientation orientation;
+ int minimum;
+ int maximum;
+ TickPosition tickPosition;
+ int tickInterval;
+ bool upsideDown;
+ int sliderPosition;
+ int sliderValue;
+ int singleStep;
+ int pageStep;
+ qreal notchTarget;
+ bool dialWrapping;
+
+ QStyleOptionSlider();
+ QStyleOptionSlider(const QStyleOptionSlider &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionSlider &operator=(const QStyleOptionSlider &) = default;
+
+protected:
+ QStyleOptionSlider(int version);
+};
+
+class QStyleOptionSpinBox : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_SpinBox };
+ enum StyleOptionVersion { Version = 1 };
+ enum StepEnabledFlag { StepNone = 0x00, StepUpEnabled = 0x01, StepDownEnabled = 0x02, StepEnabled = 0xFF };
+ enum ButtonSymbols { UpDownArrows, PlusMinus, NoButtons };
+
+ ButtonSymbols buttonSymbols;
+ StepEnabledFlag stepEnabled;
+ bool frame;
+
+ QStyleOptionSpinBox();
+ QStyleOptionSpinBox(const QStyleOptionSpinBox &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionSpinBox &operator=(const QStyleOptionSpinBox &) = default;
+
+protected:
+ QStyleOptionSpinBox(int version);
+};
+
+class QStyleOptionToolButton : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_ToolButton };
+ enum StyleOptionVersion { Version = 1 };
+
+ enum ToolButtonFeature { None = 0x00, Arrow = 0x01, Menu = 0x04, MenuButtonPopup = Menu, PopupDelay = 0x08,
+ HasMenu = 0x10 };
+ Q_DECLARE_FLAGS(ToolButtonFeatures, ToolButtonFeature)
+
+ ToolButtonFeatures features;
+ QIcon icon;
+ QSize iconSize;
+ QString text;
+ Qt::ArrowType arrowType;
+ Qt::ToolButtonStyle toolButtonStyle;
+ QPoint pos;
+ QFont font;
+
+ QStyleOptionToolButton();
+ QStyleOptionToolButton(const QStyleOptionToolButton &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionToolButton &operator=(const QStyleOptionToolButton &) = default;
+
+protected:
+ QStyleOptionToolButton(int version);
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QStyleOptionToolButton::ToolButtonFeatures)
+
+class QStyleOptionComboBox : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_ComboBox };
+ enum StyleOptionVersion { Version = 1 };
+
+ bool editable;
+ QRect popupRect;
+ bool frame;
+ QString currentText;
+ QIcon currentIcon;
+ QSize iconSize;
+
+ QStyleOptionComboBox();
+ QStyleOptionComboBox(const QStyleOptionComboBox &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionComboBox &operator=(const QStyleOptionComboBox &) = default;
+
+protected:
+ QStyleOptionComboBox(int version);
+};
+
+class QStyleOptionTitleBar : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_TitleBar };
+ enum StyleOptionVersion { Version = 1 };
+
+ QString text;
+ QIcon icon;
+ int titleBarState;
+ Qt::WindowFlags titleBarFlags;
+
+ QStyleOptionTitleBar();
+ QStyleOptionTitleBar(const QStyleOptionTitleBar &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionTitleBar &operator=(const QStyleOptionTitleBar &) = default;
+
+protected:
+ QStyleOptionTitleBar(int version);
+};
+
+class QStyleOptionGroupBox : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_GroupBox };
+ enum StyleOptionVersion { Version = 1 };
+
+ QStyleOptionFrame::FrameFeatures features;
+ QString text;
+ Qt::Alignment textAlignment;
+ QColor textColor;
+ int lineWidth;
+ int midLineWidth;
+
+ QStyleOptionGroupBox();
+ QStyleOptionGroupBox(const QStyleOptionGroupBox &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionGroupBox &operator=(const QStyleOptionGroupBox &) = default;
+protected:
+ QStyleOptionGroupBox(int version);
+};
+
+class QStyleOptionSizeGrip : public QStyleOptionComplex
+{
+public:
+ enum StyleOptionType { Type = SO_SizeGrip };
+ enum StyleOptionVersion { Version = 1 };
+
+ Qt::Corner corner;
+
+ QStyleOptionSizeGrip();
+ QStyleOptionSizeGrip(const QStyleOptionSizeGrip &other) : QStyleOptionComplex(Version, Type) { *this = other; }
+ QStyleOptionSizeGrip &operator=(const QStyleOptionSizeGrip &) = default;
+protected:
+ QStyleOptionSizeGrip(int version);
+};
+
+class QStyleOptionGraphicsItem : public QStyleOption
+{
+public:
+ enum StyleOptionType { Type = SO_GraphicsItem };
+ enum StyleOptionVersion { Version = 1 };
+
+ QRectF exposedRect;
+ qreal levelOfDetail;
+
+ QStyleOptionGraphicsItem();
+ QStyleOptionGraphicsItem(const QStyleOptionGraphicsItem &other) : QStyleOption(Version, Type) { *this = other; }
+ QStyleOptionGraphicsItem &operator=(const QStyleOptionGraphicsItem &) = default;
+ static qreal levelOfDetailFromTransform(const QTransform &worldTransform);
+protected:
+ QStyleOptionGraphicsItem(int version);
+};
+
+template <typename T>
+T qstyleoption_cast(const QStyleOption *opt)
+{
+ typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Opt;
+ if (opt && opt->version >= Opt::Version && (opt->type == Opt::Type
+ || int(Opt::Type) == QStyleOption::SO_Default
+ || (int(Opt::Type) == QStyleOption::SO_Complex
+ && opt->type > QStyleOption::SO_Complex)))
+ return static_cast<T>(opt);
+ return nullptr;
+}
+
+template <typename T>
+T qstyleoption_cast(QStyleOption *opt)
+{
+ typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Opt;
+ if (opt && opt->version >= Opt::Version && (opt->type == Opt::Type
+ || int(Opt::Type) == QStyleOption::SO_Default
+ || (int(Opt::Type) == QStyleOption::SO_Complex
+ && opt->type > QStyleOption::SO_Complex)))
+ return static_cast<T>(opt);
+ return nullptr;
+}
+
+// -------------------------- QStyleHintReturn -------------------------------
+
+class QStyleHintReturn
+{
+public:
+ enum HintReturnType {
+ SH_Default=0xf000, SH_Mask, SH_Variant
+ };
+
+ enum StyleOptionType { Type = SH_Default };
+ enum StyleOptionVersion { Version = 1 };
+
+ QStyleHintReturn(int version = QStyleOption::Version, int type = SH_Default);
+ ~QStyleHintReturn();
+
+ int version;
+ int type;
+};
+
+class QStyleHintReturnMask : public QStyleHintReturn
+{
+public:
+ enum StyleOptionType { Type = SH_Mask };
+ enum StyleOptionVersion { Version = 1 };
+
+ QStyleHintReturnMask();
+ ~QStyleHintReturnMask();
+
+ QRegion region;
+};
+
+class QStyleHintReturnVariant : public QStyleHintReturn
+{
+public:
+ enum StyleOptionType { Type = SH_Variant };
+ enum StyleOptionVersion { Version = 1 };
+
+ QStyleHintReturnVariant();
+ ~QStyleHintReturnVariant();
+
+ QVariant variant;
+};
+
+template <typename T>
+T qstyleoption_cast(const QStyleHintReturn *hint)
+{
+ typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Opt;
+ if (hint && hint->version <= Opt::Version &&
+ (hint->type == Opt::Type || int(Opt::Type) == QStyleHintReturn::SH_Default))
+ return static_cast<T>(hint);
+ return nullptr;
+}
+
+template <typename T>
+T qstyleoption_cast(QStyleHintReturn *hint)
+{
+ typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type Opt;
+ if (hint && hint->version <= Opt::Version &&
+ (hint->type == Opt::Type || int(Opt::Type) == QStyleHintReturn::SH_Default))
+ return static_cast<T>(hint);
+ return nullptr;
+}
+
+#if !defined(QT_NO_DEBUG_STREAM)
+QDebug operator<<(QDebug debug, const QStyleOption::OptionType &optionType);
+QDebug operator<<(QDebug debug, const QStyleOption &option);
+#endif
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QSTYLEOPTION_H
diff --git a/src/quicknativestyle/qstyle/qstyle.pri b/src/quicknativestyle/qstyle/qstyle.pri
new file mode 100644
index 0000000000..4d02549897
--- /dev/null
+++ b/src/quicknativestyle/qstyle/qstyle.pri
@@ -0,0 +1,23 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qquicknativestyle.h \
+ $$PWD/qquickcommonstyle.h \
+ $$PWD/qquickcommonstyle_p.h \
+ $$PWD/qquickcommonstylepixmaps_p.h \
+ $$PWD/qquickdrawutil.h \
+ $$PWD/qquickstyle.h \
+ $$PWD/qquickstyle_p.h \
+ $$PWD/qquickstylehelper_p.h \
+ $$PWD/qquickstyleoption.h
+
+SOURCES += \
+ $$PWD/qquicknativestyle.cpp \
+ $$PWD/qquickcommonstyle.cpp \
+ $$PWD/qquickdrawutil.cpp \
+ $$PWD/qquickstyle.cpp \
+ $$PWD/qquickstylehelper.cpp \
+ $$PWD/qquickstyleoption.cpp
+
+macos: include(mac/mac.pri)
+win32: include(windows/windows.pri)
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp
new file mode 100644
index 0000000000..242b770ddc
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle.cpp
@@ -0,0 +1,2388 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickwindowsstyle_p.h"
+#include "qquickwindowsstyle_p_p.h"
+#include "qquickstyleoption.h"
+#include "qquickstylehelper_p.h"
+#include "qquickdrawutil.h"
+
+#include <QtGui/qbitmap.h>
+#include <QtGui/qevent.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qpainter.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qtextstream.h>
+#include <QtGui/qpixmapcache.h>
+#include <private/qmath_p.h>
+#include <qmath.h>
+#include <QtGui/qpainterpath.h>
+#include <QtGui/qscreen.h>
+#include <QtGui/qwindow.h>
+#include <qpa/qplatformtheme.h>
+#include <qpa/qplatformscreen.h>
+#include <private/qguiapplication_p.h>
+#include <private/qhighdpiscaling_p.h>
+#include <qpa/qplatformnativeinterface.h>
+
+#if 0 && QT_CONFIG(animation)
+//#include <private/qstyleanimation_p.h>
+#endif
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_WIN)
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qt_windows.h"
+QT_END_INCLUDE_NAMESPACE
+# ifndef COLOR_GRADIENTACTIVECAPTION
+# define COLOR_GRADIENTACTIVECAPTION 27
+# endif
+# ifndef COLOR_GRADIENTINACTIVECAPTION
+# define COLOR_GRADIENTINACTIVECAPTION 28
+# endif
+
+Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
+#endif //Q_OS_WIN
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <limits.h>
+QT_END_INCLUDE_NAMESPACE
+
+namespace QQC2 {
+
+enum QSliderDirection { SlUp, SlDown, SlLeft, SlRight };
+
+/*
+ \internal
+*/
+
+QWindowsStylePrivate::QWindowsStylePrivate() = default;
+
+qreal QWindowsStylePrivate::appDevicePixelRatio()
+{
+ return qApp->devicePixelRatio();
+}
+
+bool QWindowsStylePrivate::isDarkMode()
+{
+ bool result = false;
+#ifdef Q_OS_WIN
+ // Windows only: Return whether dark mode style support is desired and
+ // dark mode is in effect.
+ if (auto ni = QGuiApplication::platformNativeInterface()) {
+ const QVariant darkModeStyleP = ni->property("darkModeStyle");
+ result = darkModeStyleP.metaType().id() == QMetaType::Bool
+ && darkModeStyleP.value<bool>()
+ && ni->property("darkMode").value<bool>();
+ }
+#endif
+ return result;
+}
+
+// ###TODO SH_UnderlineShortcut
+#if 0
+// Returns \c true if the toplevel parent of \a widget has seen the Alt-key
+bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const
+{
+ widget = widget->window();
+ return seenAlt.contains(widget);
+}
+
+/*!
+ \reimp
+*/
+bool QWindowsStyle::eventFilter(QObject *o, QEvent *e)
+{
+ // Records Alt- and Focus events
+// if (!o->isWidgetType())
+ return QObject::eventFilter(o, e);
+ QWidget *widget = qobject_cast<QWidget*>(o);
+ Q_D(QWindowsStyle);
+ switch (e->type()) {
+ case QEvent::KeyPress:
+ if (static_cast<QKeyEvent *>(e)->key() == Qt::Key_Alt) {
+ widget = widget->window();
+
+ // Alt has been pressed - find all widgets that care
+ QList<QWidget *> l = widget->findChildren<QWidget *>();
+ auto ignorable = [](QWidget *w) {
+ return w->isWindow() || !w->isVisible()
+ || w->style()->styleHint(SH_UnderlineShortcut, nullptr, w);
+ };
+ l.erase(std::remove_if (l.begin(), l.end(), ignorable), l.end());
+ // Update states before repainting
+ d->seenAlt.append(widget);
+ d->alt_down = true;
+
+ // Repaint all relevant widgets
+ for (int pos = 0; pos < l.size(); ++pos)
+ l.at(pos)->update();
+ }
+ break;
+ case QEvent::KeyRelease:
+ if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Alt) {
+ widget = widget->window();
+
+ // Update state and repaint the menu bars.
+ d->alt_down = false;
+#if 0 && QT_CONFIG(menubar)
+ QList<QMenuBar *> l = widget->findChildren<QMenuBar *>();
+ for (int i = 0; i < l.size(); ++i)
+ l.at(i)->update();
+#endif
+ }
+ break;
+ case QEvent::Close:
+ // Reset widget when closing
+ d->seenAlt.removeAll(widget);
+ d->seenAlt.removeAll(widget->window());
+ break;
+ default:
+ break;
+ }
+ return QCommonStyle::eventFilter(o, e);
+}
+#endif
+
+/*!
+ \class QWindowsStyle
+ \brief The QWindowsStyle class provides a Microsoft Windows-like look and feel.
+
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ This style is Qt's default GUI style on Windows.
+
+ \image qwindowsstyle.png
+ \sa QWindowsVistaStyle, QMacStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindowsStyle object.
+*/
+QWindowsStyle::QWindowsStyle() : QCommonStyle(*new QWindowsStylePrivate)
+{
+}
+
+/*!
+ \internal
+
+ Constructs a QWindowsStyle object.
+*/
+QWindowsStyle::QWindowsStyle(QWindowsStylePrivate &dd) : QCommonStyle(dd)
+{
+}
+
+
+/*! Destroys the QWindowsStyle object. */
+QWindowsStyle::~QWindowsStyle()
+{
+}
+
+#ifdef Q_OS_WIN
+static inline QRgb colorref2qrgb(COLORREF col)
+{
+ return qRgb(GetRValue(col), GetGValue(col), GetBValue(col));
+}
+#endif
+#if 0
+/*! \reimp */
+void QWindowsStyle::polish(QApplication *app)
+{
+ QCommonStyle::polish(app);
+ QWindowsStylePrivate *d = const_cast<QWindowsStylePrivate*>(d_func());
+ // We only need the overhead when shortcuts are sometimes hidden
+ if (!proxy()->styleHint(SH_UnderlineShortcut, nullptr) && app)
+ app->installEventFilter(this);
+
+ const auto &palette = QGuiApplication::palette();
+ d->activeGradientCaptionColor = palette.highlight().color();
+ d->activeCaptionColor = d->activeGradientCaptionColor;
+ d->inactiveGradientCaptionColor = palette.dark().color();
+ d->inactiveCaptionColor = d->inactiveGradientCaptionColor;
+ d->inactiveCaptionText = palette.window().color();
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) //fetch native title bar colors
+ if (app->desktopSettingsAware()){
+ DWORD activeCaption = GetSysColor(COLOR_ACTIVECAPTION);
+ DWORD gradientActiveCaption = GetSysColor(COLOR_GRADIENTACTIVECAPTION);
+ DWORD inactiveCaption = GetSysColor(COLOR_INACTIVECAPTION);
+ DWORD gradientInactiveCaption = GetSysColor(COLOR_GRADIENTINACTIVECAPTION);
+ DWORD inactiveCaptionText = GetSysColor(COLOR_INACTIVECAPTIONTEXT);
+ d->activeCaptionColor = colorref2qrgb(activeCaption);
+ d->activeGradientCaptionColor = colorref2qrgb(gradientActiveCaption);
+ d->inactiveCaptionColor = colorref2qrgb(inactiveCaption);
+ d->inactiveGradientCaptionColor = colorref2qrgb(gradientInactiveCaption);
+ d->inactiveCaptionText = colorref2qrgb(inactiveCaptionText);
+ }
+#endif
+}
+
+/*! \reimp */
+void QWindowsStyle::unpolish(QApplication *app)
+{
+ QCommonStyle::unpolish(app);
+ app->removeEventFilter(this);
+}
+
+/*! \reimp */
+void QWindowsStyle::polish(QWidget *widget)
+{
+ QCommonStyle::polish(widget);
+}
+
+/*! \reimp */
+void QWindowsStyle::unpolish(QWidget *widget)
+{
+ QCommonStyle::unpolish(widget);
+}
+
+/*!
+ \reimp
+*/
+void QWindowsStyle::polish(QPalette &pal)
+{
+ QCommonStyle::polish(pal);
+}
+#endif
+
+int QWindowsStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *opt)
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ switch (pm) {
+ case QStyle::PM_DockWidgetFrameWidth:
+ return GetSystemMetrics(SM_CXFRAME);
+
+ case QStyle::PM_TitleBarHeight:
+ Q_ASSERT(opt);
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(opt)) {
+ if ((tb->titleBarFlags & Qt::WindowType_Mask) == Qt::Tool) {
+ // MS always use one less than they say
+ return GetSystemMetrics(SM_CYSMCAPTION) - 1;
+ }
+ }
+ return GetSystemMetrics(SM_CYCAPTION) - 1;
+
+ case QStyle::PM_ScrollBarExtent:
+ {
+ NONCLIENTMETRICS ncm;
+ ncm.cbSize = FIELD_OFFSET(NONCLIENTMETRICS, lfMessageFont) + sizeof(LOGFONT);
+ if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0))
+ return qMax(ncm.iScrollHeight, ncm.iScrollWidth);
+ }
+ break;
+
+ case QStyle::PM_MdiSubWindowFrameWidth:
+ return GetSystemMetrics(SM_CYFRAME);
+
+ default:
+ break;
+ }
+#else // Q_OS_WIN && !Q_OS_WINRT
+ Q_UNUSED(pm);
+ Q_UNUSED(widget);
+#endif
+ return QWindowsStylePrivate::InvalidMetric;
+}
+
+int QWindowsStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm)
+{
+ switch (pm) {
+ case QStyle::PM_ToolBarItemSpacing:
+ return 0;
+ case QStyle::PM_ButtonDefaultIndicator:
+ case QStyle::PM_ButtonShiftHorizontal:
+ case QStyle::PM_ButtonShiftVertical:
+ case QStyle::PM_MenuHMargin:
+ case QStyle::PM_MenuVMargin:
+ case QStyle::PM_ToolBarItemMargin:
+ return 1;
+ case QStyle::PM_DockWidgetSeparatorExtent:
+ return 4;
+#if 0 && QT_CONFIG(tabbar)
+ case QStyle::PM_TabBarTabShiftHorizontal:
+ return 0;
+ case QStyle::PM_TabBarTabShiftVertical:
+ return 2;
+#endif
+
+ case QStyle::PM_SliderLength:
+ return 11;
+
+#if 0 && QT_CONFIG(menu)
+ case QStyle::PM_MenuBarHMargin:
+ case QStyle::PM_MenuBarVMargin:
+ case QStyle::PM_MenuBarPanelWidth:
+ return 0;
+ case QStyle::PM_SmallIconSize:
+ return 16;
+ case QStyle::PM_LargeIconSize:
+ return 32;
+ case QStyle::PM_DockWidgetTitleMargin:
+ return 2;
+ case QStyle::PM_DockWidgetTitleBarButtonMargin:
+ case QStyle::PM_DockWidgetFrameWidth:
+ return 4;
+
+#endif // QT_CONFIG(menu)
+ case QStyle::PM_ToolBarHandleExtent:
+ return 10;
+ default:
+ break;
+ }
+ return QWindowsStylePrivate::InvalidMetric;
+}
+
+static QScreen *screenOf(const QWindow *w)
+{
+ if (w) {
+ if (auto screen = w->screen())
+ return screen;
+ }
+ return QGuiApplication::primaryScreen();
+}
+
+// Calculate the overall scale factor to obtain Qt Device Independent
+// Pixels from a native Windows size. Divide by devicePixelRatio
+// and account for secondary screens with differing logical DPI.
+qreal QWindowsStylePrivate::nativeMetricScaleFactor(const QStyleOption *opt)
+{
+ Q_ASSERT(opt);
+ const QWindow *win = opt->window;
+ return nativeMetricScaleFactor(win);
+}
+
+qreal QWindowsStylePrivate::nativeMetricScaleFactor(const QWindow *win)
+{
+ qreal result = qreal(1) / QWindowsStylePrivate::devicePixelRatio(win);
+ if (QGuiApplicationPrivate::screen_list.size() > 1) {
+ const QScreen *primaryScreen = QGuiApplication::primaryScreen();
+ const QScreen *screen = screenOf(win);
+ if (screen != primaryScreen) {
+ const qreal primaryLogicalDpi = primaryScreen->handle()->logicalDpi().first;
+ const qreal logicalDpi = screen->handle()->logicalDpi().first;
+ if (!qFuzzyCompare(primaryLogicalDpi, logicalDpi))
+ result *= logicalDpi / primaryLogicalDpi;
+ }
+ }
+ return result;
+}
+
+/*!
+ \reimp
+*/
+int QWindowsStyle::pixelMetric(PixelMetric pm, const QStyleOption *opt) const
+{
+ int ret = QWindowsStylePrivate::pixelMetricFromSystemDp(pm, opt);
+ if (ret != QWindowsStylePrivate::InvalidMetric)
+ return qRound(qreal(ret) * QWindowsStylePrivate::nativeMetricScaleFactor(opt));
+
+ ret = QWindowsStylePrivate::fixedPixelMetric(pm);
+ if (ret != QWindowsStylePrivate::InvalidMetric)
+ return int(QStyleHelper::dpiScaled(ret, opt));
+
+ ret = 0;
+
+ switch (pm) {
+ case PM_MaximumDragDistance:
+ ret = QCommonStyle::pixelMetric(PM_MaximumDragDistance);
+ if (ret == -1)
+ ret = 60;
+ break;
+
+ // Returns the number of pixels to use for the business part of the
+ // slider (i.e., the non-tickmark portion). The remaining space is shared
+ // equally between the tickmark regions.
+ case PM_SliderControlThickness:
+ if (const QStyleOptionSlider *sl = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int space = (sl->orientation == Qt::Horizontal) ? sl->rect.height() : sl->rect.width();
+ int ticks = sl->tickPosition;
+ int n = 0;
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ ++n;
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ ++n;
+ if (!n) {
+ ret = space;
+ break;
+ }
+
+ int thick = 6; // Magic constant to get 5 + 16 + 5
+ if (ticks != QStyleOptionSlider::TicksBothSides && ticks != QStyleOptionSlider::NoTicks)
+ thick += proxy()->pixelMetric(PM_SliderLength, sl) / 4;
+
+ space -= thick;
+ if (space > 0)
+ thick += (space * 2) / (n + 2);
+ ret = thick;
+ }
+ break;
+
+ case PM_IconViewIconSize:
+ ret = proxy()->pixelMetric(PM_LargeIconSize, opt);
+ break;
+
+ case PM_SplitterWidth:
+ ret = int(QStyleHelper::dpiScaled(4, opt));
+ break;
+
+ default:
+ ret = QCommonStyle::pixelMetric(pm, opt);
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ \reimp
+ */
+QPixmap QWindowsStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt) const
+{
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ QPixmap desktopIcon;
+ switch (standardPixmap) {
+ case SP_DriveCDIcon:
+ case SP_DriveDVDIcon:
+ case SP_DriveNetIcon:
+ case SP_DriveHDIcon:
+ case SP_DriveFDIcon:
+ case SP_FileIcon:
+ case SP_FileLinkIcon:
+ case SP_DirLinkIcon:
+ case SP_DirClosedIcon:
+ case SP_DesktopIcon:
+ case SP_ComputerIcon:
+ case SP_DirOpenIcon:
+ case SP_FileDialogNewFolder:
+ case SP_DirHomeIcon:
+ case SP_TrashIcon:
+ case SP_VistaShield:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardPixmap);
+ desktopIcon = theme->standardPixmap(sp, QSizeF(16, 16));
+ }
+ break;
+ case SP_MessageBoxInformation:
+ case SP_MessageBoxWarning:
+ case SP_MessageBoxCritical:
+ case SP_MessageBoxQuestion:
+ if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme()) {
+ QPlatformTheme::StandardPixmap sp = static_cast<QPlatformTheme::StandardPixmap>(standardPixmap);
+ desktopIcon = theme->standardPixmap(sp, QSizeF());
+ }
+ break;
+ default:
+ break;
+ }
+ if (!desktopIcon.isNull()) {
+ return desktopIcon;
+ }
+#endif // Q_OS_WIN && !Q_OS_WINRT
+ return QCommonStyle::standardPixmap(standardPixmap, opt);
+}
+
+/*! \reimp */
+int QWindowsStyle::styleHint(StyleHint hint, const QStyleOption *opt,
+ QStyleHintReturn *returnData) const
+{
+ int ret = 0;
+
+ switch (hint) {
+ case SH_EtchDisabledText:
+ ret = d_func()->isDarkMode() ? 0 : 1;
+ break;
+ case SH_Slider_SnapToValue:
+ case SH_PrintDialog_RightAlignButtons:
+ case SH_FontDialog_SelectAssociatedText:
+ case SH_Menu_AllowActiveAndDisabled:
+ case SH_MenuBar_AltKeyNavigation:
+ case SH_MenuBar_MouseTracking:
+ case SH_Menu_MouseTracking:
+ case SH_ComboBox_ListMouseTracking:
+ case SH_Slider_StopMouseOverSlider:
+ case SH_MainWindow_SpaceBelowMenuBar:
+ ret = 1;
+
+ break;
+ case SH_ItemView_ShowDecorationSelected:
+#if 0 && QT_CONFIG(listview)
+ if (qobject_cast<const QListView*>(widget))
+ ret = 1;
+#endif
+ break;
+ case SH_ItemView_ChangeHighlightOnFocus:
+ ret = 1;
+ break;
+ case SH_ToolBox_SelectedPageTitleBold:
+ ret = 0;
+ break;
+
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) // Option not used on WinRT -> common style
+ case SH_UnderlineShortcut:
+ {
+ ret = 1;
+ BOOL cues = false;
+ SystemParametersInfo(SPI_GETKEYBOARDCUES, 0, &cues, 0);
+ ret = int(cues);
+ // Do nothing if we always paint underlines
+ Q_D(const QWindowsStyle);
+ if (!ret && d) {
+#if 0 && QT_CONFIG(menubar)
+ const QMenuBar *menuBar = qobject_cast<const QMenuBar *>(widget);
+ if (!menuBar && qobject_cast<const QMenu *>(widget)) {
+ QWidget *w = QApplication::activeWindow();
+ if (w && w != widget)
+ menuBar = w->findChild<QMenuBar *>();
+ }
+ // If we paint a menu bar draw underlines if is in the keyboardState
+ if (menuBar) {
+ if (menuBar->d_func()->keyboardState || d->altDown())
+ ret = 1;
+ // Otherwise draw underlines if the toplevel widget has seen an alt-press
+ } else
+#endif // QT_CONFIG(menubar)
+// if (d->hasSeenAlt(widget)) {
+// ret = 1;
+// }
+ }
+#ifndef QT_NO_ACCESSIBILITY
+ if (!ret && opt && opt->type == QStyleOption::SO_MenuItem
+ && QStyleHelper::isInstanceOf(opt->styleObject, QAccessible::MenuItem)
+ && opt->styleObject->property("_q_showUnderlined").toBool())
+ ret = 1;
+#endif // QT_NO_ACCESSIBILITY
+ break;
+ }
+#endif // Q_OS_WIN && !Q_OS_WINRT
+ case SH_Menu_SubMenuSloppyCloseTimeout:
+ case SH_Menu_SubMenuPopupDelay: {
+#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
+ DWORD delay;
+ if (SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &delay, 0))
+ ret = delay;
+ else
+#endif // Q_OS_WIN && !Q_OS_WINRT
+ ret = 400;
+ break;
+ }
+#if 0 && QT_CONFIG(rubberband)
+ case SH_RubberBand_Mask:
+ if (const QStyleOptionRubberBand *rbOpt = qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
+ ret = 0;
+ if (rbOpt->shape == QRubberBand::Rectangle) {
+ ret = true;
+ if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
+ mask->region = opt->rect;
+ int size = 1;
+ if (widget && widget->isWindow())
+ size = 4;
+ mask->region -= opt->rect.adjusted(size, size, -size, -size);
+ }
+ }
+ }
+ break;
+#endif // QT_CONFIG(rubberband)
+#if 0 && QT_CONFIG(wizard)
+ case SH_WizardStyle:
+ ret = QWizard::ModernStyle;
+ break;
+#endif
+ case SH_ItemView_ArrowKeysNavigateIntoChildren:
+ ret = true;
+ break;
+ case SH_DialogButtonBox_ButtonsHaveIcons:
+ ret = 0;
+ break;
+ default:
+ ret = QCommonStyle::styleHint(hint, opt, returnData);
+ break;
+ }
+ return ret;
+}
+
+/*! \reimp */
+void QWindowsStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const
+{
+ // Used to restore across fallthrough cases. Currently only used in PE_IndicatorCheckBox
+ bool doRestore = false;
+
+ switch (pe) {
+#if 0 && QT_CONFIG(toolbar)
+ case PE_IndicatorToolBarSeparator:
+ {
+ QRect rect = opt->rect;
+ const int margin = 2;
+ QPen oldPen = p->pen();
+ if (opt->state & State_Horizontal){
+ const int offset = rect.width()/2;
+ p->setPen(QPen(opt->palette.dark().color()));
+ p->drawLine(rect.bottomLeft().x() + offset,
+ rect.bottomLeft().y() - margin,
+ rect.topLeft().x() + offset,
+ rect.topLeft().y() + margin);
+ p->setPen(QPen(opt->palette.light().color()));
+ p->drawLine(rect.bottomLeft().x() + offset + 1,
+ rect.bottomLeft().y() - margin,
+ rect.topLeft().x() + offset + 1,
+ rect.topLeft().y() + margin);
+ }
+ else{ //Draw vertical separator
+ const int offset = rect.height()/2;
+ p->setPen(QPen(opt->palette.dark().color()));
+ p->drawLine(rect.topLeft().x() + margin ,
+ rect.topLeft().y() + offset,
+ rect.topRight().x() - margin,
+ rect.topRight().y() + offset);
+ p->setPen(QPen(opt->palette.light().color()));
+ p->drawLine(rect.topLeft().x() + margin ,
+ rect.topLeft().y() + offset + 1,
+ rect.topRight().x() - margin,
+ rect.topRight().y() + offset + 1);
+ }
+ p->setPen(oldPen);
+ }
+ break;
+ case PE_IndicatorToolBarHandle:
+ p->save();
+ p->translate(opt->rect.x(), opt->rect.y());
+ if (opt->state & State_Horizontal) {
+ int x = opt->rect.width() / 2 - 4;
+ if (opt->direction == Qt::RightToLeft)
+ x -= 2;
+ if (opt->rect.height() > 4) {
+ qDrawShadePanel(p, x, 2, 3, opt->rect.height() - 4,
+ opt->palette, false, 1, nullptr);
+ qDrawShadePanel(p, x + 3, 2, 3, opt->rect.height() - 4,
+ opt->palette, false, 1, nullptr);
+ }
+ } else {
+ if (opt->rect.width() > 4) {
+ int y = opt->rect.height() / 2 - 4;
+ qDrawShadePanel(p, 2, y, opt->rect.width() - 4, 3,
+ opt->palette, false, 1, nullptr);
+ qDrawShadePanel(p, 2, y + 3, opt->rect.width() - 4, 3,
+ opt->palette, false, 1, nullptr);
+ }
+ }
+ p->restore();
+ break;
+
+#endif // QT_CONFIG(toolbar)
+ case PE_FrameButtonTool:
+ case PE_PanelButtonTool: {
+ QPen oldPen = p->pen();
+#if 0 && QT_CONFIG(dockwidget)
+ if (w && w->inherits("QDockWidgetTitleButton")) {
+ if (const QWidget *dw = w->parentWidget())
+ if (dw->isWindow()){
+ qDrawWinButton(p, opt->rect.adjusted(1, 1, 0, 0), opt->palette, opt->state & (State_Sunken | State_On),
+ &opt->palette.button());
+
+ return;
+ }
+ }
+#endif // QT_CONFIG(dockwidget)
+ QBrush fill;
+ bool stippled;
+ bool panel = (pe == PE_PanelButtonTool);
+ if ((!(opt->state & State_Sunken ))
+ && (!(opt->state & State_Enabled)
+ || !(opt->state & State_MouseOver && opt->state & State_AutoRaise))
+ && (opt->state & State_On)) {
+ fill = QBrush(opt->palette.light().color(), Qt::Dense4Pattern);
+ stippled = true;
+ } else {
+ fill = opt->palette.brush(QPalette::Button);
+ stippled = false;
+ }
+
+ if (opt->state & (State_Raised | State_Sunken | State_On)) {
+ if (opt->state & State_AutoRaise) {
+ if (opt->state & (State_Enabled | State_Sunken | State_On)){
+ if (panel)
+ qDrawShadePanel(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), 1, &fill);
+ else
+ qDrawShadeRect(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), 1);
+ }
+ if (stippled) {
+ p->setPen(opt->palette.button().color());
+ p->drawRect(opt->rect.adjusted(1,1,-2,-2));
+ }
+ } else {
+ qDrawWinButton(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), panel ? &fill : nullptr);
+ }
+ } else {
+ p->fillRect(opt->rect, fill);
+ }
+ p->setPen(oldPen);
+ break; }
+ case PE_PanelButtonCommand:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ QBrush fill;
+ State flags = opt->state;
+ QPalette pal = opt->palette;
+ QRect r = opt->rect;
+ if (! (flags & State_Sunken) && (flags & State_On))
+ fill = QBrush(pal.light().color(), Qt::Dense4Pattern);
+ else
+ fill = pal.brush(QPalette::Button);
+
+ if (btn->features & QStyleOptionButton::DefaultButton && flags & State_Sunken) {
+ p->setPen(pal.dark().color());
+ p->setBrush(fill);
+ p->drawRect(r.adjusted(0, 0, -1, -1));
+ } else if (flags & (State_Raised | State_On | State_Sunken)) {
+ qDrawWinButton(p, r, pal, flags & (State_Sunken | State_On),
+ &fill);
+ } else {
+ p->fillRect(r, fill);
+ }
+ }
+ break;
+ case PE_FrameDefaultButton: {
+ QPen oldPen = p->pen();
+ p->setPen(QPen(opt->palette.shadow().color(), 0));
+ QRectF rect = opt->rect;
+ const qreal dpi = QStyleHelper::dpi(opt);
+ const qreal topLevelAdjustment = QStyleHelper::dpiScaled(0.5, dpi);
+ const qreal bottomRightAdjustment = QStyleHelper::dpiScaled(-1.5, dpi);
+ rect.adjust(topLevelAdjustment, topLevelAdjustment,
+ bottomRightAdjustment, bottomRightAdjustment);
+ p->drawRect(rect);
+ p->setPen(oldPen);
+ break;
+ }
+ case PE_IndicatorCheckBox: {
+ QBrush fill;
+ if (opt->state & State_NoChange)
+ fill = QBrush(opt->palette.base().color(), Qt::Dense4Pattern);
+ else if (opt->state & State_Sunken)
+ fill = opt->palette.button();
+ else if (opt->state & State_Enabled)
+ fill = opt->palette.base();
+ else
+ fill = opt->palette.window();
+ p->save();
+ doRestore = true;
+ qDrawWinPanel(p, opt->rect, opt->palette, true, &fill);
+ if (opt->state & State_NoChange)
+ p->setPen(opt->palette.dark().color());
+ else
+ p->setPen(opt->palette.text().color());
+ }
+ Q_FALLTHROUGH();
+ case PE_IndicatorItemViewItemCheck:
+ if (!doRestore) {
+ p->save();
+ doRestore = true;
+ }
+#if 0 && QT_CONFIG(itemviews)
+ if (pe == PE_IndicatorItemViewItemCheck) {
+ const QStyleOptionViewItem *itemViewOpt = qstyleoption_cast<const QStyleOptionViewItem *>(opt);
+ p->setPen(itemViewOpt
+ && itemViewOpt->showDecorationSelected
+ && opt->state & State_Selected
+ ? opt->palette.highlightedText().color()
+ : opt->palette.text().color());
+ if (opt->state & State_NoChange)
+ p->setBrush(opt->palette.brush(QPalette::Button));
+ p->drawRect(opt->rect.x() + 1, opt->rect.y() + 1, opt->rect.width() - 2, opt->rect.height() - 2);
+ }
+#endif // QT_CONFIG(itemviews)
+ if (!(opt->state & State_Off)) {
+ QPointF points[6];
+ qreal scaleh = opt->rect.width() / 12.0;
+ qreal scalev = opt->rect.height() / 12.0;
+ points[0] = { opt->rect.x() + 3.5 * scaleh, opt->rect.y() + 5.5 * scalev };
+ points[1] = { points[0].x(), points[0].y() + 2 * scalev };
+ points[2] = { points[1].x() + 2 * scaleh, points[1].y() + 2 * scalev };
+ points[3] = { points[2].x() + 4 * scaleh, points[2].y() - 4 * scalev };
+ points[4] = { points[3].x(), points[3].y() - 2 * scalev };
+ points[5] = { points[4].x() - 4 * scaleh, points[4].y() + 4 * scalev };
+ p->setPen(QPen(opt->palette.text().color(), 0));
+ p->setBrush(opt->palette.text().color());
+ p->drawPolygon(points, 6);
+ }
+ if (doRestore)
+ p->restore();
+ break;
+ case PE_FrameFocusRect:
+ if (const QStyleOptionFocusRect *fropt = qstyleoption_cast<const QStyleOptionFocusRect *>(opt)) {
+ //### check for d->alt_down
+ if (!(fropt->state & State_KeyboardFocusChange) && !proxy()->styleHint(SH_UnderlineShortcut, opt))
+ return;
+ QRect r = opt->rect;
+ p->save();
+ p->setBackgroundMode(Qt::TransparentMode);
+ QColor bg_col = fropt->backgroundColor;
+ if (!bg_col.isValid())
+ bg_col = p->background().color();
+ // Create an "XOR" color.
+ QColor patternCol((bg_col.red() ^ 0xff) & 0xff,
+ (bg_col.green() ^ 0xff) & 0xff,
+ (bg_col.blue() ^ 0xff) & 0xff);
+ p->setBrush(QBrush(patternCol, Qt::Dense4Pattern));
+ p->setBrushOrigin(r.topLeft());
+ p->setPen(Qt::NoPen);
+ p->drawRect(r.left(), r.top(), r.width(), 1); // Top
+ p->drawRect(r.left(), r.bottom(), r.width(), 1); // Bottom
+ p->drawRect(r.left(), r.top(), 1, r.height()); // Left
+ p->drawRect(r.right(), r.top(), 1, r.height()); // Right
+ p->restore();
+ }
+ break;
+ case PE_IndicatorRadioButton:
+ {
+ QRect r = opt->rect;
+ p->save();
+ p->setRenderHint(QPainter::Antialiasing, true);
+
+ QPointF circleCenter = r.center() + QPoint(1, 1);
+ qreal radius = (r.width() + (r.width() + 1) % 2) / 2.0 - 1;
+
+ QPainterPath path1;
+ path1.addEllipse(circleCenter, radius, radius);
+ radius *= 0.85;
+ QPainterPath path2;
+ path2.addEllipse(circleCenter, radius, radius);
+ radius *= 0.85;
+ QPainterPath path3;
+ path3.addEllipse(circleCenter, radius, radius);
+ radius *= 0.5;
+ QPainterPath path4;
+ path4.addEllipse(circleCenter, radius, radius);
+
+ QPolygon topLeftPol, bottomRightPol;
+ topLeftPol.setPoints(3, r.x(), r.y(), r.x(), r.y() + r.height(), r.x() + r.width(), r.y());
+ bottomRightPol.setPoints(3, r.x(), r.y() + r.height(), r.x() + r.width(), r.y() + r.height(), r.x() + r.width(), r.y());
+
+ p->setClipRegion(QRegion(topLeftPol));
+ p->setPen(opt->palette.dark().color());
+ p->setBrush(opt->palette.dark().color());
+ p->drawPath(path1);
+ p->setPen(opt->palette.shadow().color());
+ p->setBrush(opt->palette.shadow().color());
+ p->drawPath(path2);
+
+ p->setClipRegion(QRegion(bottomRightPol));
+ p->setPen(opt->palette.light().color());
+ p->setBrush(opt->palette.light().color());
+ p->drawPath(path1);
+ p->setPen(opt->palette.midlight().color());
+ p->setBrush(opt->palette.midlight().color());
+ p->drawPath(path2);
+
+ QColor fillColor = ((opt->state & State_Sunken) || !(opt->state & State_Enabled)) ?
+ opt->palette.button().color() : opt->palette.base().color();
+
+ p->setClipping(false);
+ p->setPen(fillColor);
+ p->setBrush(fillColor);
+ p->drawPath(path3);
+
+ if (opt->state & State_On) {
+ p->setPen(opt->palette.text().color());
+ p->setBrush(opt->palette.text());
+ p->drawPath(path4);
+ }
+ p->restore();
+ break;
+ }
+#ifndef QT_NO_FRAME
+ case PE_Frame:
+ case PE_FrameMenu:
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ if (frame->lineWidth == 2 || pe == PE_Frame) {
+ QPalette popupPal = frame->palette;
+ if (pe == PE_FrameMenu) {
+ popupPal.setColor(QPalette::Light, frame->palette.window().color());
+ popupPal.setColor(QPalette::Midlight, frame->palette.light().color());
+ }
+ if (pe == PE_Frame && (frame->state & State_Raised))
+ qDrawWinButton(p, frame->rect, popupPal, frame->state & State_Sunken);
+ else if (pe == PE_Frame && (frame->state & State_Sunken))
+ {
+ popupPal.setColor(QPalette::Midlight, frame->palette.window().color());
+ qDrawWinPanel(p, frame->rect, popupPal, frame->state & State_Sunken);
+ }
+ else
+ qDrawWinPanel(p, frame->rect, popupPal, frame->state & State_Sunken);
+ } else {
+ QCommonStyle::drawPrimitive(pe, opt, p);
+ }
+ } else {
+ QPalette popupPal = opt->palette;
+ popupPal.setColor(QPalette::Light, opt->palette.window().color());
+ popupPal.setColor(QPalette::Midlight, opt->palette.light().color());
+ qDrawWinPanel(p, opt->rect, popupPal, opt->state & State_Sunken);
+ }
+ break;
+#endif // QT_NO_FRAME
+ case PE_FrameButtonBevel:
+ case PE_PanelButtonBevel: {
+ QBrush fill;
+ bool panel = pe != PE_FrameButtonBevel;
+ p->setBrushOrigin(opt->rect.topLeft());
+ if (!(opt->state & State_Sunken) && (opt->state & State_On))
+ fill = QBrush(opt->palette.light().color(), Qt::Dense4Pattern);
+ else
+ fill = opt->palette.brush(QPalette::Button);
+
+ if (opt->state & (State_Raised | State_On | State_Sunken)) {
+ qDrawWinButton(p, opt->rect, opt->palette, opt->state & (State_Sunken | State_On),
+ panel ? &fill : nullptr);
+ } else {
+ if (panel)
+ p->fillRect(opt->rect, fill);
+ else
+ p->drawRect(opt->rect);
+ }
+ break; }
+ case PE_FrameWindow: {
+ QPalette popupPal = opt->palette;
+ popupPal.setColor(QPalette::Light, opt->palette.window().color());
+ popupPal.setColor(QPalette::Midlight, opt->palette.light().color());
+ qDrawWinPanel(p, opt->rect, popupPal, opt->state & State_Sunken);
+ break; }
+#if 0 && QT_CONFIG(dockwidget)
+ case PE_IndicatorDockWidgetResizeHandle:
+ break;
+ case PE_FrameDockWidget:
+ if (qstyleoption_cast<const QStyleOptionFrame *>(opt)) {
+ proxy()->drawPrimitive(QStyle::PE_FrameWindow, opt, p, w);
+ }
+ break;
+#endif // QT_CONFIG(dockwidget)
+
+ case PE_FrameStatusBarItem:
+ qDrawShadePanel(p, opt->rect, opt->palette, true, 1, nullptr);
+ break;
+
+ case PE_IndicatorProgressChunk:
+ {
+ bool vertical = false, inverted = false;
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ vertical = !(pb->state & QStyle::State_Horizontal);
+ inverted = pb->invertedAppearance;
+ }
+
+ int space = 2;
+ int chunksize = proxy()->pixelMetric(PM_ProgressBarChunkWidth, opt) - space;
+ if (!vertical) {
+ if (opt->rect.width() <= chunksize)
+ space = 0;
+
+ if (inverted)
+ p->fillRect(opt->rect.x() + space, opt->rect.y(), opt->rect.width() - space, opt->rect.height(),
+ opt->palette.brush(QPalette::Highlight));
+ else
+ p->fillRect(opt->rect.x(), opt->rect.y(), opt->rect.width() - space, opt->rect.height(),
+ opt->palette.brush(QPalette::Highlight));
+ } else {
+ if (opt->rect.height() <= chunksize)
+ space = 0;
+
+ if (inverted)
+ p->fillRect(opt->rect.x(), opt->rect.y(), opt->rect.width(), opt->rect.height() - space,
+ opt->palette.brush(QPalette::Highlight));
+ else
+ p->fillRect(opt->rect.x(), opt->rect.y() + space, opt->rect.width(), opt->rect.height() - space,
+ opt->palette.brush(QPalette::Highlight));
+ }
+ }
+ break;
+
+ case PE_FrameTabWidget: {
+ qDrawWinButton(p, opt->rect, opt->palette, false, nullptr);
+ break;
+ }
+ default:
+ QCommonStyle::drawPrimitive(pe, opt, p);
+ }
+}
+
+/*! \reimp */
+void QWindowsStyle::drawControl(ControlElement ce, const QStyleOption *opt, QPainter *p) const
+{
+ switch (ce) {
+#if 0 && QT_CONFIG(rubberband)
+ case CE_RubberBand:
+ if (qstyleoption_cast<const QStyleOptionRubberBand *>(opt)) {
+ // ### workaround for slow general painter path
+ QPixmap tiledPixmap(16, 16);
+ QPainter pixmapPainter(&tiledPixmap);
+ pixmapPainter.setPen(Qt::NoPen);
+ pixmapPainter.setBrush(Qt::Dense4Pattern);
+ pixmapPainter.setBackground(Qt::white);
+ pixmapPainter.setBackgroundMode(Qt::OpaqueMode);
+ pixmapPainter.drawRect(0, 0, tiledPixmap.width(), tiledPixmap.height());
+ pixmapPainter.end();
+ tiledPixmap = QPixmap::fromImage(tiledPixmap.toImage());
+ p->save();
+ QRect r = opt->rect;
+ QStyleHintReturnMask mask;
+ if (proxy()->styleHint(QStyle::SH_RubberBand_Mask, opt, widget, &mask))
+ p->setClipRegion(mask.region);
+ p->drawTiledPixmap(r.x(), r.y(), r.width(), r.height(), tiledPixmap);
+ p->restore();
+ return;
+ }
+ break;
+#endif // QT_CONFIG(rubberband)
+
+#if 0 && QT_CONFIG(menu) && QT_CONFIG(mainwindow)
+ case CE_MenuBarEmptyArea:
+ if (widget && qobject_cast<const QMainWindow *>(widget->parentWidget())) {
+ p->fillRect(opt->rect, opt->palette.button());
+ QPen oldPen = p->pen();
+ p->setPen(QPen(opt->palette.dark().color()));
+ p->drawLine(opt->rect.bottomLeft(), opt->rect.bottomRight());
+ p->setPen(oldPen);
+ }
+ break;
+#endif
+#if 0 && QT_CONFIG(menu)
+ case CE_MenuItem:
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ int x, y, w, h;
+ menuitem->rect.getRect(&x, &y, &w, &h);
+ int tab = menuitem->tabWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
+ ? menuitem->checked : false;
+ bool act = menuitem->state & State_Selected;
+
+ // windows always has a check column, regardless whether we have an icon or not
+ int checkcol = qMax<int>(menuitem->maxIconWidth, QWindowsStylePrivate::windowsCheckMarkWidth);
+
+ QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button);
+ p->fillRect(menuitem->rect.adjusted(0, 0, -1, 0), fill);
+
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator){
+ int yoff = y-1 + h / 2;
+ p->setPen(menuitem->palette.dark().color());
+ p->drawLine(x + 2, yoff, x + w - 4, yoff);
+ p->setPen(menuitem->palette.light().color());
+ p->drawLine(x + 2, yoff + 1, x + w - 4, yoff + 1);
+ return;
+ }
+
+ QRect vCheckRect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x(), menuitem->rect.y(), checkcol, menuitem->rect.height()));
+ if (!menuitem->icon.isNull() && checked) {
+ if (act) {
+ qDrawShadePanel(p, vCheckRect,
+ menuitem->palette, true, 1,
+ &menuitem->palette.brush(QPalette::Button));
+ } else {
+ QBrush fill(menuitem->palette.light().color(), Qt::Dense4Pattern);
+ qDrawShadePanel(p, vCheckRect, menuitem->palette, true, 1, &fill);
+ }
+ } else if (!act) {
+ p->fillRect(vCheckRect, menuitem->palette.brush(QPalette::Button));
+ }
+
+ // On Windows Style, if we have a checkable item and an icon we
+ // draw the icon recessed to indicate an item is checked. If we
+ // have no icon, we draw a checkmark instead.
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ QPixmap pixmap;
+ if (checked)
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, opt, widget), mode, QIcon::On);
+ else
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, opt, widget), mode);
+ const int pixw = pixmap.width() / pixmap.devicePixelRatio();
+ const int pixh = pixmap.height() / pixmap.devicePixelRatio();
+ QRect pmr(0, 0, pixw, pixh);
+ pmr.moveCenter(vCheckRect.center());
+ p->setPen(menuitem->palette.text().color());
+ p->drawPixmap(pmr.topLeft(), pixmap);
+ } else if (checked) {
+ QStyleOptionMenuItem newMi = *menuitem;
+ newMi.state = State_None;
+ if (!dis)
+ newMi.state |= State_Enabled;
+ if (act)
+ newMi.state |= State_On;
+ newMi.rect = visualRect(opt->direction, menuitem->rect, QRect(menuitem->rect.x() + QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.y() + QWindowsStylePrivate::windowsItemFrame,
+ checkcol - 2 * QWindowsStylePrivate::windowsItemFrame,
+ menuitem->rect.height() - 2 * QWindowsStylePrivate::windowsItemFrame));
+ proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p, widget);
+ }
+ p->setPen(act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color());
+
+ QColor discol;
+ if (dis) {
+ discol = menuitem->palette.text().color();
+ p->setPen(discol);
+ }
+
+ int xm = int(QWindowsStylePrivate::windowsItemFrame) + checkcol + int(QWindowsStylePrivate::windowsItemHMargin);
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + QWindowsStylePrivate::windowsItemVMargin,
+ w - xm - QWindowsStylePrivate::windowsRightBorder - tab + 1, h - 2 * QWindowsStylePrivate::windowsItemVMargin);
+ QRect vTextRect = visualRect(opt->direction, menuitem->rect, textRect);
+ QStringRef s(&menuitem->text);
+ if (!s.isEmpty()) { // draw text
+ p->save();
+ int t = s.indexOf(QLatin1Char('\t'));
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(opt->direction, menuitem->rect,
+ QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
+ const QString textToDraw = s.mid(t + 1).toString();
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, opt, widget)) {
+ p->setPen(menuitem->palette.light().color());
+ p->drawText(vShortcutRect.adjusted(1, 1, 1, 1), text_flags, textToDraw);
+ p->setPen(discol);
+ }
+ p->drawText(vShortcutRect, text_flags, textToDraw);
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ p->setFont(font);
+ const QString textToDraw = s.left(t).toString();
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, opt, widget)) {
+ p->setPen(menuitem->palette.light().color());
+ p->drawText(vTextRect.adjusted(1, 1, 1, 1), text_flags, textToDraw);
+ p->setPen(discol);
+ }
+ p->drawText(vTextRect, text_flags, textToDraw);
+ p->restore();
+ }
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
+ int dim = (h - 2 * QWindowsStylePrivate::windowsItemFrame) / 2;
+ PrimitiveElement arrow;
+ arrow = (opt->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
+ xpos = x + w - QWindowsStylePrivate::windowsArrowHMargin - QWindowsStylePrivate::windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(opt->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ if (act)
+ newMI.palette.setColor(QPalette::ButtonText,
+ newMI.palette.highlightedText().color());
+ proxy()->drawPrimitive(arrow, &newMI, p, widget);
+ }
+
+ }
+ break;
+#endif // QT_CONFIG(menu)
+#if 0 && QT_CONFIG(menubar)
+ case CE_MenuBarItem:
+ if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ bool active = mbi->state & State_Selected;
+ bool hasFocus = mbi->state & State_HasFocus;
+ bool down = mbi->state & State_Sunken;
+ QStyleOptionMenuItem newMbi = *mbi;
+ p->fillRect(mbi->rect, mbi->palette.brush(QPalette::Button));
+ if (active || hasFocus) {
+ QBrush b = mbi->palette.brush(QPalette::Button);
+ if (active && down)
+ p->setBrushOrigin(p->brushOrigin() + QPoint(1, 1));
+ if (active && hasFocus)
+ qDrawShadeRect(p, mbi->rect.x(), mbi->rect.y(), mbi->rect.width(),
+ mbi->rect.height(), mbi->palette, active && down, 1, 0, &b);
+ if (active && down) {
+ newMbi.rect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, mbi, widget),
+ proxy()->pixelMetric(PM_ButtonShiftVertical, mbi, widget));
+ p->setBrushOrigin(p->brushOrigin() - QPoint(1, 1));
+ }
+ }
+ QCommonStyle::drawControl(ce, &newMbi, p, widget);
+ }
+ break;
+#endif // QT_CONFIG(menubar)
+#if 0 && QT_CONFIG(tabbar)
+ case CE_TabBarTabShape:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
+ bool rtlHorTabs = (tab->direction == Qt::RightToLeft
+ && (tab->shape == QTabBar::RoundedNorth
+ || tab->shape == QTabBar::RoundedSouth));
+ bool selected = tab->state & State_Selected;
+ bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End)
+ || (rtlHorTabs
+ && tab->position == QStyleOptionTab::Beginning));
+ bool firstTab = ((!rtlHorTabs
+ && tab->position == QStyleOptionTab::Beginning)
+ || (rtlHorTabs
+ && tab->position == QStyleOptionTab::End));
+ bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
+ bool previousSelected =
+ ((!rtlHorTabs
+ && tab->selectedPosition == QStyleOptionTab::PreviousIsSelected)
+ || (rtlHorTabs
+ && tab->selectedPosition == QStyleOptionTab::NextIsSelected));
+ bool nextSelected =
+ ((!rtlHorTabs
+ && tab->selectedPosition == QStyleOptionTab::NextIsSelected)
+ || (rtlHorTabs
+ && tab->selectedPosition
+ == QStyleOptionTab::PreviousIsSelected));
+ int tabBarAlignment = proxy()->styleHint(SH_TabBar_Alignment, tab, widget);
+ bool leftAligned = (!rtlHorTabs && tabBarAlignment == Qt::AlignLeft)
+ || (rtlHorTabs
+ && tabBarAlignment == Qt::AlignRight);
+
+ bool rightAligned = (!rtlHorTabs && tabBarAlignment == Qt::AlignRight)
+ || (rtlHorTabs
+ && tabBarAlignment == Qt::AlignLeft);
+
+ QColor light = tab->palette.light().color();
+ QColor dark = tab->palette.dark().color();
+ QColor shadow = tab->palette.shadow().color();
+ int borderThinkness = proxy()->pixelMetric(PM_TabBarBaseOverlap, tab, widget);
+ if (selected)
+ borderThinkness /= 2;
+ QRect r2(opt->rect);
+ int x1 = r2.left();
+ int x2 = r2.right();
+ int y1 = r2.top();
+ int y2 = r2.bottom();
+ switch (tab->shape) {
+ default:
+ QCommonStyle::drawControl(ce, tab, p, widget);
+ break;
+ case QTabBar::RoundedNorth: {
+ if (!selected) {
+ y1 += 2;
+ x1 += onlyOne || firstTab ? borderThinkness : 0;
+ x2 -= onlyOne || lastTab ? borderThinkness : 0;
+ }
+
+ p->fillRect(QRect(x1 + 1, y1 + 1, (x2 - x1) - 1, (y2 - y1) - 2), tab->palette.window());
+
+ // Delete border
+ if (selected) {
+ p->fillRect(QRect(x1,y2-1,x2-x1,1), tab->palette.window());
+ p->fillRect(QRect(x1,y2,x2-x1,1), tab->palette.window());
+ }
+ // Left
+ if (firstTab || selected || onlyOne || !previousSelected) {
+ p->setPen(light);
+ p->drawLine(x1, y1 + 2, x1, y2 - ((onlyOne || firstTab) && selected && leftAligned ? 0 : borderThinkness));
+ p->drawPoint(x1 + 1, y1 + 1);
+ }
+ // Top
+ {
+ int beg = x1 + (previousSelected ? 0 : 2);
+ int end = x2 - (nextSelected ? 0 : 2);
+ p->setPen(light);
+ p->drawLine(beg, y1, end, y1);
+ }
+ // Right
+ if (lastTab || selected || onlyOne || !nextSelected) {
+ p->setPen(shadow);
+ p->drawLine(x2, y1 + 2, x2, y2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness));
+ p->drawPoint(x2 - 1, y1 + 1);
+ p->setPen(dark);
+ p->drawLine(x2 - 1, y1 + 2, x2 - 1, y2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness));
+ }
+ break; }
+ case QTabBar::RoundedSouth: {
+ if (!selected) {
+ y2 -= 2;
+ x1 += firstTab ? borderThinkness : 0;
+ x2 -= lastTab ? borderThinkness : 0;
+ }
+
+ p->fillRect(QRect(x1 + 1, y1 + 2, (x2 - x1) - 1, (y2 - y1) - 1), tab->palette.window());
+
+ // Delete border
+ if (selected) {
+ p->fillRect(QRect(x1, y1 + 1, (x2 - 1)-x1, 1), tab->palette.window());
+ p->fillRect(QRect(x1, y1, (x2 - 1)-x1, 1), tab->palette.window());
+ }
+ // Left
+ if (firstTab || selected || onlyOne || !previousSelected) {
+ p->setPen(light);
+ p->drawLine(x1, y2 - 2, x1, y1 + ((onlyOne || firstTab) && selected && leftAligned ? 0 : borderThinkness));
+ p->drawPoint(x1 + 1, y2 - 1);
+ }
+ // Bottom
+ {
+ int beg = x1 + (previousSelected ? 0 : 2);
+ int end = x2 - (nextSelected ? 0 : 2);
+ p->setPen(shadow);
+ p->drawLine(beg, y2, end, y2);
+ p->setPen(dark);
+ p->drawLine(beg, y2 - 1, end, y2 - 1);
+ }
+ // Right
+ if (lastTab || selected || onlyOne || !nextSelected) {
+ p->setPen(shadow);
+ p->drawLine(x2, y2 - 2, x2, y1 + ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness));
+ p->drawPoint(x2 - 1, y2 - 1);
+ p->setPen(dark);
+ p->drawLine(x2 - 1, y2 - 2, x2 - 1, y1 + ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness));
+ }
+ break; }
+ case QTabBar::RoundedWest: {
+ if (!selected) {
+ x1 += 2;
+ y1 += firstTab ? borderThinkness : 0;
+ y2 -= lastTab ? borderThinkness : 0;
+ }
+
+ p->fillRect(QRect(x1 + 1, y1 + 1, (x2 - x1) - 2, (y2 - y1) - 1), tab->palette.window());
+
+ // Delete border
+ if (selected) {
+ p->fillRect(QRect(x2 - 1, y1, 1, y2-y1), tab->palette.window());
+ p->fillRect(QRect(x2, y1, 1, y2-y1), tab->palette.window());
+ }
+ // Top
+ if (firstTab || selected || onlyOne || !previousSelected) {
+ p->setPen(light);
+ p->drawLine(x1 + 2, y1, x2 - ((onlyOne || firstTab) && selected && leftAligned ? 0 : borderThinkness), y1);
+ p->drawPoint(x1 + 1, y1 + 1);
+ }
+ // Left
+ {
+ int beg = y1 + (previousSelected ? 0 : 2);
+ int end = y2 - (nextSelected ? 0 : 2);
+ p->setPen(light);
+ p->drawLine(x1, beg, x1, end);
+ }
+ // Bottom
+ if (lastTab || selected || onlyOne || !nextSelected) {
+ p->setPen(shadow);
+ p->drawLine(x1 + 3, y2, x2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness), y2);
+ p->drawPoint(x1 + 2, y2 - 1);
+ p->setPen(dark);
+ p->drawLine(x1 + 3, y2 - 1, x2 - ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness), y2 - 1);
+ p->drawPoint(x1 + 1, y2 - 1);
+ p->drawPoint(x1 + 2, y2);
+ }
+ break; }
+ case QTabBar::RoundedEast: {
+ if (!selected) {
+ x2 -= 2;
+ y1 += firstTab ? borderThinkness : 0;
+ y2 -= lastTab ? borderThinkness : 0;
+ }
+
+ p->fillRect(QRect(x1 + 2, y1 + 1, (x2 - x1) - 1, (y2 - y1) - 1), tab->palette.window());
+
+ // Delete border
+ if (selected) {
+ p->fillRect(QRect(x1 + 1, y1, 1, (y2 - 1)-y1),tab->palette.window());
+ p->fillRect(QRect(x1, y1, 1, (y2-1)-y1), tab->palette.window());
+ }
+ // Top
+ if (firstTab || selected || onlyOne || !previousSelected) {
+ p->setPen(light);
+ p->drawLine(x2 - 2, y1, x1 + ((onlyOne || firstTab) && selected && leftAligned ? 0 : borderThinkness), y1);
+ p->drawPoint(x2 - 1, y1 + 1);
+ }
+ // Right
+ {
+ int beg = y1 + (previousSelected ? 0 : 2);
+ int end = y2 - (nextSelected ? 0 : 2);
+ p->setPen(shadow);
+ p->drawLine(x2, beg, x2, end);
+ p->setPen(dark);
+ p->drawLine(x2 - 1, beg, x2 - 1, end);
+ }
+ // Bottom
+ if (lastTab || selected || onlyOne || !nextSelected) {
+ p->setPen(shadow);
+ p->drawLine(x2 - 2, y2, x1 + ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness), y2);
+ p->drawPoint(x2 - 1, y2 - 1);
+ p->setPen(dark);
+ p->drawLine(x2 - 2, y2 - 1, x1 + ((onlyOne || lastTab) && selected && rightAligned ? 0 : borderThinkness), y2 - 1);
+ }
+ break; }
+ }
+ }
+ break;
+#endif // QT_CONFIG(tabbar)
+ case CE_ToolBoxTabShape:
+ qDrawShadePanel(p, opt->rect, opt->palette,
+ opt->state & (State_Sunken | State_On), 1,
+ &opt->palette.brush(QPalette::Button));
+ break;
+#if 0 && QT_CONFIG(splitter)
+ case CE_Splitter:
+ p->eraseRect(opt->rect);
+ break;
+#endif // QT_CONFIG(splitter)
+#if 0 && QT_CONFIG(scrollbar)
+ case CE_ScrollBarSubLine:
+ case CE_ScrollBarAddLine: {
+ if ((opt->state & State_Sunken)) {
+ p->setPen(opt->palette.dark().color());
+ p->setBrush(opt->palette.brush(QPalette::Button));
+ p->drawRect(opt->rect.adjusted(0, 0, -1, -1));
+ } else {
+ QStyleOption buttonOpt = *opt;
+ if (!(buttonOpt.state & State_Sunken))
+ buttonOpt.state |= State_Raised;
+ QPalette pal(opt->palette);
+ pal.setColor(QPalette::Button, opt->palette.light().color());
+ pal.setColor(QPalette::Light, opt->palette.button().color());
+ qDrawWinButton(p, opt->rect, pal, opt->state & (State_Sunken | State_On),
+ &opt->palette.brush(QPalette::Button));
+ }
+ PrimitiveElement arrow;
+ if (opt->state & State_Horizontal) {
+ if (ce == CE_ScrollBarAddLine)
+ arrow = opt->direction == Qt::LeftToRight ? PE_IndicatorArrowRight : PE_IndicatorArrowLeft;
+ else
+ arrow = opt->direction == Qt::LeftToRight ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
+ } else {
+ if (ce == CE_ScrollBarAddLine)
+ arrow = PE_IndicatorArrowDown;
+ else
+ arrow = PE_IndicatorArrowUp;
+ }
+ QStyleOption arrowOpt = *opt;
+ arrowOpt.rect = opt->rect.adjusted(4, 4, -4, -4);
+ proxy()->drawPrimitive(arrow, &arrowOpt, p, widget);
+ break; }
+ case CE_ScrollBarAddPage:
+ case CE_ScrollBarSubPage: {
+ QBrush br;
+ QBrush bg = p->background();
+ Qt::BGMode bg_mode = p->backgroundMode();
+ p->setPen(Qt::NoPen);
+ p->setBackgroundMode(Qt::OpaqueMode);
+
+ if (opt->state & State_Sunken) {
+ br = QBrush(opt->palette.shadow().color(), Qt::Dense4Pattern);
+ p->setBackground(opt->palette.dark().color());
+ p->setBrush(br);
+ } else {
+ const QBrush paletteBrush = opt->palette.brush(QPalette::Light);
+ if (paletteBrush.style() == Qt::TexturePattern) {
+ if (qHasPixmapTexture(paletteBrush))
+ br = QBrush(paletteBrush.texture());
+ else
+ br = QBrush(paletteBrush.textureImage());
+ } else
+ br = QBrush(opt->palette.light().color(), Qt::Dense4Pattern);
+ p->setBackground(opt->palette.window().color());
+ p->setBrush(br);
+ }
+ p->drawRect(opt->rect);
+ p->setBackground(bg);
+ p->setBackgroundMode(bg_mode);
+ break; }
+ case CE_ScrollBarSlider:
+ if (!(opt->state & State_Enabled)) {
+ QBrush br;
+ const QBrush paletteBrush = opt->palette.brush(QPalette::Light);
+ if (paletteBrush.style() == Qt::TexturePattern) {
+ if (qHasPixmapTexture(paletteBrush))
+ br = QBrush(paletteBrush.texture());
+ else
+ br = QBrush(paletteBrush.textureImage());
+ } else
+ br = QBrush(opt->palette.light().color(), Qt::Dense4Pattern);
+ p->setPen(Qt::NoPen);
+ p->setBrush(br);
+ p->setBackgroundMode(Qt::OpaqueMode);
+ p->drawRect(opt->rect);
+ } else {
+ QStyleOptionButton buttonOpt;
+ buttonOpt.QStyleOption::operator=(*opt);
+ buttonOpt.state = State_Enabled | State_Raised;
+
+ QPalette pal(opt->palette);
+ pal.setColor(QPalette::Button, opt->palette.light().color());
+ pal.setColor(QPalette::Light, opt->palette.button().color());
+ qDrawWinButton(p, opt->rect, pal, false, &opt->palette.brush(QPalette::Button));
+ }
+ break;
+#endif // QT_CONFIG(scrollbar)
+ case CE_HeaderSection: {
+ QBrush fill;
+ if (opt->state & State_On)
+ fill = QBrush(opt->palette.light().color(), Qt::Dense4Pattern);
+ else
+ fill = opt->palette.brush(QPalette::Button);
+
+ if (opt->state & (State_Raised | State_Sunken)) {
+ qDrawWinButton(p, opt->rect, opt->palette, opt->state & State_Sunken, &fill);
+ } else {
+ p->fillRect(opt->rect, fill);
+ }
+ break; }
+#if 0 && QT_CONFIG(toolbar)
+ case CE_ToolBar:
+ if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(opt)) {
+ // Reserve the beveled appearance only for mainwindow toolbars
+ if (!(widget && qobject_cast<const QMainWindow*> (widget->parentWidget())))
+ break;
+
+ QRect rect = opt->rect;
+ bool paintLeftBorder = true;
+ bool paintRightBorder = true;
+ bool paintBottomBorder = true;
+
+ switch (toolbar->toolBarArea){
+ case Qt::BottomToolBarArea :
+ switch (toolbar->positionOfLine){
+ case QStyleOptionToolBar::Beginning:
+ case QStyleOptionToolBar::OnlyOne:
+ paintBottomBorder = false;
+ break;
+ default:
+ break;
+ }
+ Q_FALLTHROUGH(); // It continues in the end of the next case
+ case Qt::TopToolBarArea :
+ switch (toolbar->positionWithinLine){
+ case QStyleOptionToolBar::Beginning:
+ paintLeftBorder = false;
+ break;
+ case QStyleOptionToolBar::End:
+ paintRightBorder = false;
+ break;
+ case QStyleOptionToolBar::OnlyOne:
+ paintRightBorder = false;
+ paintLeftBorder = false;
+ break;
+ default:
+ break;
+ }
+ if (opt->direction == Qt::RightToLeft){ //reverse layout changes the order of Beginning/end
+ bool tmp = paintLeftBorder;
+ paintRightBorder=paintLeftBorder;
+ paintLeftBorder=tmp;
+ }
+ break;
+ case Qt::RightToolBarArea :
+ switch (toolbar->positionOfLine){
+ case QStyleOptionToolBar::Beginning:
+ case QStyleOptionToolBar::OnlyOne:
+ paintRightBorder = false;
+ break;
+ default:
+ break;
+ }
+ break;
+ case Qt::LeftToolBarArea :
+ switch (toolbar->positionOfLine){
+ case QStyleOptionToolBar::Beginning:
+ case QStyleOptionToolBar::OnlyOne:
+ paintLeftBorder = false;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+
+ //draw top border
+ p->setPen(QPen(opt->palette.light().color()));
+ p->drawLine(rect.topLeft().x(),
+ rect.topLeft().y(),
+ rect.topRight().x(),
+ rect.topRight().y());
+
+ if (paintLeftBorder){
+ p->setPen(QPen(opt->palette.light().color()));
+ p->drawLine(rect.topLeft().x(),
+ rect.topLeft().y(),
+ rect.bottomLeft().x(),
+ rect.bottomLeft().y());
+ }
+
+ if (paintRightBorder){
+ p->setPen(QPen(opt->palette.dark().color()));
+ p->drawLine(rect.topRight().x(),
+ rect.topRight().y(),
+ rect.bottomRight().x(),
+ rect.bottomRight().y());
+ }
+
+ if (paintBottomBorder){
+ p->setPen(QPen(opt->palette.dark().color()));
+ p->drawLine(rect.bottomLeft().x(),
+ rect.bottomLeft().y(),
+ rect.bottomRight().x(),
+ rect.bottomRight().y());
+ }
+ }
+ break;
+
+
+#endif // QT_CONFIG(toolbar)
+
+ case CE_ProgressBarContents:
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(opt)) {
+ QRect rect = pb->rect;
+ if (!rect.isValid())
+ return;
+
+ const bool vertical = !(pb->state & QStyle::State_Horizontal);
+ const bool inverted = pb->invertedAppearance;
+
+ QTransform m;
+ if (vertical) {
+ rect = QRect(rect.y(), rect.x(), rect.height(), rect.width()); // flip width and height
+ m.rotate(90);
+ m.translate(0, -(rect.height() + rect.y()*2));
+ }
+ QPalette pal2 = pb->palette;
+ // Correct the highlight color if it is the same as the background
+ if (pal2.highlight() == pal2.window())
+ pal2.setColor(QPalette::Highlight, pb->palette.color(QPalette::Active,
+ QPalette::Highlight));
+ bool reverse = ((!vertical && (pb->direction == Qt::RightToLeft)) || vertical);
+ if (inverted)
+ reverse = !reverse;
+ int w = rect.width();
+ Q_D(const QWindowsStyle);
+ if (pb->minimum == 0 && pb->maximum == 0) {
+ const int unit_width = proxy()->pixelMetric(PM_ProgressBarChunkWidth, pb);
+ QStyleOptionProgressBar pbBits = *pb;
+ Q_ASSERT(unit_width >0);
+
+ pbBits.rect = rect;
+ pbBits.palette = pal2;
+
+ int step = 0;
+ int chunkCount = w / unit_width + 1;
+#if 0 && QT_CONFIG(animation)
+ if (QProgressStyleAnimation *animation = qobject_cast<QProgressStyleAnimation*>(d->animation(opt->styleObject)))
+ step = (animation->animationStep() / 3) % chunkCount;
+ else
+ d->startAnimation(new QProgressStyleAnimation(d->animationFps, opt->styleObject));
+#else
+ Q_UNUSED(d);
+#endif
+ int chunksInRow = 5;
+ int myY = pbBits.rect.y();
+ int myHeight = pbBits.rect.height();
+ int chunksToDraw = chunksInRow;
+
+ if (step > chunkCount - 5)chunksToDraw = (chunkCount - step);
+ p->save();
+ p->setClipRect(m.mapRect(QRectF(rect)).toRect());
+
+ int x0 = reverse ? rect.left() + rect.width() - unit_width*(step) - unit_width : rect.left() + unit_width * step;
+ int x = 0;
+
+ for (int i = 0; i < chunksToDraw ; ++i) {
+ pbBits.rect.setRect(x0 + x, myY, unit_width, myHeight);
+ pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
+ proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p);
+ x += reverse ? -unit_width : unit_width;
+ }
+ //Draw wrap-around chunks
+ if ( step > chunkCount-5){
+ x0 = reverse ? rect.left() + rect.width() - unit_width : rect.left() ;
+ x = 0;
+ int chunksToDraw = step - (chunkCount - chunksInRow);
+ for (int i = 0; i < chunksToDraw ; ++i) {
+ pbBits.rect.setRect(x0 + x, myY, unit_width, myHeight);
+ pbBits.rect = m.mapRect(QRectF(pbBits.rect)).toRect();
+ proxy()->drawPrimitive(PE_IndicatorProgressChunk, &pbBits, p);
+ x += reverse ? -unit_width : unit_width;
+ }
+ }
+ p->restore(); //restore state
+ }
+ else {
+#if 0 && QT_CONFIG(animation)
+ d->stopAnimation(opt->styleObject);
+#endif
+ QCommonStyle::drawControl(ce, opt, p);
+ }
+ }
+ break;
+
+#if 0 && QT_CONFIG(dockwidget)
+ case CE_DockWidgetTitle:
+
+ if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(opt)) {
+ Q_D(const QWindowsStyle);
+
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ QRect rect = dwOpt->rect;
+ QRect r = rect;
+
+ if (verticalTitleBar) {
+ r = r.transposed();
+
+ p->save();
+ p->translate(r.left(), r.top() + r.width());
+ p->rotate(-90);
+ p->translate(-r.left(), -r.top());
+ }
+
+ bool floating = false;
+ bool active = dwOpt->state & State_Active;
+ QColor inactiveCaptionTextColor = d->inactiveCaptionText;
+ if (dwOpt->movable) {
+ QColor left, right;
+
+ //Titlebar gradient
+ if (opt->state & QStyle::State_Window) {
+ floating = true;
+ if (active) {
+ left = d->activeCaptionColor;
+ right = d->activeGradientCaptionColor;
+ } else {
+ left = d->inactiveCaptionColor;
+ right = d->inactiveGradientCaptionColor;
+ }
+ QBrush fillBrush(left);
+ if (left != right) {
+ QPoint p1(r.x(), r.top() + r.height()/2);
+ QPoint p2(rect.right(), r.top() + r.height()/2);
+ QLinearGradient lg(p1, p2);
+ lg.setColorAt(0, left);
+ lg.setColorAt(1, right);
+ fillBrush = lg;
+ }
+ p->fillRect(r.adjusted(0, 0, 0, -3), fillBrush);
+ }
+ }
+ if (!dwOpt->title.isEmpty()) {
+ QFont oldFont = p->font();
+ if (floating) {
+ QFont font = oldFont;
+ font.setBold(true);
+ p->setFont(font);
+ }
+ QPalette palette = dwOpt->palette;
+ palette.setColor(QPalette::Window, inactiveCaptionTextColor);
+ QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, opt, widget);
+ if (verticalTitleBar) {
+ titleRect = QRect(r.left() + rect.bottom()
+ - titleRect.bottom(),
+ r.top() + titleRect.left() - rect.left(),
+ titleRect.height(), titleRect.width());
+ }
+ proxy()->drawItemText(p, titleRect,
+ Qt::AlignLeft | Qt::AlignVCenter, palette,
+ dwOpt->state & State_Enabled, dwOpt->title,
+ floating ? (active ? QPalette::BrightText : QPalette::Window) : QPalette::WindowText);
+ p->setFont(oldFont);
+ }
+ if (verticalTitleBar)
+ p->restore();
+ }
+ return;
+#endif // QT_CONFIG(dockwidget)
+#if 0 && QT_CONFIG(combobox)
+ case CE_ComboBoxLabel:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ if (cb->state & State_HasFocus) {
+ p->setPen(cb->palette.highlightedText().color());
+ p->setBackground(cb->palette.highlight());
+ } else {
+ p->setPen(cb->palette.text().color());
+ p->setBackground(cb->palette.window());
+ }
+ }
+ QCommonStyle::drawControl(ce, opt, p, widget);
+ break;
+#endif // QT_CONFIG(combobox)
+ default:
+ QCommonStyle::drawControl(ce, opt, p);
+ }
+}
+
+/*! \reimp */
+QRect QWindowsStyle::subElementRect(SubElement sr, const QStyleOption *opt) const
+{
+ QRect r;
+ switch (sr) {
+ case SE_SliderFocusRect:
+ case SE_ToolBoxTabContents:
+ r = visualRect(opt->direction, opt->rect, opt->rect);
+ break;
+ case SE_DockWidgetTitleBarText: {
+ r = QCommonStyle::subElementRect(sr, opt);
+ const QStyleOptionDockWidget *dwOpt
+ = qstyleoption_cast<const QStyleOptionDockWidget*>(opt);
+ const bool verticalTitleBar = dwOpt && dwOpt->verticalTitleBar;
+ int m = proxy()->pixelMetric(PM_DockWidgetTitleMargin, opt);
+ if (verticalTitleBar) {
+ r.adjust(0, 0, 0, -m);
+ } else {
+ if (opt->direction == Qt::LeftToRight)
+ r.adjust(m, 0, 0, 0);
+ else
+ r.adjust(0, 0, -m, 0);
+ }
+ break;
+ }
+ case SE_ProgressBarContents:
+ r = QCommonStyle::subElementRect(SE_ProgressBarGroove, opt);
+ r.adjust(3, 3, -3, -3);
+ break;
+ default:
+ r = QCommonStyle::subElementRect(sr, opt);
+ }
+ return r;
+}
+
+
+/*! \reimp */
+void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt,
+ QPainter *p) const
+{
+#if 0
+ switch (cc) {
+#if QT_CONFIG(slider)
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider);
+ int ticks = slider->tickPosition;
+ QRect groove = proxy()->subControlRect(CC_Slider, slider, SC_SliderGroove);
+ QRect handle = proxy()->subControlRect(CC_Slider, slider, SC_SliderHandle);
+
+ if ((slider->subControls & SC_SliderGroove) && groove.isValid()) {
+ int mid = thickness / 2;
+
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ mid += len / 8;
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ mid -= len / 8;
+
+ p->setPen(slider->palette.shadow().color());
+ if (slider->orientation == Qt::Horizontal) {
+ qDrawWinPanel(p, groove.x(), groove.y() + mid - 2,
+ groove.width(), 4, slider->palette, true);
+ p->drawLine(groove.x() + 1, groove.y() + mid - 1,
+ groove.x() + groove.width() - 3, groove.y() + mid - 1);
+ } else {
+ qDrawWinPanel(p, groove.x() + mid - 2, groove.y(),
+ 4, groove.height(), slider->palette, true);
+ p->drawLine(groove.x() + mid - 1, groove.y() + 1,
+ groove.x() + mid - 1, groove.y() + groove.height() - 3);
+ }
+ }
+
+ if (slider->subControls & SC_SliderTickmarks) {
+ QStyleOptionSlider tmpSlider = *slider;
+ tmpSlider.subControls = SC_SliderTickmarks;
+ QCommonStyle::drawComplexControl(cc, &tmpSlider, p);
+ }
+
+ if (slider->subControls & SC_SliderHandle) {
+ // 4444440
+ // 4333310
+ // 4322210
+ // 4322210
+ // 4322210
+ // 4322210
+ // *43210*
+ // **410**
+ // ***0***
+ const QColor c0 = slider->palette.shadow().color();
+ const QColor c1 = slider->palette.dark().color();
+ // const QColor c2 = g.button();
+ const QColor c3 = slider->palette.midlight().color();
+ const QColor c4 = slider->palette.light().color();
+ QBrush handleBrush;
+
+ if (slider->state & State_Enabled) {
+ handleBrush = slider->palette.color(QPalette::Button);
+ } else {
+ handleBrush = QBrush(slider->palette.color(QPalette::Button),
+ Qt::Dense4Pattern);
+ }
+
+
+ int x = handle.x(), y = handle.y(),
+ wi = handle.width(), he = handle.height();
+
+ int x1 = x;
+ int x2 = x+wi-1;
+ int y1 = y;
+ int y2 = y+he-1;
+
+ Qt::Orientation orient = slider->orientation;
+ bool tickAbove = slider->tickPosition == QStyleOptionSlider::TicksAbove;
+ bool tickBelow = slider->tickPosition == QStyleOptionSlider::TicksBelow;
+
+ if (slider->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*slider);
+ fropt.rect = subElementRect(SE_SliderFocusRect, slider);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+
+ if ((tickAbove && tickBelow) || (!tickAbove && !tickBelow)) {
+ Qt::BGMode oldMode = p->backgroundMode();
+ p->setBackgroundMode(Qt::OpaqueMode);
+ qDrawWinButton(p, QRect(x, y, wi, he), slider->palette, false,
+ &handleBrush);
+ p->setBackgroundMode(oldMode);
+ return;
+ }
+
+ QSliderDirection dir;
+
+ if (orient == Qt::Horizontal)
+ if (tickAbove)
+ dir = SlUp;
+ else
+ dir = SlDown;
+ else
+ if (tickAbove)
+ dir = SlLeft;
+ else
+ dir = SlRight;
+
+ QPolygon a;
+
+ int d = 0;
+ switch (dir) {
+ case SlUp:
+ y1 = y1 + wi/2;
+ d = (wi + 1) / 2 - 1;
+ a.setPoints(5, x1,y1, x1,y2, x2,y2, x2,y1, x1+d,y1-d);
+ break;
+ case SlDown:
+ y2 = y2 - wi/2;
+ d = (wi + 1) / 2 - 1;
+ a.setPoints(5, x1,y1, x1,y2, x1+d,y2+d, x2,y2, x2,y1);
+ break;
+ case SlLeft:
+ d = (he + 1) / 2 - 1;
+ x1 = x1 + he/2;
+ a.setPoints(5, x1,y1, x1-d,y1+d, x1,y2, x2,y2, x2,y1);
+ break;
+ case SlRight:
+ d = (he + 1) / 2 - 1;
+ x2 = x2 - he/2;
+ a.setPoints(5, x1,y1, x1,y2, x2,y2, x2+d,y1+d, x2,y1);
+ break;
+ }
+
+ QBrush oldBrush = p->brush();
+ p->setPen(Qt::NoPen);
+ p->setBrush(handleBrush);
+ Qt::BGMode oldMode = p->backgroundMode();
+ p->setBackgroundMode(Qt::OpaqueMode);
+ p->drawRect(x1, y1, x2-x1+1, y2-y1+1);
+ p->drawPolygon(a);
+ p->setBrush(oldBrush);
+ p->setBackgroundMode(oldMode);
+
+ if (dir != SlUp) {
+ p->setPen(c4);
+ p->drawLine(x1, y1, x2, y1);
+ p->setPen(c3);
+ p->drawLine(x1, y1+1, x2, y1+1);
+ }
+ if (dir != SlLeft) {
+ p->setPen(c3);
+ p->drawLine(x1+1, y1+1, x1+1, y2);
+ p->setPen(c4);
+ p->drawLine(x1, y1, x1, y2);
+ }
+ if (dir != SlRight) {
+ p->setPen(c0);
+ p->drawLine(x2, y1, x2, y2);
+ p->setPen(c1);
+ p->drawLine(x2-1, y1+1, x2-1, y2-1);
+ }
+ if (dir != SlDown) {
+ p->setPen(c0);
+ p->drawLine(x1, y2, x2, y2);
+ p->setPen(c1);
+ p->drawLine(x1+1, y2-1, x2-1, y2-1);
+ }
+
+ switch (dir) {
+ case SlUp:
+ p->setPen(c4);
+ p->drawLine(x1, y1, x1+d, y1-d);
+ p->setPen(c0);
+ d = wi - d - 1;
+ p->drawLine(x2, y1, x2-d, y1-d);
+ d--;
+ p->setPen(c3);
+ p->drawLine(x1+1, y1, x1+1+d, y1-d);
+ p->setPen(c1);
+ p->drawLine(x2-1, y1, x2-1-d, y1-d);
+ break;
+ case SlDown:
+ p->setPen(c4);
+ p->drawLine(x1, y2, x1+d, y2+d);
+ p->setPen(c0);
+ d = wi - d - 1;
+ p->drawLine(x2, y2, x2-d, y2+d);
+ d--;
+ p->setPen(c3);
+ p->drawLine(x1+1, y2, x1+1+d, y2+d);
+ p->setPen(c1);
+ p->drawLine(x2-1, y2, x2-1-d, y2+d);
+ break;
+ case SlLeft:
+ p->setPen(c4);
+ p->drawLine(x1, y1, x1-d, y1+d);
+ p->setPen(c0);
+ d = he - d - 1;
+ p->drawLine(x1, y2, x1-d, y2-d);
+ d--;
+ p->setPen(c3);
+ p->drawLine(x1, y1+1, x1-d, y1+1+d);
+ p->setPen(c1);
+ p->drawLine(x1, y2-1, x1-d, y2-1-d);
+ break;
+ case SlRight:
+ p->setPen(c4);
+ p->drawLine(x2, y1, x2+d, y1+d);
+ p->setPen(c0);
+ d = he - d - 1;
+ p->drawLine(x2, y2, x2+d, y2-d);
+ d--;
+ p->setPen(c3);
+ p->drawLine(x2, y1+1, x2+d, y1+1+d);
+ p->setPen(c1);
+ p->drawLine(x2, y2-1, x2+d, y2-1-d);
+ break;
+ }
+ }
+ }
+ break;
+#endif // QT_CONFIG(slider)
+#if QT_CONFIG(scrollbar)
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ QStyleOptionSlider newScrollbar = *scrollbar;
+ if (scrollbar->minimum == scrollbar->maximum)
+ newScrollbar.state &= ~State_Enabled; //do not draw the slider.
+ QCommonStyle::drawComplexControl(cc, &newScrollbar, p, widget);
+ }
+ break;
+#endif // QT_CONFIG(scrollbar)
+#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(opt)) {
+ QBrush editBrush = cmb->palette.brush(QPalette::Button);
+ if ((cmb->subControls & SC_ComboBoxFrame)) {
+ if (cmb->frame) {
+ QPalette shadePal = opt->palette;
+ shadePal.setColor(QPalette::Midlight, shadePal.button().color());
+ qDrawWinPanel(p, opt->rect, shadePal, true, &editBrush);
+ }
+ else {
+ p->fillRect(opt->rect, editBrush);
+ }
+ }
+ if (cmb->subControls & SC_ComboBoxArrow) {
+ State flags = State_None;
+
+ QRect ar = proxy()->subControlRect(CC_ComboBox, cmb, SC_ComboBoxArrow, widget);
+ bool sunkenArrow = cmb->activeSubControls == SC_ComboBoxArrow
+ && cmb->state & State_Sunken;
+ if (sunkenArrow) {
+ p->setPen(cmb->palette.dark().color());
+ p->setBrush(cmb->palette.brush(QPalette::Button));
+ p->drawRect(ar.adjusted(0,0,-1,-1));
+ } else {
+ // Make qDrawWinButton use the right colors for drawing the shade of the button
+ QPalette pal(cmb->palette);
+ pal.setColor(QPalette::Button, cmb->palette.light().color());
+ pal.setColor(QPalette::Light, cmb->palette.button().color());
+ qDrawWinButton(p, ar, pal, false,
+ &cmb->palette.brush(QPalette::Button));
+ }
+
+ ar.adjust(2, 2, -2, -2);
+ if (opt->state & State_Enabled)
+ flags |= State_Enabled;
+ if (opt->state & State_HasFocus)
+ flags |= State_HasFocus;
+
+ if (sunkenArrow)
+ flags |= State_Sunken;
+ QStyleOption arrowOpt = *cmb;
+ arrowOpt.rect = ar.adjusted(1, 1, -1, -1);
+ arrowOpt.state = flags;
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget);
+ }
+
+ if (cmb->subControls & SC_ComboBoxEditField) {
+ QRect re = proxy()->subControlRect(CC_ComboBox, cmb, SC_ComboBoxEditField, widget);
+ if (cmb->state & State_HasFocus && !cmb->editable)
+ p->fillRect(re.x(), re.y(), re.width(), re.height(),
+ cmb->palette.brush(QPalette::Highlight));
+
+ if (cmb->state & State_HasFocus) {
+ p->setPen(cmb->palette.highlightedText().color());
+ p->setBackground(cmb->palette.highlight());
+
+ } else {
+ p->setPen(cmb->palette.text().color());
+ p->setBackground(cmb->palette.window());
+ }
+
+ if (cmb->state & State_HasFocus && !cmb->editable) {
+ QStyleOptionFocusRect focus;
+ focus.QStyleOption::operator=(*cmb);
+ focus.rect = subElementRect(SE_ComboBoxFocusRect, cmb, widget);
+ focus.state |= State_FocusAtBorder;
+ focus.backgroundColor = cmb->palette.highlight().color();
+ proxy()->drawPrimitive(PE_FrameFocusRect, &focus, p, widget);
+ }
+ }
+ }
+ break;
+#endif // QT_CONFIG(combobox)
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(opt)) {
+ QStyleOptionSpinBox copy = *sb;
+ PrimitiveElement pe;
+ bool enabled = opt->state & State_Enabled;
+ if (sb->frame && (sb->subControls & SC_SpinBoxFrame)) {
+ QBrush editBrush = sb->palette.brush(QPalette::Base);
+ QRect r = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxFrame, widget);
+ QPalette shadePal = sb->palette;
+ shadePal.setColor(QPalette::Midlight, shadePal.button().color());
+ qDrawWinPanel(p, r, shadePal, true, &editBrush);
+ }
+
+ QPalette shadePal(opt->palette);
+ shadePal.setColor(QPalette::Button, opt->palette.light().color());
+ shadePal.setColor(QPalette::Light, opt->palette.button().color());
+
+ if (sb->subControls & SC_SpinBoxUp) {
+ copy.subControls = SC_SpinBoxUp;
+ QPalette pal2 = sb->palette;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled)) {
+ pal2.setCurrentColorGroup(QPalette::Disabled);
+ copy.state &= ~State_Enabled;
+ }
+
+ copy.palette = pal2;
+
+ if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken)) {
+ copy.state |= State_On;
+ copy.state |= State_Sunken;
+ } else {
+ copy.state |= State_Raised;
+ copy.state &= ~State_Sunken;
+ }
+ pe = (sb->buttonSymbols == QAbstractSpinBox::PlusMinus ? PE_IndicatorSpinPlus
+ : PE_IndicatorSpinUp);
+
+ copy.rect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxUp, widget);
+ qDrawWinButton(p, copy.rect, shadePal, copy.state & (State_Sunken | State_On),
+ &copy.palette.brush(QPalette::Button));
+ copy.rect.adjust(4, 1, -5, -1);
+ if ((!enabled || !(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled))
+ && proxy()->styleHint(SH_EtchDisabledText, opt, widget) )
+ {
+ QStyleOptionSpinBox lightCopy = copy;
+ lightCopy.rect.adjust(1, 1, 1, 1);
+ lightCopy.palette.setBrush(QPalette::ButtonText, copy.palette.light());
+ proxy()->drawPrimitive(pe, &lightCopy, p, widget);
+ }
+ proxy()->drawPrimitive(pe, &copy, p, widget);
+ }
+
+ if (sb->subControls & SC_SpinBoxDown) {
+ copy.subControls = SC_SpinBoxDown;
+ copy.state = sb->state;
+ QPalette pal2 = sb->palette;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled)) {
+ pal2.setCurrentColorGroup(QPalette::Disabled);
+ copy.state &= ~State_Enabled;
+ }
+ copy.palette = pal2;
+
+ if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken)) {
+ copy.state |= State_On;
+ copy.state |= State_Sunken;
+ } else {
+ copy.state |= State_Raised;
+ copy.state &= ~State_Sunken;
+ }
+ pe = (sb->buttonSymbols == QAbstractSpinBox::PlusMinus ? PE_IndicatorSpinMinus
+ : PE_IndicatorSpinDown);
+
+ copy.rect = proxy()->subControlRect(CC_SpinBox, sb, SC_SpinBoxDown, widget);
+ qDrawWinButton(p, copy.rect, shadePal, copy.state & (State_Sunken | State_On),
+ &copy.palette.brush(QPalette::Button));
+ copy.rect.adjust(4, 0, -5, -1);
+ if ((!enabled || !(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled))
+ && proxy()->styleHint(SH_EtchDisabledText, opt, widget) )
+ {
+ QStyleOptionSpinBox lightCopy = copy;
+ lightCopy.rect.adjust(1, 1, 1, 1);
+ lightCopy.palette.setBrush(QPalette::ButtonText, copy.palette.light());
+ proxy()->drawPrimitive(pe, &lightCopy, p, widget);
+ }
+ proxy()->drawPrimitive(pe, &copy, p, widget);
+ }
+ }
+ break;
+#endif // QT_CONFIG(spinbox)
+ default:
+ QCommonStyle::drawComplexControl(cc, opt, p);
+ }
+#else // 0
+ QCommonStyle::drawComplexControl(cc, opt, p);
+#endif
+}
+
+/*! \reimp */
+QSize QWindowsStyle::sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &csz) const
+{
+ QSize sz(csz);
+ switch (ct) {
+ case CT_PushButton:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz);
+ int w = sz.width(),
+ h = sz.height();
+ int defwidth = 0;
+ if (btn->features & QStyleOptionButton::AutoDefaultButton)
+ defwidth = 2 * proxy()->pixelMetric(PM_ButtonDefaultIndicator, btn);
+ const qreal dpi = QStyleHelper::dpi(opt);
+ int minwidth = int(QStyleHelper::dpiScaled(75, dpi));
+ int minheight = int(QStyleHelper::dpiScaled(23, dpi));
+
+#ifndef QT_QWS_SMALL_PUSHBUTTON
+ if (w < minwidth + defwidth && !btn->text.isEmpty())
+ w = minwidth + defwidth;
+ if (h < minheight + defwidth)
+ h = minheight + defwidth;
+#endif
+ sz = QSize(w, h);
+ }
+ break;
+#if 0 && QT_CONFIG(menu)
+ case CT_MenuItem:
+ if (const QStyleOptionMenuItem *mi = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) {
+ int w = sz.width();
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget);
+
+ if (mi->menuItemType == QStyleOptionMenuItem::Separator) {
+ sz = QSize(10, QWindowsStylePrivate::windowsSepHeight);
+ }
+ else if (mi->icon.isNull()) {
+ sz.setHeight(sz.height() - 2);
+ w -= 6;
+ }
+
+ if (mi->menuItemType != QStyleOptionMenuItem::Separator && !mi->icon.isNull()) {
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, opt, widget);
+ sz.setHeight(qMax(sz.height(),
+ mi->icon.actualSize(QSize(iconExtent, iconExtent)).height()
+ + 2 * QWindowsStylePrivate::windowsItemFrame));
+ }
+ int maxpmw = mi->maxIconWidth;
+ int tabSpacing = 20;
+ if (mi->text.contains(QLatin1Char('\t')))
+ w += tabSpacing;
+ else if (mi->menuItemType == QStyleOptionMenuItem::SubMenu)
+ w += 2 * QWindowsStylePrivate::windowsArrowHMargin;
+ else if (mi->menuItemType == QStyleOptionMenuItem::DefaultItem) {
+ // adjust the font and add the difference in size.
+ // it would be better if the font could be adjusted in the initStyleOption qmenu func!!
+ QFontMetrics fm(mi->font);
+ QFont fontBold = mi->font;
+ fontBold.setBold(true);
+ QFontMetrics fmBold(fontBold);
+ w += fmBold.horizontalAdvance(mi->text) - fm.horizontalAdvance(mi->text);
+ }
+
+ int checkcol = qMax<int>(maxpmw, QWindowsStylePrivate::windowsCheckMarkWidth); // Windows always shows a check column
+ w += checkcol;
+ w += int(QWindowsStylePrivate::windowsRightBorder) + 10;
+ sz.setWidth(w);
+ }
+ break;
+#endif // QT_CONFIG(menu)
+#if 0 && QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!sz.isEmpty())
+ sz += QSize(QWindowsStylePrivate::windowsItemHMargin * 4, QWindowsStylePrivate::windowsItemVMargin * 2);
+ break;
+#endif
+ case CT_ToolButton:
+ if (qstyleoption_cast<const QStyleOptionToolButton *>(opt))
+ return sz += QSize(7, 6);
+ Q_FALLTHROUGH();
+
+ default:
+ sz = QCommonStyle::sizeFromContents(ct, opt, csz);
+ }
+ return sz;
+}
+
+/*!
+ \reimp
+*/
+QIcon QWindowsStyle::standardIcon(StandardPixmap standardIcon, const QStyleOption *option) const
+{
+ return QCommonStyle::standardIcon(standardIcon, option);
+}
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#include "moc_qquickwindowsstyle_p.cpp"
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p.h
new file mode 100644
index 0000000000..92926b7129
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOWSSTYLE_P_H
+#define QQUICKWINDOWSSTYLE_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 "qquickcommonstyle.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPalette;
+
+namespace QQC2 {
+
+class QStyleOptionButton;
+class QWindowsStylePrivate;
+
+class QWindowsStylePrivate;
+
+class QWindowsStyle : public QCommonStyle
+{
+ Q_OBJECT
+public:
+ QWindowsStyle();
+ ~QWindowsStyle() override;
+/*
+ void polish(QApplication*) override;
+ void unpolish(QApplication*) override;
+
+ void polish(QWidget*) override;
+ void unpolish(QWidget*) override;
+
+ void polish(QPalette &) override;
+*/
+ void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, QPainter *p) const override;
+ void drawControl(ControlElement element, const QStyleOption *opt, QPainter *p) const override;
+ void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p) const override;
+
+ QRect subElementRect(SubElement r, const QStyleOption *opt) const override;
+ QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize) const override;
+
+ int pixelMetric(PixelMetric pm, const QStyleOption *option = nullptr) const override;
+
+ int styleHint(StyleHint hint, const QStyleOption *opt = nullptr,
+ QStyleHintReturn *returnData = nullptr) const override;
+
+ QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt) const override;
+
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr) const override;
+
+protected:
+// bool eventFilter(QObject *o, QEvent *e) override;
+ QWindowsStyle(QWindowsStylePrivate &dd);
+
+private:
+ Q_DISABLE_COPY_MOVE(QWindowsStyle)
+ Q_DECLARE_PRIVATE(QWindowsStyle)
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QQUICKWINDOWSSTYLE_P_H
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p_p.h
new file mode 100644
index 0000000000..64b95a4016
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsstyle_p_p.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOWSSTYLE_P_P_H
+#define QQUICKWINDOWSSTYLE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of XX. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qquickwindowsstyle_p.h"
+#include "qquickcommonstyle_p.h"
+#include "qquickstylehelper_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+class QStyleOptionButton;
+class QWindowsStylePrivate;
+
+#include <qlist.h>
+
+class QTime;
+
+class QWindowsStylePrivate : public QCommonStylePrivate
+{
+ Q_DECLARE_PUBLIC(QWindowsStyle)
+public:
+ enum { InvalidMetric = -23576 };
+
+ QWindowsStylePrivate();
+ static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr);
+ static int fixedPixelMetric(QStyle::PixelMetric pm);
+ static qreal devicePixelRatio(const QStyleOption *option = nullptr)
+ {
+ return devicePixelRatio(option ? option->window : nullptr);
+ }
+
+ static qreal devicePixelRatio(const QWindow *win)
+ { return win ? win->devicePixelRatio() : QWindowsStylePrivate::appDevicePixelRatio(); }
+ static qreal nativeMetricScaleFactor(const QStyleOption *option = nullptr);
+ static qreal nativeMetricScaleFactor(const QWindow *win);
+ static bool isDarkMode();
+
+#if 0
+ bool hasSeenAlt(const QWidget *widget) const;
+ bool altDown() const { return alt_down; }
+ bool alt_down = false;
+#endif
+ QList<const QWidget *> seenAlt;
+ int menuBarTimer = 0;
+
+ QColor inactiveCaptionText;
+ QColor activeCaptionColor;
+ QColor activeGradientCaptionColor;
+ QColor inactiveCaptionColor;
+ QColor inactiveGradientCaptionColor;
+
+ enum {
+ windowsItemFrame = 2, // menu item frame width
+ windowsSepHeight = 9, // separator item height
+ windowsItemHMargin = 3, // menu item hor text margin
+ windowsItemVMargin = 2, // menu item ver text margin
+ windowsArrowHMargin = 6, // arrow horizontal margin
+ windowsRightBorder = 15, // right border on windows
+ windowsCheckMarkWidth = 12 // checkmarks width on windows
+ };
+
+private:
+ static qreal appDevicePixelRatio();
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif //QQUICKWINDOWSSTYLE_P_P_H
+
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle.cpp b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle.cpp
new file mode 100644
index 0000000000..c815b23f04
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle.cpp
@@ -0,0 +1,2494 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickwindowsvistastyle_p.h"
+#include "qquickwindowsvistastyle_p_p.h"
+#include <qoperatingsystemversion.h>
+#include <qscreen.h>
+#include <qwindow.h>
+#include <private/qstyleanimation_p.h>
+#include <private/qstylehelper_p.h>
+#include <qpa/qplatformnativeinterface.h>
+
+QT_BEGIN_NAMESPACE
+
+static const int windowsItemFrame = 2; // menu item frame width
+static const int windowsItemHMargin = 3; // menu item hor text margin
+static const int windowsItemVMargin = 4; // menu item ver text margin
+static const int windowsArrowHMargin = 6; // arrow horizontal margin
+static const int windowsRightBorder = 15; // right border on windows
+
+#ifndef TMT_CONTENTMARGINS
+# define TMT_CONTENTMARGINS 3602
+#endif
+#ifndef TMT_SIZINGMARGINS
+# define TMT_SIZINGMARGINS 3601
+#endif
+#ifndef LISS_NORMAL
+# define LISS_NORMAL 1
+# define LISS_HOT 2
+# define LISS_SELECTED 3
+# define LISS_DISABLED 4
+# define LISS_SELECTEDNOTFOCUS 5
+# define LISS_HOTSELECTED 6
+#endif
+#ifndef BP_COMMANDLINK
+# define BP_COMMANDLINK 6
+# define BP_COMMANDLINKGLYPH 7
+# define CMDLGS_NORMAL 1
+# define CMDLGS_HOT 2
+# define CMDLGS_PRESSED 3
+# define CMDLGS_DISABLED 4
+#endif
+
+/* \internal
+ Checks if we should use Vista style , or if we should
+ fall back to Windows style.
+*/
+bool QWindowsVistaStylePrivate::useVista()
+{
+ return QWindowsVistaStylePrivate::useXP();
+}
+
+/* \internal
+ Checks and returns the style object
+*/
+inline QObject *styleObject(const QStyleOption *option) {
+ return option ? option->styleObject : nullptr;
+}
+
+/* \internal
+ Checks if we can animate on a style option
+*/
+bool canAnimate(const QStyleOption *option) {
+ return option
+ && option->styleObject
+ && !option->styleObject->property("_q_no_animation").toBool();
+}
+
+static inline QImage createAnimationBuffer(const QStyleOption *option, const QWidget *widget)
+{
+ const int devicePixelRatio = widget ? widget->devicePixelRatio() : 1;
+ QImage result(option->rect.size() * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
+ result.setDevicePixelRatio(devicePixelRatio);
+ result.fill(0);
+ return result;
+}
+
+/* \internal
+ Used by animations to clone a styleoption and shift its offset
+*/
+QStyleOption *clonedAnimationStyleOption(const QStyleOption*option) {
+ QStyleOption *styleOption = nullptr;
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
+ styleOption = new QStyleOptionSlider(*slider);
+ else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
+ styleOption = new QStyleOptionSpinBox(*spinbox);
+ else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
+ styleOption = new QStyleOptionGroupBox(*groupBox);
+ else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
+ styleOption = new QStyleOptionComboBox(*combo);
+ else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
+ styleOption = new QStyleOptionButton(*button);
+ else
+ styleOption = new QStyleOption(*option);
+ styleOption->rect = QRect(QPoint(0,0), option->rect.size());
+ return styleOption;
+}
+
+/* \internal
+ Used by animations to delete cloned styleoption
+*/
+void deleteClonedAnimationStyleOption(const QStyleOption *option)
+{
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider*>(option))
+ delete slider;
+ else if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox*>(option))
+ delete spinbox;
+ else if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox*>(option))
+ delete groupBox;
+ else if (const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox*>(option))
+ delete combo;
+ else if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton*>(option))
+ delete button;
+ else
+ delete option;
+}
+
+/*!
+ \class QWindowsVistaStyle
+ \brief The QWindowsVistaStyle class provides a look and feel suitable for applications on Microsoft Windows Vista.
+ \since 4.3
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ \warning This style is only available on the Windows Vista platform
+ because it makes use of Windows Vista's style engine.
+
+ \sa QMacStyle, QWindowsXPStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindowsVistaStyle object.
+*/
+QWindowsVistaStyle::QWindowsVistaStyle()
+ : QWindowsXPStyle(*new QWindowsVistaStylePrivate)
+{
+}
+
+/*!
+ Destructor.
+*/
+QWindowsVistaStyle::~QWindowsVistaStyle() = default;
+
+//convert Qt state flags to uxtheme button states
+static int buttonStateId(int flags, int partId)
+{
+ int stateId = 0;
+ if (partId == BP_RADIOBUTTON || partId == BP_CHECKBOX) {
+ if (!(flags & QStyle::State_Enabled))
+ stateId = RBS_UNCHECKEDDISABLED;
+ else if (flags & QStyle::State_Sunken)
+ stateId = RBS_UNCHECKEDPRESSED;
+ else if (flags & QStyle::State_MouseOver)
+ stateId = RBS_UNCHECKEDHOT;
+ else
+ stateId = RBS_UNCHECKEDNORMAL;
+
+ if (flags & QStyle::State_On)
+ stateId += RBS_CHECKEDNORMAL-1;
+
+ } else if (partId == BP_PUSHBUTTON) {
+ if (!(flags & QStyle::State_Enabled))
+ stateId = PBS_DISABLED;
+ else if (flags & (QStyle::State_Sunken | QStyle::State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & QStyle::State_MouseOver)
+ stateId = PBS_HOT;
+ else
+ stateId = PBS_NORMAL;
+ } else {
+ Q_ASSERT(1);
+ }
+ return stateId;
+}
+
+bool QWindowsVistaAnimation::isUpdateNeeded() const
+{
+ return QWindowsVistaStylePrivate::useVista();
+}
+
+void QWindowsVistaAnimation::paint(QPainter *painter, const QStyleOption *option)
+{
+ painter->drawImage(option->rect, currentImage());
+}
+
+static inline bool supportsStateTransition(QStyle::PrimitiveElement element,
+ const QStyleOption *option,
+ const QWidget *widget)
+{
+ bool result = false;
+ switch (element) {
+ case QStyle::PE_IndicatorRadioButton:
+ case QStyle::PE_IndicatorCheckBox:
+ result = true;
+ break;
+ // QTBUG-40634, do not animate when color is set in palette for PE_PanelLineEdit.
+ case QStyle::PE_FrameLineEdit:
+ result = !QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget);
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+/*!
+ \internal
+
+ Animations are used for some state transitions on specific widgets.
+
+ Only one running animation can exist for a widget at any specific
+ time. Animations can be added through
+ QWindowsVistaStylePrivate::startAnimation(Animation *) and any
+ existing animation on a widget can be retrieved with
+ QWindowsVistaStylePrivate::widgetAnimation(Widget *).
+
+ Once an animation has been started,
+ QWindowsVistaStylePrivate::timerEvent(QTimerEvent *) will
+ continuously call update() on the widget until it is stopped,
+ meaning that drawPrimitive will be called many times until the
+ transition has completed. During this time, the result will be
+ retrieved by the Animation::paint(...) function and not by the style
+ itself.
+
+ To determine if a transition should occur, the style needs to know
+ the previous state of the widget as well as the current one. This is
+ solved by updating dynamic properties on the widget every time the
+ function is called.
+
+ Transitions interrupting existing transitions should always be
+ smooth, so whenever a hover-transition is started on a pulsating
+ button, it uses the current frame of the pulse-animation as the
+ starting image for the hover transition.
+
+ */
+
+void QWindowsVistaStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ int state = option->state;
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+
+ if ((option->state & State_Enabled) && d->transitionsEnabled() && canAnimate(option)) {
+ {
+ QRect oldRect;
+ QRect newRect;
+
+ if (supportsStateTransition(element, option, widget)) {
+ // Retrieve and update the dynamic properties tracking
+ // the previous state of the widget:
+ QObject *styleObject = option->styleObject;
+ styleObject->setProperty("_q_no_animation", true);
+
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ oldRect = styleObject->property("_q_stylerect").toRect();
+ newRect = option->rect;
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool doTransition = oldState &&
+ ((state & State_Sunken) != (oldState & State_Sunken) ||
+ (state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+
+ if (oldRect != newRect ||
+ (state & State_Enabled) != (oldState & State_Enabled) ||
+ (state & State_Active) != (oldState & State_Active))
+ d->stopAnimation(styleObject);
+
+ if (option->state & State_ReadOnly && element == PE_FrameLineEdit) // Do not animate read only line edits
+ doTransition = false;
+
+ if (doTransition) {
+ QStyleOption *styleOption = clonedAnimationStyleOption(option);
+ styleOption->state = QStyle::State(oldState);
+
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
+
+ // We create separate images for the initial and final transition states and store them in the
+ // Transition object.
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+
+ // If we have a running animation on the widget already, we will use that to paint the initial
+ // state of the new transition, this ensures a smooth transition from a current animation such as a
+ // pulsating default button into the intended target state.
+ if (!anim)
+ proxy()->drawPrimitive(element, styleOption, &startPainter, widget);
+ else
+ anim->paint(&startPainter, styleOption);
+
+ t->setStartImage(startImage);
+
+ // The end state of the transition is simply the result we would have painted
+ // if the style was not animated.
+ styleOption->styleObject = nullptr;
+ styleOption->state = option->state;
+ proxy()->drawPrimitive(element, styleOption, &endPainter, widget);
+
+
+ t->setEndImage(endImage);
+
+ HTHEME theme;
+ int partId;
+ DWORD duration;
+ int fromState = 0;
+ int toState = 0;
+
+ //translate state flags to UXTHEME states :
+ if (element == PE_FrameLineEdit) {
+ theme = OpenThemeData(nullptr, L"Edit");
+ partId = EP_EDITBORDER_NOSCROLL;
+
+ if (oldState & State_MouseOver)
+ fromState = ETS_HOT;
+ else if (oldState & State_HasFocus)
+ fromState = ETS_FOCUSED;
+ else
+ fromState = ETS_NORMAL;
+
+ if (state & State_MouseOver)
+ toState = ETS_HOT;
+ else if (state & State_HasFocus)
+ toState = ETS_FOCUSED;
+ else
+ toState = ETS_NORMAL;
+
+ } else {
+ theme = OpenThemeData(nullptr, L"Button");
+ if (element == PE_IndicatorRadioButton)
+ partId = BP_RADIOBUTTON;
+ else if (element == PE_IndicatorCheckBox)
+ partId = BP_CHECKBOX;
+ else
+ partId = BP_PUSHBUTTON;
+
+ fromState = buttonStateId(oldState, partId);
+ toState = buttonStateId(option->state, partId);
+ }
+
+ // Retrieve the transition time between the states from the system.
+ if (theme
+ && SUCCEEDED(GetThemeTransitionDuration(theme, partId, fromState, toState,
+ TMT_TRANSITIONDURATIONS, &duration))) {
+ t->setDuration(int(duration));
+ }
+ t->setStartTime(QTime::currentTime());
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(t);
+ }
+ styleObject->setProperty("_q_no_animation", false);
+ }
+
+ } // End of animation part
+ }
+
+ QRect rect = option->rect;
+
+ switch (element) {
+ case PE_IndicatorHeaderArrow:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ int stateId = HSAS_SORTEDDOWN;
+ if (header->sortIndicator & QStyleOptionHeader::SortDown)
+ stateId = HSAS_SORTEDUP; //note that the uxtheme sort down indicator is the inverse of ours
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::HeaderTheme,
+ HP_HEADERSORTARROW, stateId, option->rect);
+ d->drawBackground(theme);
+ }
+ break;
+
+ case PE_IndicatorBranch:
+ {
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::VistaTreeViewTheme);
+ static int decoration_size = 0;
+ if (!decoration_size && theme.isValid()) {
+ XPThemeData themeSize = theme;
+ themeSize.partId = TVP_HOTGLYPH;
+ themeSize.stateId = GLPS_OPENED;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ decoration_size = qRound(qMax(size.width(), size.height()));
+ }
+ int mid_h = option->rect.x() + option->rect.width() / 2;
+ int mid_v = option->rect.y() + option->rect.height() / 2;
+ int bef_h = mid_h;
+ int bef_v = mid_v;
+ int aft_h = mid_h;
+ int aft_v = mid_v;
+ if (option->state & State_Children) {
+ int delta = decoration_size / 2;
+ theme.rect = QRect(bef_h - delta, bef_v - delta, decoration_size, decoration_size);
+ theme.partId = option->state & State_MouseOver ? TVP_HOTGLYPH : TVP_GLYPH;
+ theme.stateId = option->state & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
+ if (option->direction == Qt::RightToLeft)
+ theme.mirrorHorizontally = true;
+ d->drawBackground(theme);
+ bef_h -= delta + 2;
+ bef_v -= delta + 2;
+ aft_h += delta - 2;
+ aft_v += delta - 2;
+ }
+#if 0
+ QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
+ if (option->state & State_Item) {
+ if (option->direction == Qt::RightToLeft)
+ painter->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
+ else
+ painter->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
+ }
+ if (option->state & State_Sibling && option->rect.bottom() > aft_v)
+ painter->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
+ if (option->state & (State_Open | State_Children | State_Item | State_Sibling) && (bef_v > option->rect.y()))
+ painter->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
+#endif
+ }
+ break;
+
+ case PE_PanelButtonBevel:
+ case PE_IndicatorCheckBox:
+ case PE_IndicatorRadioButton:
+ {
+ if (QWindowsVistaAnimation *a =
+ qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))){
+ a->paint(painter, option);
+ } else {
+ QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
+ }
+ }
+ break;
+
+ case PE_FrameMenu:
+ {
+ int stateId = option->state & State_Active ? MB_ACTIVE : MB_INACTIVE;
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPBORDERS, stateId, option->rect);
+ d->drawBackground(theme);
+ }
+ break;
+ case PE_Frame: {
+#ifndef QT_NO_ACCESSIBILITY
+ if (QStyleHelper::isInstanceOf(option->styleObject, QAccessible::EditableText)
+ || QStyleHelper::isInstanceOf(option->styleObject, QAccessible::StaticText) ||
+#else
+ if (
+#endif
+ (widget && widget->inherits("QTextEdit"))) {
+ painter->save();
+ int stateId = ETS_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (state & State_ReadOnly)
+ stateId = ETS_READONLY;
+ else if (state & State_HasFocus)
+ stateId = ETS_SELECTED;
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::EditTheme,
+ EP_EDITBORDER_HVSCROLL, stateId, option->rect);
+ // Since EP_EDITBORDER_HVSCROLL does not us borderfill, theme.noContent cannot be used for clipping
+ int borderSize = 1;
+ GetThemeInt(theme.handle(), theme.partId, theme.stateId, TMT_BORDERSIZE, &borderSize);
+ QRegion clipRegion = option->rect;
+ QRegion content = option->rect.adjusted(borderSize, borderSize, -borderSize, -borderSize);
+ clipRegion ^= content;
+ painter->setClipRegion(clipRegion);
+ d->drawBackground(theme);
+ painter->restore();
+ } else {
+ QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
+ }
+ }
+ break;
+
+ case PE_PanelLineEdit:
+ if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ bool isEnabled = option->state & State_Enabled;
+ if (QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget)) {
+ painter->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
+ } else {
+ int partId = EP_BACKGROUND;
+ int stateId = EBS_NORMAL;
+ if (!isEnabled)
+ stateId = EBS_DISABLED;
+ else if (state & State_ReadOnly)
+ stateId = EBS_READONLY;
+ else if (state & State_MouseOver)
+ stateId = EBS_HOT;
+
+ XPThemeData theme(nullptr, painter, QWindowsXPStylePrivate::EditTheme,
+ partId, stateId, rect);
+ if (!theme.isValid()) {
+ QWindowsStyle::drawPrimitive(element, option, painter, widget);
+ return;
+ }
+ int bgType;
+ GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
+ if ( bgType == BT_IMAGEFILE ) {
+ d->drawBackground(theme);
+ } else {
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+ if (!isEnabled) {
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
+ // Use only if the fill property comes from our part
+ if ((origin == PO_PART || origin == PO_STATE)) {
+ COLORREF bgRef;
+ GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
+ fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
+ }
+ }
+ painter->fillRect(option->rect, fillColor);
+ }
+ }
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, painter, widget);
+ return;
+ }
+ break;
+
+ case PE_FrameLineEdit:
+ if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)))) {
+ anim->paint(painter, option);
+ } else {
+ QPainter *p = painter;
+ if (QWindowsXPStylePrivate::isItemViewDelegateLineEdit(widget)) {
+ // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
+ QPen oldPen = p->pen();
+ // Inner white border
+ p->setPen(QPen(option->palette.base().color(), 1));
+ p->drawRect(option->rect.adjusted(1, 1, -2, -2));
+ // Outer dark border
+ p->setPen(QPen(option->palette.shadow().color(), 1));
+ p->drawRect(option->rect.adjusted(0, 0, -1, -1));
+ p->setPen(oldPen);
+ return;
+ }
+ int stateId = ETS_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (state & State_ReadOnly)
+ stateId = ETS_READONLY;
+ else if (state & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (state & State_HasFocus)
+ stateId = ETS_SELECTED;
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::EditTheme,
+ EP_EDITBORDER_NOSCROLL, stateId, option->rect);
+ theme.noContent = true;
+ painter->save();
+ QRegion clipRegion = option->rect;
+ clipRegion -= option->rect.adjusted(2, 2, -2, -2);
+ painter->setClipRegion(clipRegion);
+ d->drawBackground(theme);
+ painter->restore();
+ }
+ break;
+
+ case PE_IndicatorToolBarHandle:
+ {
+ XPThemeData theme;
+ QRect rect;
+ if (option->state & State_Horizontal) {
+ theme = XPThemeData(widget, painter,
+ QWindowsXPStylePrivate::RebarTheme,
+ RP_GRIPPER, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
+ rect = option->rect.adjusted(0, 1, 0, -2);
+ rect.setWidth(4);
+ } else {
+ theme = XPThemeData(widget, painter, QWindowsXPStylePrivate::RebarTheme,
+ RP_GRIPPERVERT, ETS_NORMAL, option->rect.adjusted(0, 1, -2, -2));
+ rect = option->rect.adjusted(1, 0, -1, 0);
+ rect.setHeight(4);
+ }
+ theme.rect = rect;
+ d->drawBackground(theme);
+ }
+ break;
+
+ case PE_IndicatorToolBarSeparator:
+ {
+ QPen pen = painter->pen();
+ int margin = 3;
+ painter->setPen(option->palette.window().color().darker(114));
+ if (option->state & State_Horizontal) {
+ int x1 = option->rect.center().x();
+ painter->drawLine(QPoint(x1, option->rect.top() + margin), QPoint(x1, option->rect.bottom() - margin));
+ } else {
+ int y1 = option->rect.center().y();
+ painter->drawLine(QPoint(option->rect.left() + margin, y1), QPoint(option->rect.right() - margin, y1));
+ }
+ painter->setPen(pen);
+ }
+ break;
+
+ case PE_PanelTipLabel: {
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::ToolTipTheme,
+ TTP_STANDARD, TTSS_NORMAL, option->rect);
+ d->drawBackground(theme);
+ break;
+ }
+
+ case PE_PanelItemViewItem:
+ {
+ const QStyleOptionViewItem *vopt;
+ bool newStyle = true;
+ QAbstractItemView::SelectionBehavior selectionBehavior = QAbstractItemView::SelectRows;
+ QAbstractItemView::SelectionMode selectionMode = QAbstractItemView::NoSelection;
+ if (const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget)) {
+ newStyle = !qobject_cast<const QTableView*>(view);
+ selectionBehavior = view->selectionBehavior();
+ selectionMode = view->selectionMode();
+#ifndef QT_NO_ACCESSIBILITY
+ } else if (!widget) {
+ newStyle = !QStyleHelper::hasAncestor(option->styleObject, QAccessible::MenuItem) ;
+#endif
+ }
+
+ if (newStyle && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
+ bool selected = vopt->state & QStyle::State_Selected;
+ const bool hover = selectionMode != QAbstractItemView::NoSelection && (vopt->state & QStyle::State_MouseOver);
+ bool active = vopt->state & QStyle::State_Active;
+
+ if (vopt->features & QStyleOptionViewItem::Alternate)
+ painter->fillRect(vopt->rect, vopt->palette.alternateBase());
+
+ QPalette::ColorGroup cg = vopt->state & QStyle::State_Enabled
+ ? QPalette::Normal : QPalette::Disabled;
+ if (cg == QPalette::Normal && !(vopt->state & QStyle::State_Active))
+ cg = QPalette::Inactive;
+
+ QRect itemRect = subElementRect(QStyle::SE_ItemViewItemFocusRect, option, widget).adjusted(-1, 0, 1, 0);
+ itemRect.setTop(vopt->rect.top());
+ itemRect.setBottom(vopt->rect.bottom());
+
+ QSize sectionSize = itemRect.size();
+ if (vopt->showDecorationSelected)
+ sectionSize = vopt->rect.size();
+
+ if (selectionBehavior == QAbstractItemView::SelectRows)
+ sectionSize.setWidth(vopt->rect.width());
+ QPixmap pixmap;
+
+ if (vopt->backgroundBrush.style() != Qt::NoBrush) {
+ const QPointF oldBrushOrigin = painter->brushOrigin();
+ painter->setBrushOrigin(vopt->rect.topLeft());
+ painter->fillRect(vopt->rect, vopt->backgroundBrush);
+ painter->setBrushOrigin(oldBrushOrigin);
+ }
+
+ if (hover || selected) {
+ if (sectionSize.width() > 0 && sectionSize.height() > 0) {
+ QString key = QString::fromLatin1("qvdelegate-%1-%2-%3-%4-%5").arg(sectionSize.width())
+ .arg(sectionSize.height()).arg(selected).arg(active).arg(hover);
+ if (!QPixmapCache::find(key, &pixmap)) {
+ pixmap = QPixmap(sectionSize);
+ pixmap.fill(Qt::transparent);
+
+ int state;
+ if (selected && hover)
+ state = LISS_HOTSELECTED;
+ else if (selected && !active)
+ state = LISS_SELECTEDNOTFOCUS;
+ else if (selected)
+ state = LISS_SELECTED;
+ else
+ state = LISS_HOT;
+
+ QPainter pixmapPainter(&pixmap);
+ XPThemeData theme(widget, &pixmapPainter,
+ QWindowsXPStylePrivate::VistaTreeViewTheme,
+ LVP_LISTITEM, state, QRect(0, 0, sectionSize.width(), sectionSize.height()));
+ if (theme.isValid()) {
+ d->drawBackground(theme);
+ } else {
+ QWindowsXPStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);
+ break;
+ }
+ QPixmapCache::insert(key, pixmap);
+ }
+ }
+
+ if (vopt->showDecorationSelected) {
+ const int frame = 2; //Assumes a 2 pixel pixmap border
+ QRect srcRect = QRect(0, 0, sectionSize.width(), sectionSize.height());
+ QRect pixmapRect = vopt->rect;
+ bool reverse = vopt->direction == Qt::RightToLeft;
+ bool leftSection = vopt->viewItemPosition == QStyleOptionViewItem::Beginning;
+ bool rightSection = vopt->viewItemPosition == QStyleOptionViewItem::End;
+ if (vopt->viewItemPosition == QStyleOptionViewItem::OnlyOne
+ || vopt->viewItemPosition == QStyleOptionViewItem::Invalid)
+ painter->drawPixmap(pixmapRect.topLeft(), pixmap);
+ else if (reverse ? rightSection : leftSection){
+ painter->drawPixmap(QRect(pixmapRect.topLeft(),
+ QSize(frame, pixmapRect.height())), pixmap,
+ QRect(QPoint(0, 0), QSize(frame, pixmapRect.height())));
+ painter->drawPixmap(pixmapRect.adjusted(frame, 0, 0, 0),
+ pixmap, srcRect.adjusted(frame, 0, -frame, 0));
+ } else if (reverse ? leftSection : rightSection) {
+ painter->drawPixmap(QRect(pixmapRect.topRight() - QPoint(frame - 1, 0),
+ QSize(frame, pixmapRect.height())), pixmap,
+ QRect(QPoint(pixmapRect.width() - frame, 0),
+ QSize(frame, pixmapRect.height())));
+ painter->drawPixmap(pixmapRect.adjusted(0, 0, -frame, 0),
+ pixmap, srcRect.adjusted(frame, 0, -frame, 0));
+ } else if (vopt->viewItemPosition == QStyleOptionViewItem::Middle)
+ painter->drawPixmap(pixmapRect, pixmap,
+ srcRect.adjusted(frame, 0, -frame, 0));
+ } else {
+ if (vopt->text.isEmpty() && vopt->icon.isNull())
+ break;
+ painter->drawPixmap(itemRect.topLeft(), pixmap);
+ }
+ }
+ } else {
+ QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
+ }
+ break;
+ }
+ case PE_Widget:
+ {
+#if QT_CONFIG(dialogbuttonbox)
+ const QDialogButtonBox *buttonBox = nullptr;
+
+ if (qobject_cast<const QMessageBox *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<const QInputDialog *> (widget))
+ buttonBox = widget->findChild<const QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+#endif // QT_CONFIG(inputdialog)
+
+ if (buttonBox) {
+ //draw white panel part
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::TaskDialogTheme,
+ TDLG_PRIMARYPANEL, 0, option->rect);
+ QRect toprect = option->rect;
+ toprect.setBottom(buttonBox->geometry().top());
+ theme.rect = toprect;
+ d->drawBackground(theme);
+
+ //draw bottom panel part
+ QRect buttonRect = option->rect;
+ buttonRect.setTop(buttonBox->geometry().top());
+ theme.rect = buttonRect;
+ theme.partId = TDLG_SECONDARYPANEL;
+ d->drawBackground(theme);
+ }
+#endif
+ }
+ break;
+ default:
+ QWindowsXPStyle::drawPrimitive(element, option, painter, widget);
+ break;
+ }
+}
+
+
+/*!
+ \internal
+
+ see drawPrimitive for comments on the animation support
+ */
+void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawControl(element, option, painter, widget);
+ return;
+ }
+
+ bool selected = option->state & State_Selected;
+ bool pressed = option->state & State_Sunken;
+ bool disabled = !(option->state & State_Enabled);
+
+ int state = option->state;
+ int themeNumber = -1;
+
+ QRect rect(option->rect);
+ State flags = option->state;
+ int partId = 0;
+ int stateId = 0;
+
+ if (d->transitionsEnabled() && canAnimate(option))
+ {
+ if (element == CE_PushButtonBevel) {
+ QRect oldRect;
+ QRect newRect;
+
+ QObject *styleObject = option->styleObject;
+
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ oldRect = styleObject->property("_q_stylerect").toRect();
+ newRect = option->rect;
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool wasDefault = false;
+ bool isDefault = false;
+ if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ wasDefault = styleObject->property("_q_isdefault").toBool();
+ isDefault = button->features & QStyleOptionButton::DefaultButton;
+ styleObject->setProperty("_q_isdefault", isDefault);
+ }
+
+ bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
+ (state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+
+ if (oldRect != newRect || (wasDefault && !isDefault)) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+
+ if (doTransition) {
+ styleObject->setProperty("_q_no_animation", true);
+
+ QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QStyleOption *styleOption = clonedAnimationStyleOption(option);
+ styleOption->state = QStyle::State(oldState);
+
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ // Use current state of existing animation if already one is running
+ if (!anim) {
+ proxy()->drawControl(element, styleOption, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, styleOption);
+ d->stopAnimation(styleObject);
+ }
+
+ t->setStartImage(startImage);
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+ styleOption->state = option->state;
+ proxy()->drawControl(element, styleOption, &endPainter, widget);
+ t->setEndImage(endImage);
+
+
+ DWORD duration = 0;
+ const HTHEME theme = OpenThemeData(nullptr, L"Button");
+
+ int fromState = buttonStateId(oldState, BP_PUSHBUTTON);
+ int toState = buttonStateId(option->state, BP_PUSHBUTTON);
+ if (GetThemeTransitionDuration(theme, BP_PUSHBUTTON, fromState, toState, TMT_TRANSITIONDURATIONS, &duration) == S_OK)
+ t->setDuration(int(duration));
+ else
+ t->setDuration(0);
+ t->setStartTime(QTime::currentTime());
+ styleObject->setProperty("_q_no_animation", false);
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(t);
+ }
+
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ if (anim) {
+ anim->paint(painter, option);
+ return;
+ }
+
+ }
+ }
+ switch (element) {
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_PUSHBUTTON;
+ if (btn->features & QStyleOptionButton::CommandLinkButton)
+ partId = BP_COMMANDLINK;
+ bool justFlat = (btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken));
+ if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
+ stateId = PBS_DISABLED;
+ else if (justFlat)
+ ;
+ else if (flags & (State_Sunken | State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton && (state & State_Active))
+ stateId = PBS_DEFAULTED;
+ else
+ stateId = PBS_NORMAL;
+
+ if (!justFlat) {
+
+ if (d->transitionsEnabled() && (btn->features & QStyleOptionButton::DefaultButton) &&
+ !(state & (State_Sunken | State_On)) && !(state & State_MouseOver) &&
+ (state & State_Enabled) && (state & State_Active))
+ {
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject(option)));
+
+ if (!anim) {
+ QImage startImage = createAnimationBuffer(option, widget);
+ QImage alternateImage = createAnimationBuffer(option, widget);
+
+ QWindowsVistaPulse *pulse = new QWindowsVistaPulse(styleObject(option));
+
+ QPainter startPainter(&startImage);
+ stateId = PBS_DEFAULTED;
+ XPThemeData theme(widget, &startPainter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+
+ QPainter alternatePainter(&alternateImage);
+ theme.stateId = PBS_DEFAULTED_ANIMATING;
+ theme.painter = &alternatePainter;
+ d->drawBackground(theme);
+ pulse->setStartImage(startImage);
+ pulse->setEndImage(alternateImage);
+ pulse->setStartTime(QTime::currentTime());
+ pulse->setDuration(2000);
+ d->startAnimation(pulse);
+ anim = pulse;
+ }
+
+ if (anim)
+ anim->paint(painter, option);
+ else {
+ XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+ }
+ }
+ else {
+ XPThemeData theme(widget, painter, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+ }
+ }
+
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int mbiw = 0, mbih = 0;
+ XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::ToolBarTheme,
+ TP_DROPDOWNBUTTON);
+ if (theme.isValid()) {
+ const QSizeF size = theme.size() * QStyleHelper::dpiScaled(1, option);
+ if (!size.isEmpty()) {
+ mbiw = qRound(size.width());
+ mbih = qRound(size.height());
+ }
+ }
+ QRect ir = subElementRect(SE_PushButtonContents, option, nullptr);
+ QStyleOptionButton newBtn = *btn;
+ newBtn.rect = QStyle::visualRect(option->direction, option->rect,
+ QRect(ir.right() - mbiw - 2,
+ option->rect.top() + (option->rect.height()/2) - (mbih/2),
+ mbiw + 1, mbih + 1));
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, painter, widget);
+ }
+ return;
+ }
+ break;
+
+ case CE_ProgressBarContents:
+ if (const QStyleOptionProgressBar *bar
+ = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ bool isIndeterminate = (bar->minimum == 0 && bar->maximum == 0);
+ const bool vertical = bar->orientation == Qt::Vertical;
+ const bool inverted = bar->invertedAppearance;
+
+ if (isIndeterminate || (bar->progress > 0 && (bar->progress < bar->maximum) && d->transitionsEnabled())) {
+ if (!d->animation(styleObject(option)))
+ d->startAnimation(new QProgressStyleAnimation(d->animationFps, styleObject(option)));
+ } else {
+ d->stopAnimation(styleObject(option));
+ }
+
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::ProgressTheme,
+ vertical ? PP_FILLVERT : PP_FILL);
+ theme.rect = option->rect;
+ bool reverse = (bar->direction == Qt::LeftToRight && inverted) || (bar->direction == Qt::RightToLeft && !inverted);
+ QTime current = QTime::currentTime();
+
+ if (isIndeterminate) {
+ if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
+ int glowSize = 120;
+ int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
+ int animOffset = a->startTime().msecsTo(current) / 4;
+ if (animOffset > animationWidth)
+ a->setStartTime(QTime::currentTime());
+ painter->save();
+ painter->setClipRect(theme.rect);
+ QRect animRect;
+ QSize pixmapSize(14, 14);
+ if (vertical) {
+ animRect = QRect(theme.rect.left(),
+ inverted ? rect.top() - glowSize + animOffset :
+ rect.bottom() + glowSize - animOffset,
+ rect.width(), glowSize);
+ pixmapSize.setHeight(animRect.height());
+ } else {
+ animRect = QRect(rect.left() - glowSize + animOffset,
+ rect.top(), glowSize, rect.height());
+ animRect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
+ option->rect, animRect);
+ pixmapSize.setWidth(animRect.width());
+ }
+ QString name = QString::fromLatin1("qiprogress-%1-%2").arg(pixmapSize.width()).arg(pixmapSize.height());
+ QPixmap pixmap;
+ if (!QPixmapCache::find(name, &pixmap)) {
+ QImage image(pixmapSize, QImage::Format_ARGB32);
+ image.fill(Qt::transparent);
+ QPainter imagePainter(&image);
+ theme.painter = &imagePainter;
+ theme.partId = vertical ? PP_FILLVERT : PP_FILL;
+ theme.rect = QRect(QPoint(0,0), animRect.size());
+ QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(),
+ vertical ? image.height() : 0);
+ alphaGradient.setColorAt(0, QColor(0, 0, 0, 0));
+ alphaGradient.setColorAt(0.5, QColor(0, 0, 0, 220));
+ alphaGradient.setColorAt(1, QColor(0, 0, 0, 0));
+ imagePainter.fillRect(image.rect(), alphaGradient);
+ imagePainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ d->drawBackground(theme);
+ imagePainter.end();
+ pixmap = QPixmap::fromImage(image);
+ QPixmapCache::insert(name, pixmap);
+ }
+ painter->drawPixmap(animRect, pixmap);
+ painter->restore();
+ }
+ }
+ else {
+ qint64 progress = qMax<qint64>(bar->progress, bar->minimum); // workaround for bug in QProgressBar
+
+ if (vertical) {
+ int maxHeight = option->rect.height();
+ int minHeight = 0;
+ double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxHeight);
+ int height = isIndeterminate ? maxHeight: qMax(int(vc6_workaround), minHeight);
+ theme.rect.setHeight(height);
+ if (!inverted)
+ theme.rect.moveTop(rect.height() - theme.rect.height());
+ } else {
+ int maxWidth = option->rect.width();
+ int minWidth = 0;
+ double vc6_workaround = ((progress - qint64(bar->minimum)) / qMax(double(1.0), double(qint64(bar->maximum) - qint64(bar->minimum))) * maxWidth);
+ int width = isIndeterminate ? maxWidth : qMax(int(vc6_workaround), minWidth);
+ theme.rect.setWidth(width);
+ theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight,
+ option->rect, theme.rect);
+ }
+ d->drawBackground(theme);
+
+ if (QProgressStyleAnimation *a = qobject_cast<QProgressStyleAnimation *>(d->animation(styleObject(option)))) {
+ int glowSize = 140;
+ int animationWidth = glowSize * 2 + (vertical ? theme.rect.height() : theme.rect.width());
+ int animOffset = a->startTime().msecsTo(current) / 4;
+ theme.partId = vertical ? PP_MOVEOVERLAYVERT : PP_MOVEOVERLAY;
+ if (animOffset > animationWidth) {
+ if (bar->progress < bar->maximum)
+ a->setStartTime(QTime::currentTime());
+ else
+ d->stopAnimation(styleObject(option)); //we stop the glow motion only after it has
+ //moved out of view
+ }
+ painter->save();
+ painter->setClipRect(theme.rect);
+ if (vertical) {
+ theme.rect = QRect(theme.rect.left(),
+ inverted ? rect.top() - glowSize + animOffset :
+ rect.bottom() + glowSize - animOffset,
+ rect.width(), glowSize);
+ } else {
+ theme.rect = QRect(rect.left() - glowSize + animOffset,rect.top(), glowSize, rect.height());
+ theme.rect = QStyle::visualRect(reverse ? Qt::RightToLeft : Qt::LeftToRight, option->rect, theme.rect);
+ }
+ d->drawBackground(theme);
+ painter->restore();
+ }
+ }
+ }
+ break;
+
+ case CE_MenuBarItem:
+ {
+
+ if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
+ {
+ if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ break;
+
+ QPalette::ColorRole textRole = disabled ? QPalette::Text : QPalette::ButtonText;
+ QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), QIcon::Normal);
+
+ int alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget))
+ alignment |= Qt::TextHideMnemonic;
+
+ if (widget && mbi->palette.color(QPalette::Window) != Qt::transparent) { // Not needed for QtQuick Controls
+ //The rect adjustment is a workaround for the menu not really filling its background.
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_BARBACKGROUND, 0, option->rect.adjusted(-1, 0, 2, 1));
+ d->drawBackground(theme);
+ }
+
+ int stateId = MBI_NORMAL;
+ if (disabled)
+ stateId = MBI_DISABLED;
+ else if (pressed)
+ stateId = MBI_PUSHED;
+ else if (selected)
+ stateId = MBI_HOT;
+
+ XPThemeData theme2(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_BARITEM, stateId, option->rect);
+ d->drawBackground(theme2);
+
+ if (!pix.isNull())
+ drawItemPixmap(painter, mbi->rect, alignment, pix);
+ else
+ drawItemText(painter, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
+ }
+ }
+ break;
+#if QT_CONFIG(menu)
+ case CE_MenuItem:
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ // windows always has a check column, regardless whether we have an icon or not
+ const qreal factor = QWindowsXPStylePrivate::nativeMetricScaleFactor(widget);
+ int checkcol = qRound(qreal(25) * factor);
+ const int gutterWidth = qRound(qreal(3) * factor);
+ {
+ XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND, MBI_HOT);
+ XPThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ checkcol = qMax(menuitem->maxIconWidth, qRound(gutterWidth + size.width() + margins.left() + margins.right()));
+ }
+ QRect rect = option->rect;
+
+ //draw vertical menu line
+ if (option->direction == Qt::LeftToRight)
+ checkcol += rect.x();
+ QPoint p1 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.top()));
+ QPoint p2 = QStyle::visualPos(option->direction, menuitem->rect, QPoint(checkcol, rect.bottom()));
+ QRect gutterRect(p1.x(), p1.y(), gutterWidth, p2.y() - p1.y() + 1);
+ XPThemeData theme2(widget, painter, QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPGUTTER, stateId, gutterRect);
+ d->drawBackground(theme2);
+
+ int x, y, w, h;
+ menuitem->rect.getRect(&x, &y, &w, &h);
+ int tab = menuitem->tabWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool checked = menuitem->checkType != QStyleOptionMenuItem::NotCheckable
+ ? menuitem->checked : false;
+ bool act = menuitem->state & State_Selected;
+
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
+ int yoff = y-2 + h / 2;
+ const int separatorSize = qRound(qreal(6) * QWindowsStylePrivate::nativeMetricScaleFactor(widget));
+ QPoint p1 = QPoint(x + checkcol, yoff);
+ QPoint p2 = QPoint(x + w + separatorSize, yoff);
+ stateId = MBI_HOT;
+ QRect subRect(p1.x() + (gutterWidth - menuitem->rect.x()), p1.y(),
+ p2.x() - p1.x(), separatorSize);
+ subRect = QStyle::visualRect(option->direction, option->rect, subRect );
+ XPThemeData theme2(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPSEPARATOR, stateId, subRect);
+ d->drawBackground(theme2);
+ return;
+ }
+
+ QRect vCheckRect = visualRect(option->direction, menuitem->rect, QRect(menuitem->rect.x(),
+ menuitem->rect.y(), checkcol - (gutterWidth + menuitem->rect.x()), menuitem->rect.height()));
+
+ if (act) {
+ stateId = dis ? MBI_DISABLED : MBI_HOT;
+ XPThemeData theme2(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPITEM, stateId, option->rect);
+ d->drawBackground(theme2);
+ }
+
+ if (checked) {
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND,
+ menuitem->icon.isNull() ? MBI_HOT : MBI_PUSHED, vCheckRect);
+ XPThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ QRect checkRect(0, 0, qRound(size.width() + margins.left() + margins.right()),
+ qRound(size.height() + margins.bottom() + margins.top()));
+ checkRect.moveCenter(vCheckRect.center());
+ theme.rect = checkRect;
+
+ d->drawBackground(theme);
+
+ if (menuitem->icon.isNull()) {
+ checkRect = QRect(QPoint(0, 0), size.toSize());
+ checkRect.moveCenter(theme.rect.center());
+ theme.rect = checkRect;
+
+ theme.partId = MENU_POPUPCHECK;
+ bool bullet = menuitem->checkType & QStyleOptionMenuItem::Exclusive;
+ if (dis)
+ theme.stateId = bullet ? MC_BULLETDISABLED: MC_CHECKMARKDISABLED;
+ else
+ theme.stateId = bullet ? MC_BULLETNORMAL: MC_CHECKMARKNORMAL;
+ d->drawBackground(theme);
+ }
+ }
+
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ QPixmap pixmap;
+ if (checked)
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode, QIcon::On);
+ else
+ pixmap = menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option, widget), mode);
+ const int pixw = pixmap.width() / pixmap.devicePixelRatio();
+ const int pixh = pixmap.height() / pixmap.devicePixelRatio();
+ QRect pmr(0, 0, pixw, pixh);
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(menuitem->palette.text().color());
+ painter->drawPixmap(pmr.topLeft(), pixmap);
+ }
+
+ painter->setPen(menuitem->palette.buttonText().color());
+
+ const QColor textColor = menuitem->palette.text().color();
+ if (dis)
+ painter->setPen(textColor);
+
+ int xm = windowsItemFrame + checkcol + windowsItemHMargin + (gutterWidth - menuitem->rect.x()) - 1;
+ int xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, menuitem->rect, textRect);
+ QString s = menuitem->text;
+ if (!s.isEmpty()) { // draw text
+ painter->save();
+ int t = s.indexOf(QLatin1Char('\t'));
+ int text_flags = Qt::AlignVCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem, widget))
+ text_flags |= Qt::TextHideMnemonic;
+ text_flags |= Qt::AlignLeft;
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(option->direction, menuitem->rect,
+ QRect(textRect.topRight(), QPoint(menuitem->rect.right(), textRect.bottom())));
+ painter->drawText(vShortcutRect, text_flags, s.mid(t + 1));
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ painter->setFont(font);
+ painter->setPen(textColor);
+ painter->drawText(vTextRect, text_flags, s.left(t));
+ painter->restore();
+ }
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {// draw sub menu arrow
+ int dim = (h - 2 * windowsItemFrame) / 2;
+ PrimitiveElement arrow;
+ arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
+ xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(option->direction, menuitem->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ proxy()->drawPrimitive(arrow, &newMI, painter, widget);
+ }
+ }
+ break;
+#endif // QT_CONFIG(menu)
+ case CE_HeaderSection:
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ partId = HP_HEADERITEM;
+ if (flags & State_Sunken)
+ stateId = HIS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = HIS_HOT;
+ else
+ stateId = HIS_NORMAL;
+
+ if (header->sortIndicator != QStyleOptionHeader::None)
+ stateId += 3;
+
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::HeaderTheme,
+ partId, stateId, option->rect);
+ d->drawBackground(theme);
+ }
+ break;
+ case CE_MenuBarEmptyArea:
+ {
+ stateId = MBI_NORMAL;
+ if (!(state & State_Enabled))
+ stateId = MBI_DISABLED;
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_BARBACKGROUND, stateId, option->rect);
+ d->drawBackground(theme);
+ }
+ break;
+ case CE_ToolBar:
+ if (const QStyleOptionToolBar *toolbar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) {
+ QPalette pal = option->palette;
+ pal.setColor(QPalette::Dark, option->palette.window().color().darker(130));
+ QStyleOptionToolBar copyOpt = *toolbar;
+ copyOpt.palette = pal;
+ QWindowsStyle::drawControl(element, &copyOpt, painter, widget);
+ }
+ break;
+#if QT_CONFIG(dockwidget)
+ case CE_DockWidgetTitle:
+ if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option)) {
+ const QDockWidget *dockWidget = qobject_cast<const QDockWidget *>(widget);
+ QRect rect = option->rect;
+ if (dockWidget && dockWidget->isFloating()) {
+ QWindowsXPStyle::drawControl(element, option, painter, widget);
+ break; //otherwise fall through
+ }
+
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ if (verticalTitleBar) {
+ rect = rect.transposed();
+
+ painter->translate(rect.left() - 1, rect.top() + rect.width());
+ painter->rotate(-90);
+ painter->translate(-rect.left() + 1, -rect.top());
+ }
+
+ painter->setBrush(option->palette.window().color().darker(110));
+ painter->setPen(option->palette.window().color().darker(130));
+ painter->drawRect(rect.adjusted(0, 1, -1, -3));
+
+ int buttonMargin = 4;
+ int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt, widget);
+ int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt, widget);
+ const QDockWidget *dw = qobject_cast<const QDockWidget *>(widget);
+ bool isFloating = dw && dw->isFloating();
+
+ QRect r = option->rect.adjusted(0, 2, -1, -3);
+ QRect titleRect = r;
+
+ if (dwOpt->closable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt, widget).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (dwOpt->floatable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt, widget).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (isFloating) {
+ titleRect.adjust(0, -fw, 0, 0);
+ if (widget && widget->windowIcon().cacheKey() != QApplication::windowIcon().cacheKey())
+ titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
+ } else {
+ titleRect.adjust(mw, 0, 0, 0);
+ if (!dwOpt->floatable && !dwOpt->closable)
+ titleRect.adjust(0, 0, -mw, 0);
+ }
+ if (!verticalTitleBar)
+ titleRect = visualRect(dwOpt->direction, r, titleRect);
+
+ if (!dwOpt->title.isEmpty()) {
+ QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight,
+ verticalTitleBar ? titleRect.height() : titleRect.width());
+ const int indent = 4;
+ drawItemText(painter, rect.adjusted(indent + 1, 1, -indent - 1, -1),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic,
+ dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText,
+ QPalette::WindowText);
+ }
+ }
+ break;
+#endif // QT_CONFIG(dockwidget)
+#if QT_CONFIG(itemviews)
+ case CE_ItemViewItem:
+ {
+ const QStyleOptionViewItem *vopt;
+
+ const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
+ bool newStyle = true;
+
+ if (qobject_cast<const QTableView*>(widget))
+ newStyle = false;
+
+ if (newStyle && view && (vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option))) {
+ /*
+ // We cannot currently get the correct selection color for "explorer style" views
+ COLORREF cref = 0;
+ XPThemeData theme(d->treeViewHelper(), 0, QLatin1String("LISTVIEW"), 0, 0);
+ unsigned int res = GetThemeColor(theme.handle(), LVP_LISTITEM, LISS_SELECTED, TMT_TEXTCOLOR, &cref);
+ QColor textColor(GetRValue(cref), GetGValue(cref), GetBValue(cref));
+ */
+ QPalette palette = vopt->palette;
+ palette.setColor(QPalette::All, QPalette::HighlightedText, palette.color(QPalette::Active, QPalette::Text));
+ // Note that setting a saturated color here results in ugly XOR colors in the focus rect
+ palette.setColor(QPalette::All, QPalette::Highlight, palette.base().color().darker(108));
+ QStyleOptionViewItem adjustedOption = *vopt;
+ adjustedOption.palette = palette;
+ // We hide the focusrect in singleselection as it is not required
+ if ((view->selectionMode() == QAbstractItemView::SingleSelection)
+ && !(vopt->state & State_KeyboardFocusChange))
+ adjustedOption.state &= ~State_HasFocus;
+ QWindowsXPStyle::drawControl(element, &adjustedOption, painter, widget);
+ } else {
+ QWindowsXPStyle::drawControl(element, option, painter, widget);
+ }
+ break;
+ }
+#endif // QT_CONFIG(itemviews)
+#if QT_CONFIG(combobox)
+ case CE_ComboBoxLabel:
+ QCommonStyle::drawControl(element, option, painter, widget);
+ break;
+#endif // QT_CONFIG(combobox)
+ default:
+ QWindowsXPStyle::drawControl(element, option, painter, widget);
+ break;
+ }
+}
+
+/*!
+ \internal
+
+ see drawPrimitive for comments on the animation support
+
+ */
+void QWindowsVistaStyle::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ QWindowsStyle::drawComplexControl(control, option, painter, widget);
+ return;
+ }
+
+ State state = option->state;
+ SubControls sub = option->subControls;
+ QRect r = option->rect;
+
+ int partId = 0;
+ int stateId = 0;
+
+ State flags = option->state;
+ if (widget && widget->testAttribute(Qt::WA_UnderMouse) && widget->isActiveWindow())
+ flags |= State_MouseOver;
+
+ if (d->transitionsEnabled() && canAnimate(option))
+ {
+
+ if (control == CC_ScrollBar || control == CC_SpinBox || control == CC_ComboBox) {
+
+ QObject *styleObject = option->styleObject; // Can be widget or qquickitem
+
+ int oldState = styleObject->property("_q_stylestate").toInt();
+ int oldActiveControls = styleObject->property("_q_stylecontrols").toInt();
+
+ QRect oldRect = styleObject->property("_q_stylerect").toRect();
+ styleObject->setProperty("_q_stylestate", int(option->state));
+ styleObject->setProperty("_q_stylecontrols", int(option->activeSubControls));
+ styleObject->setProperty("_q_stylerect", option->rect);
+
+ bool doTransition = ((state & State_Sunken) != (oldState & State_Sunken) ||
+ (state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver) ||
+ oldActiveControls != int(option->activeSubControls));
+
+ if (qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRect oldSliderPos = styleObject->property("_q_stylesliderpos").toRect();
+ QRect currentPos = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ styleObject->setProperty("_q_stylesliderpos", currentPos);
+ if (oldSliderPos != currentPos) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+ } else if (control == CC_SpinBox) {
+ //spinboxes have a transition when focus changes
+ if (!doTransition)
+ doTransition = (state & State_HasFocus) != (oldState & State_HasFocus);
+ }
+
+ if (oldRect != option->rect) {
+ doTransition = false;
+ d->stopAnimation(styleObject);
+ }
+
+ if (doTransition) {
+ QImage startImage = createAnimationBuffer(option, widget);
+ QPainter startPainter(&startImage);
+
+ QImage endImage = createAnimationBuffer(option, widget);
+ QPainter endPainter(&endImage);
+
+ QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject));
+ QWindowsVistaTransition *t = new QWindowsVistaTransition(styleObject);
+
+ // Draw the image that ends the animation by using the current styleoption
+ QStyleOptionComplex *styleOption = qstyleoption_cast<QStyleOptionComplex*>(clonedAnimationStyleOption(option));
+
+ styleObject->setProperty("_q_no_animation", true);
+
+ // Draw transition source
+ if (!anim) {
+ styleOption->state = QStyle::State(oldState);
+ styleOption->activeSubControls = QStyle::SubControl(oldActiveControls);
+ proxy()->drawComplexControl(control, styleOption, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, option);
+ }
+ t->setStartImage(startImage);
+
+ // Draw transition target
+ styleOption->state = option->state;
+ styleOption->activeSubControls = option->activeSubControls;
+ proxy()->drawComplexControl(control, styleOption, &endPainter, widget);
+
+ styleObject->setProperty("_q_no_animation", false);
+
+ t->setEndImage(endImage);
+ t->setStartTime(QTime::currentTime());
+
+ if (option->state & State_MouseOver || option->state & State_Sunken)
+ t->setDuration(150);
+ else
+ t->setDuration(500);
+
+ deleteClonedAnimationStyleOption(styleOption);
+ d->startAnimation(t);
+ }
+ if (QWindowsVistaAnimation *anim = qobject_cast<QWindowsVistaAnimation *>(d->animation(styleObject))) {
+ anim->paint(painter, option);
+ return;
+ }
+ }
+ }
+
+ switch (control) {
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
+ {
+ if (cmb->editable) {
+ if (sub & SC_ComboBoxEditField) {
+ partId = EP_EDITBORDER_NOSCROLL;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = ETS_FOCUSED;
+ else
+ stateId = ETS_NORMAL;
+
+ XPThemeData theme(widget, painter,
+ QWindowsXPStylePrivate::EditTheme,
+ partId, stateId, r);
+
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = subRect;
+ partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+
+ if (!(cmb->state & State_Enabled))
+ stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
+ stateId = CBXS_HOT;
+ else
+ stateId = CBXS_NORMAL;
+
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+
+ } else {
+ if (sub & SC_ComboBoxFrame) {
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = option->rect;
+ theme.partId = CP_READONLY;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ theme.stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver)
+ theme.stateId = CBXS_HOT;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow, widget);
+ theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*cmb);
+ fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget);
+ }
+ }
+ }
+ break;
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
+ {
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::ScrollBarTheme);
+ bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
+ if (maxedOut)
+ flags &= ~State_Enabled;
+
+ bool isHorz = flags & State_Horizontal;
+ bool isRTL = option->direction == Qt::RightToLeft;
+ if (sub & SC_ScrollBarAddLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine, widget);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
+ else if (scrollbar->state & State_MouseOver)
+ stateId = (isHorz ? (isRTL ? ABS_LEFTHOVER : ABS_RIGHTHOVER) : ABS_DOWNHOVER);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSubLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine, widget);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
+ else if (scrollbar->state & State_MouseOver)
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTHOVER : ABS_LEFTHOVER) : ABS_UPHOVER);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (maxedOut) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget));
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget));
+ partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ stateId = SCRBS_DISABLED;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ } else {
+ if (sub & SC_ScrollBarSubPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage, widget);
+ partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarAddPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage, widget);
+ partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSlider) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider, widget);
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else if (option->state & State_MouseOver)
+ stateId = SCRBS_HOVER;
+ else
+ stateId = SCRBS_NORMAL;
+
+ // Draw handle
+ theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ }
+ }
+ break;
+#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
+ {
+ XPThemeData theme(widget, painter, QWindowsXPStylePrivate::SpinTheme);
+ if (sb->frame && (sub & SC_SpinBoxFrame)) {
+ partId = EP_EDITBORDER_NOSCROLL;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = ETS_SELECTED;
+ else
+ stateId = ETS_NORMAL;
+
+ XPThemeData ftheme(widget, painter,
+ QWindowsXPStylePrivate::EditTheme,
+ partId, stateId, r);
+ // The spinbox in Windows QStyle is drawn with frameless QLineEdit inside it
+ // That however breaks with QtQuickControls where this results in transparent
+ // spinbox background, so if there's no "widget" passed (QtQuickControls case),
+ // let ftheme.noContent be false, which fixes the spinbox rendering in QQC
+ ftheme.noContent = (widget != nullptr);
+ d->drawBackground(ftheme);
+ }
+ if (sub & SC_SpinBoxUp) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp, widget).adjusted(0, 0, 0, 1);
+ partId = SPNP_UP;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepUpEnabled) || !(flags & State_Enabled))
+ stateId = UPS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
+ stateId = UPS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
+ stateId = UPS_HOT;
+ else
+ stateId = UPS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_SpinBoxDown) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown, widget);
+ partId = SPNP_DOWN;
+ if (!(sb->stepEnabled & QAbstractSpinBox::StepDownEnabled) || !(flags & State_Enabled))
+ stateId = DNS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
+ stateId = DNS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
+ stateId = DNS_HOT;
+ else
+ stateId = DNS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ }
+ break;
+#endif // QT_CONFIG(spinbox)
+ default:
+ QWindowsXPStyle::drawComplexControl(control, option, painter, widget);
+ break;
+ }
+}
+
+/*!
+ \internal
+ */
+QSize QWindowsVistaStyle::sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::sizeFromContents(type, option, size, widget);
+
+ QSize sz(size);
+ switch (type) {
+ case CT_MenuItem:
+ sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
+ int minimumHeight;
+ {
+ XPThemeData theme(widget, nullptr,
+ QWindowsXPStylePrivate::MenuTheme,
+ MENU_POPUPCHECKBACKGROUND, MBI_HOT);
+ XPThemeData themeSize = theme;
+ themeSize.partId = MENU_POPUPCHECK;
+ themeSize.stateId = 0;
+ const QSizeF size = themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const QMarginsF margins = themeSize.margins() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ minimumHeight = qMax(qRound(size.height() + margins.bottom() + margins.top()), sz.height());
+ sz.rwidth() += qRound(size.width() + margins.left() + margins.right());
+ }
+
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ if (menuitem->menuItemType != QStyleOptionMenuItem::Separator)
+ sz.setHeight(minimumHeight);
+ }
+ return sz;
+#if QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!sz.isEmpty())
+ sz += QSize(windowsItemHMargin * 5 + 1, 5);
+ return sz;
+#endif
+ case CT_ItemViewItem:
+ sz = QWindowsXPStyle::sizeFromContents(type, option, size, widget);
+ sz.rheight() += 2;
+ return sz;
+ case CT_SpinBox:
+ {
+ //Spinbox adds frame twice
+ sz = QWindowsStyle::sizeFromContents(type, option, size, widget);
+ int border = proxy()->pixelMetric(PM_SpinBoxFrameWidth, option, widget);
+ sz -= QSize(2*border, 2*border);
+ }
+ return sz;
+ case CT_HeaderSection:
+ {
+ // When there is a sort indicator it adds to the width but it is shown
+ // above the text natively and not on the side
+ if (QStyleOptionHeader *hdr = qstyleoption_cast<QStyleOptionHeader *>(const_cast<QStyleOption *>(option))) {
+ QStyleOptionHeader::SortIndicator sortInd = hdr->sortIndicator;
+ hdr->sortIndicator = QStyleOptionHeader::None;
+ sz = QWindowsXPStyle::sizeFromContents(type, hdr, size, widget);
+ hdr->sortIndicator = sortInd;
+ return sz;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return QWindowsXPStyle::sizeFromContents(type, option, size, widget);
+}
+
+/*!
+ \internal
+ */
+QRect QWindowsVistaStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::subElementRect(element, option, widget);
+
+ QRect rect = QWindowsXPStyle::subElementRect(element, option, widget);
+ switch (element) {
+
+ case SE_PushButtonContents:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ MARGINS borderSize;
+ const HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"Button");
+ if (theme) {
+ int stateId = PBS_NORMAL;
+ if (!(option->state & State_Enabled))
+ stateId = PBS_DISABLED;
+ else if (option->state & State_Sunken)
+ stateId = PBS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton)
+ stateId = PBS_DEFAULTED;
+
+ int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn, widget);
+ rect = option->rect.adjusted(border, border, -border, -border);
+
+ if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
+ rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
+ -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
+ rect = visualRect(option->direction, option->rect, rect);
+ }
+ }
+ }
+ break;
+
+ case SE_HeaderArrow:
+ {
+ QRect r = rect;
+ int h = option->rect.height();
+ int w = option->rect.width();
+ int x = option->rect.x();
+ int y = option->rect.y();
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
+
+ XPThemeData theme(widget, nullptr,
+ QWindowsXPStylePrivate::HeaderTheme,
+ HP_HEADERSORTARROW, HSAS_SORTEDDOWN, option->rect);
+
+ int arrowWidth = 13;
+ int arrowHeight = 5;
+ if (theme.isValid()) {
+ const QSizeF size = theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ if (!size.isEmpty()) {
+ arrowWidth = qRound(size.width());
+ arrowHeight = qRound(size.height());
+ }
+ }
+ if (option->state & State_Horizontal) {
+ r.setRect(x + w/2 - arrowWidth/2, y , arrowWidth, arrowHeight);
+ } else {
+ int vert_size = w / 2;
+ r.setRect(x + 5, y + h - margin * 2 - vert_size,
+ w - margin * 2 - 5, vert_size);
+ }
+ rect = visualRect(option->direction, option->rect, r);
+ }
+ break;
+
+ case SE_HeaderLabel:
+ {
+ int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget);
+ QRect r = option->rect;
+ r.setRect(option->rect.x() + margin, option->rect.y() + margin,
+ option->rect.width() - margin * 2, option->rect.height() - margin * 2);
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ // Subtract width needed for arrow, if there is one
+ if (header->sortIndicator != QStyleOptionHeader::None) {
+ if (!(option->state & State_Horizontal)) //horizontal arrows are positioned on top
+ r.setHeight(r.height() - (option->rect.width() / 2) - (margin * 2));
+ }
+ }
+ rect = visualRect(option->direction, option->rect, r);
+ }
+ break;
+ case SE_ProgressBarContents:
+ rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option, widget);
+ break;
+ case SE_ItemViewItemDecoration:
+ if (qstyleoption_cast<const QStyleOptionViewItem *>(option))
+ rect.adjust(-2, 0, 2, 0);
+ break;
+ case SE_ItemViewItemFocusRect:
+ if (const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option)) {
+ QRect textRect = subElementRect(QStyle::SE_ItemViewItemText, option, widget);
+ QRect displayRect = subElementRect(QStyle::SE_ItemViewItemDecoration, option, widget);
+ if (!vopt->icon.isNull())
+ rect = textRect.united(displayRect);
+ else
+ rect = textRect;
+ rect = rect.adjusted(1, 0, -1, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ return rect;
+}
+
+
+/*
+ This function is used by subControlRect to check if a button
+ should be drawn for the given subControl given a set of window flags.
+*/
+static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
+
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+ const auto flags = tb->titleBarFlags;
+ bool retVal = false;
+ switch (sc) {
+ case QStyle::SC_TitleBarContextHelpButton:
+ if (flags & Qt::WindowContextHelpButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMinButton:
+ if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarNormalButton:
+ if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMaxButton:
+ if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ if (!isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarUnshadeButton:
+ if (isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarCloseButton:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ default :
+ retVal = true;
+ }
+ return retVal;
+}
+
+
+/*! \internal */
+int QWindowsVistaStyle::styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget,
+ QStyleHintReturn *returnData) const
+{
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate*>(d_func());
+ int ret = 0;
+ switch (hint) {
+ case SH_MessageBox_CenterButtons:
+ ret = false;
+ break;
+ case SH_ToolTip_Mask:
+ if (option) {
+ if (QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask*>(returnData)) {
+ ret = true;
+ XPThemeData themeData(widget, nullptr,
+ QWindowsXPStylePrivate::ToolTipTheme,
+ TTP_STANDARD, TTSS_NORMAL, option->rect);
+ mask->region = d->region(themeData);
+ }
+ }
+ break;
+ case SH_Table_GridLineColor:
+ if (option)
+ ret = int(option->palette.color(QPalette::Base).darker(118).rgba());
+ else
+ ret = -1;
+ break;
+ case SH_Header_ArrowAlignment:
+ ret = Qt::AlignTop | Qt::AlignHCenter;
+ break;
+ default:
+ ret = QWindowsXPStyle::styleHint(hint, option, widget, returnData);
+ break;
+ }
+ return ret;
+}
+
+
+/*!
+ \internal
+ */
+QRect QWindowsVistaStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
+ SubControl subControl, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::subControlRect(control, option, subControl, widget);
+
+ QRect rect = QWindowsXPStyle::subControlRect(control, option, subControl, widget);
+ switch (control) {
+#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ const int x = cb->rect.x(), y = cb->rect.y(), wi = cb->rect.width(), he = cb->rect.height();
+ const int margin = cb->frame ? 3 : 0;
+ const int bmarg = cb->frame ? 2 : 0;
+ const int arrowWidth = qRound(QStyleHelper::dpiScaled(16, option));
+ const int arrowButtonWidth = bmarg + arrowWidth;
+ const int xpos = x + wi - arrowButtonWidth;
+
+ switch (subControl) {
+ case SC_ComboBoxFrame:
+ rect = cb->rect;
+ break;
+ case SC_ComboBoxArrow:
+ rect.setRect(xpos, y , arrowButtonWidth, he);
+ break;
+ case SC_ComboBoxEditField:
+ rect.setRect(x + margin, y + margin, wi - 2 * margin - arrowWidth, he - 2 * margin);
+ break;
+ case SC_ComboBoxListBoxPopup:
+ rect = cb->rect;
+ break;
+ default:
+ break;
+ }
+ rect = visualRect(cb->direction, cb->rect, rect);
+ return rect;
+ }
+ break;
+#endif // QT_CONFIG(combobox)
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ if (!buttonVisible(subControl, tb))
+ return rect;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(widget);
+ const bool isToolTitle = false;
+ const int height = tb->rect.height();
+ const int width = tb->rect.width();
+ const int buttonWidth =
+ qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor - QStyleHelper::dpiScaled(4, option));
+
+ const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option, widget);
+ const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
+ const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
+ const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
+ const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
+ const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
+
+ switch (subControl) {
+ case SC_TitleBarLabel:
+ rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
+ if (isToolTitle) {
+ if (sysmenuHint) {
+ rect.adjust(0, 0, int(-buttonWidth - 3 * factor), 0);
+ }
+ if (minimizeHint || maximizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ } else {
+ if (sysmenuHint) {
+ const int leftOffset = int(height - 8 * factor);
+ rect.adjust(leftOffset, 0, 0, int(4 * factor));
+ }
+ if (minimizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (maximizeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (contextHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ if (shadeHint)
+ rect.adjust(0, 0, int(-buttonWidth - 2 * factor), 0);
+ }
+ rect.translate(0, int(2 * factor));
+ rect = visualRect(option->direction, option->rect, rect);
+ break;
+ case SC_TitleBarSysMenu:
+ {
+ const int controlTop = int(6 * factor);
+ const int controlHeight = int(height - controlTop - 3 * factor);
+ int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option);
+ QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
+ if (tb->icon.isNull())
+ iconSize = QSize(controlHeight, controlHeight);
+ int hPad = (controlHeight - iconSize.height())/2;
+ int vPad = (controlHeight - iconSize.width())/2;
+ rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
+ rect.translate(0, int(3 * factor));
+ rect = visualRect(option->direction, option->rect, rect);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return rect;
+}
+
+/*!
+ \internal
+ */
+QStyle::SubControl QWindowsVistaStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ const QPoint &pos, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ return QWindowsStyle::hitTestComplexControl(control, option, pos, widget);
+ }
+ return QWindowsXPStyle::hitTestComplexControl(control, option, pos, widget);
+}
+
+int QWindowsVistaStylePrivate::fixedPixelMetric(QStyle::PixelMetric pm)
+{
+ switch (pm) {
+ case QStyle::PM_DockWidgetTitleBarButtonMargin:
+ return 5;
+ case QStyle::PM_ScrollBarSliderMin:
+ return 18;
+ case QStyle::PM_MenuHMargin:
+ case QStyle::PM_MenuVMargin:
+ return 0;
+ case QStyle::PM_MenuPanelWidth:
+ return 3;
+ default:
+ break;
+ }
+ return QWindowsVistaStylePrivate::InvalidMetric;
+}
+
+/*!
+ \internal
+ */
+int QWindowsVistaStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista())
+ return QWindowsStyle::pixelMetric(metric, option, widget);
+
+ int ret = QWindowsVistaStylePrivate::fixedPixelMetric(metric);
+ if (ret != QWindowsStylePrivate::InvalidMetric)
+ return int(QStyleHelper::dpiScaled(ret, option));
+
+ return QWindowsXPStyle::pixelMetric(metric, option, widget);
+}
+
+/*!
+ \internal
+ */
+QPalette QWindowsVistaStyle::standardPalette() const
+{
+ return QWindowsXPStyle::standardPalette();
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QApplication *app)
+{
+ QWindowsXPStyle::polish(app);
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QWidget *widget)
+{
+ QWindowsXPStyle::polish(widget);
+#if QT_CONFIG(lineedit)
+ if (qobject_cast<QLineEdit*>(widget))
+ widget->setAttribute(Qt::WA_Hover);
+ else
+#endif // QT_CONFIG(lineedit)
+ if (qobject_cast<QGroupBox*>(widget))
+ widget->setAttribute(Qt::WA_Hover);
+#if QT_CONFIG(commandlinkbutton)
+ else if (qobject_cast<QCommandLinkButton*>(widget)) {
+ QFont buttonFont = widget->font();
+ buttonFont.setFamilies(QStringList{QLatin1String("Segoe UI")});
+ widget->setFont(buttonFont);
+ }
+#endif // QT_CONFIG(commandlinkbutton)
+ else if (widget->inherits("QTipLabel")){
+ //note that since tooltips are not reused
+ //we do not have to care about unpolishing
+ widget->setContentsMargins(3, 0, 4, 0);
+ COLORREF bgRef;
+ HTHEME theme = OpenThemeData(widget ? QWindowsVistaStylePrivate::winId(widget) : nullptr, L"TOOLTIP");
+ if (theme && SUCCEEDED(GetThemeColor(theme, TTP_STANDARD, TTSS_NORMAL, TMT_TEXTCOLOR, &bgRef))) {
+ QColor textColor = QColor::fromRgb(bgRef);
+ QPalette pal;
+ pal.setColor(QPalette::All, QPalette::ToolTipText, textColor);
+ widget->setPalette(pal);
+ }
+ } else if (qobject_cast<QMessageBox *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
+ }
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<QInputDialog *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 9, 0, 0);
+#endif
+ }
+#endif // QT_CONFIG(inputdialog)
+ else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
+ tree->viewport()->setAttribute(Qt::WA_Hover);
+ }
+ else if (QListView *list = qobject_cast<QListView *> (widget)) {
+ list->viewport()->setAttribute(Qt::WA_Hover);
+ }
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::unpolish(QWidget *widget)
+{
+ QWindowsXPStyle::unpolish(widget);
+
+ QWindowsVistaStylePrivate *d = d_func();
+
+ d->stopAnimation(widget);
+
+#if QT_CONFIG(lineedit)
+ if (qobject_cast<QLineEdit*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ else
+#endif // QT_CONFIG(lineedit)
+ if (qobject_cast<QGroupBox*>(widget))
+ widget->setAttribute(Qt::WA_Hover, false);
+ else if (qobject_cast<QMessageBox *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_msgbox_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
+ }
+#if QT_CONFIG(inputdialog)
+ else if (qobject_cast<QInputDialog *> (widget)) {
+ widget->setAttribute(Qt::WA_StyledBackground, false);
+#if QT_CONFIG(dialogbuttonbox)
+ QDialogButtonBox *buttonBox = widget->findChild<QDialogButtonBox *>(QLatin1String("qt_inputdlg_buttonbox"));
+ if (buttonBox)
+ buttonBox->setContentsMargins(0, 0, 0, 0);
+#endif
+ }
+#endif // QT_CONFIG(inputdialog)
+ else if (QTreeView *tree = qobject_cast<QTreeView *> (widget)) {
+ tree->viewport()->setAttribute(Qt::WA_Hover, false);
+ }
+#if QT_CONFIG(commandlinkbutton)
+ else if (qobject_cast<QCommandLinkButton*>(widget)) {
+ QFont font = QApplication::font("QCommandLinkButton");
+ QFont widgetFont = widget->font();
+ widgetFont.setFamilies(font.families()); //Only family set by polish
+ widget->setFont(widgetFont);
+ }
+#endif // QT_CONFIG(commandlinkbutton)
+}
+
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::unpolish(QApplication *app)
+{
+ QWindowsXPStyle::unpolish(app);
+}
+
+/*!
+ \internal
+ */
+void QWindowsVistaStyle::polish(QPalette &pal)
+{
+ QWindowsStyle::polish(pal);
+ pal.setBrush(QPalette::AlternateBase, pal.base().color().darker(104));
+}
+
+/*!
+ \internal
+ */
+QPixmap QWindowsVistaStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option,
+ const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ return QWindowsStyle::standardPixmap(standardPixmap, option, widget);
+ }
+ return QWindowsXPStyle::standardPixmap(standardPixmap, option, widget);
+}
+
+QWindowsVistaStylePrivate::QWindowsVistaStylePrivate() :
+ QWindowsXPStylePrivate()
+{
+}
+
+bool QWindowsVistaStylePrivate::transitionsEnabled() const
+{
+ BOOL animEnabled = false;
+ if (SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &animEnabled, 0))
+ {
+ if (animEnabled)
+ return true;
+ }
+ return false;
+}
+
+/*!
+\reimp
+*/
+QIcon QWindowsVistaStyle::standardIcon(StandardPixmap standardIcon,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
+ if (!QWindowsVistaStylePrivate::useVista()) {
+ return QWindowsStyle::standardIcon(standardIcon, option, widget);
+ }
+
+ QWindowsVistaStylePrivate *d = const_cast<QWindowsVistaStylePrivate *>(d_func());
+ switch (standardIcon) {
+ case SP_CommandLink:
+ {
+ XPThemeData theme(nullptr, nullptr,
+ QWindowsXPStylePrivate::ButtonTheme,
+ BP_COMMANDLINKGLYPH, CMDLGS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(widget)).toSize();
+ QIcon linkGlyph;
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_PRESSED;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_HOT;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+
+ theme.stateId = CMDLGS_DISABLED;
+ d->drawBackground(theme);
+ linkGlyph.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ return linkGlyph;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return QWindowsXPStyle::standardIcon(standardIcon, option, widget);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p.h
new file mode 100644
index 0000000000..07cd2b8ae7
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSVISTASTYLE_P_H
+#define QWINDOWSVISTASTYLE_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 <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qquickwindowsxpstyle_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QWindowsVistaStylePrivate;
+class QWindowsVistaStyle : public QWindowsXPStyle
+{
+ Q_OBJECT
+public:
+ QWindowsVistaStyle();
+ ~QWindowsVistaStyle() override;
+
+ void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+ void drawControl(ControlElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const override;
+ void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ QPainter *painter, const QWidget *widget) const override;
+ QSize sizeFromContents(ContentsType type, const QStyleOption *option,
+ const QSize &size, const QWidget *widget) const override;
+
+ QRect subElementRect(SubElement element, const QStyleOption *option,
+ const QWidget *widget) const override;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,
+ SubControl sc, const QWidget *widget) const override;
+
+ SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
+ const QPoint &pos, const QWidget *widget = nullptr) const override;
+
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+ QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt,
+ const QWidget *widget = nullptr) const override;
+ int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+ int styleHint(StyleHint hint, const QStyleOption *opt = nullptr,
+ const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
+
+ void polish(QWidget *widget) override;
+ void unpolish(QWidget *widget) override;
+ void polish(QPalette &pal) override;
+ void polish(QApplication *app) override;
+ void unpolish(QApplication *app) override;
+ QPalette standardPalette() const override;
+
+private:
+ Q_DISABLE_COPY_MOVE(QWindowsVistaStyle)
+ Q_DECLARE_PRIVATE(QWindowsVistaStyle)
+ friend class QStyleFactory;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSVISTASTYLE_P_H
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p_p.h
new file mode 100644
index 0000000000..a5383175a3
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsvistastyle_p_p.h
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWINDOWSVISTASTYLE_P_P_H
+#define QWINDOWSVISTASTYLE_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qquickwindowsvistastyle_p.h"
+#include "qquickwindowsxpstyle_p_p.h"
+#include <private/qstyleanimation_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <qpaintengine.h>
+#include <qwidget.h>
+#include <qapplication.h>
+#include <qpixmapcache.h>
+#include <qstyleoption.h>
+#if QT_CONFIG(pushbutton)
+#include <qpushbutton.h>
+#endif
+#include <qradiobutton.h>
+#if QT_CONFIG(lineedit)
+#include <qlineedit.h>
+#endif
+#include <qgroupbox.h>
+#if QT_CONFIG(toolbutton)
+#include <qtoolbutton.h>
+#endif
+#if QT_CONFIG(spinbox)
+#include <qspinbox.h>
+#endif
+#if QT_CONFIG(toolbar)
+#include <qtoolbar.h>
+#endif
+#if QT_CONFIG(combobox)
+#include <qcombobox.h>
+#endif
+#if QT_CONFIG(scrollbar)
+#include <qscrollbar.h>
+#endif
+#if QT_CONFIG(progressbar)
+#include <qprogressbar.h>
+#endif
+#if QT_CONFIG(dockwidget)
+#include <qdockwidget.h>
+#endif
+#if QT_CONFIG(listview)
+#include <qlistview.h>
+#endif
+#if QT_CONFIG(treeview)
+#include <qtreeview.h>
+#endif
+#include <qtextedit.h>
+#include <qmessagebox.h>
+#if QT_CONFIG(dialogbuttonbox)
+#include <qdialogbuttonbox.h>
+#endif
+#include <qinputdialog.h>
+#if QT_CONFIG(tableview)
+#include <qtableview.h>
+#endif
+#include <qdatetime.h>
+#if QT_CONFIG(commandlinkbutton)
+#include <qcommandlinkbutton.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(SCHEMA_VERIFY_VSSYM32)
+#define TMT_ANIMATIONDURATION 5006
+#define TMT_TRANSITIONDURATIONS 6000
+#define EP_EDITBORDER_NOSCROLL 6
+#define EP_EDITBORDER_HVSCROLL 9
+#define EP_BACKGROUND 3
+#define EBS_NORMAL 1
+#define EBS_HOT 2
+#define EBS_DISABLED 3
+#define EBS_READONLY 5
+#define PBS_DEFAULTED_ANIMATING 6
+#define MBI_NORMAL 1
+#define MBI_HOT 2
+#define MBI_PUSHED 3
+#define MBI_DISABLED 4
+#define MB_ACTIVE 1
+#define MB_INACTIVE 2
+#define PP_FILL 5
+#define PP_FILLVERT 6
+#define PP_MOVEOVERLAY 8
+#define PP_MOVEOVERLAYVERT 10
+#define MENU_BARBACKGROUND 7
+#define MENU_BARITEM 8
+#define MENU_POPUPCHECK 11
+#define MENU_POPUPCHECKBACKGROUND 12
+#define MENU_POPUPGUTTER 13
+#define MENU_POPUPITEM 14
+#define MENU_POPUPBORDERS 10
+#define MENU_POPUPSEPARATOR 15
+#define MC_CHECKMARKNORMAL 1
+#define MC_CHECKMARKDISABLED 2
+#define MC_BULLETNORMAL 3
+#define MC_BULLETDISABLED 4
+#define ABS_UPHOVER 17
+#define ABS_DOWNHOVER 18
+#define ABS_LEFTHOVER 19
+#define ABS_RIGHTHOVER 20
+#define CP_DROPDOWNBUTTONRIGHT 6
+#define CP_DROPDOWNBUTTONLEFT 7
+#define SCRBS_HOVER 5
+#define TVP_HOTGLYPH 4
+#define SPI_GETCLIENTAREAANIMATION 0x1042
+#define TDLG_PRIMARYPANEL 1
+#define TDLG_SECONDARYPANEL 8
+#endif
+
+class QWindowsVistaAnimation : public QBlendStyleAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaAnimation(Type type, QObject *target) : QBlendStyleAnimation(type, target) { }
+
+ bool isUpdateNeeded() const override;
+ void paint(QPainter *painter, const QStyleOption *option);
+};
+
+
+// Handles state transition animations
+class QWindowsVistaTransition : public QWindowsVistaAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaTransition(QObject *target) : QWindowsVistaAnimation(Transition, target) {}
+};
+
+
+// Handles pulse animations (default buttons)
+class QWindowsVistaPulse: public QWindowsVistaAnimation
+{
+ Q_OBJECT
+public:
+ QWindowsVistaPulse(QObject *target) : QWindowsVistaAnimation(Pulse, target) {}
+};
+
+
+class QWindowsVistaStylePrivate : public QWindowsXPStylePrivate
+{
+ Q_DECLARE_PUBLIC(QWindowsVistaStyle)
+
+public:
+ QWindowsVistaStylePrivate();
+
+ static int fixedPixelMetric(QStyle::PixelMetric pm);
+ static inline bool useVista();
+ bool transitionsEnabled() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWINDOWSVISTASTYLE_P_P_H
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp
new file mode 100644
index 0000000000..39de66d55c
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle.cpp
@@ -0,0 +1,4147 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qquickstylehelper_p.h"
+#include "qquickwindowsxpstyle_p.h"
+#include "qquickwindowsxpstyle_p_p.h"
+
+#include <private/qobject_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qpainter.h>
+#include <qpaintengine.h>
+#include <qbackingstore.h>
+#include <qpixmapcache.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qvarlengtharray.h>
+#include <qdebug.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+// General const values
+static const int windowsItemFrame = 2; // menu item frame width
+static const int windowsItemHMargin = 3; // menu item hor text margin
+static const int windowsItemVMargin = 0; // menu item ver text margin
+static const int windowsArrowHMargin = 6; // arrow horizontal margin
+static const int windowsRightBorder = 12; // right border on windows
+
+// Theme names matching the QWindowsXPStylePrivate::Theme enumeration.
+static const wchar_t *themeNames[QWindowsXPStylePrivate::NThemes] =
+{
+ L"BUTTON", L"COMBOBOX", L"EDIT", L"HEADER", L"LISTVIEW",
+ L"MENU", L"PROGRESS", L"REBAR", L"SCROLLBAR", L"SPIN",
+ L"TAB", L"TASKDIALOG", L"TOOLBAR", L"TOOLTIP", L"TRACKBAR",
+ L"TREEVIEW", L"WINDOW", L"STATUS", L"TREEVIEW"
+};
+
+// Theme data helper ------------------------------------------------------------------------------
+/* \internal
+ Returns \c true if the themedata is valid for use.
+*/
+bool XPThemeData::isValid()
+{
+ return QWindowsXPStylePrivate::useXP() && theme >= 0 && handle();
+}
+
+
+/* \internal
+ Returns the theme engine handle to the specific class.
+ If the handle hasn't been opened before, it opens the data, and
+ adds it to a static map, for caching.
+*/
+HTHEME XPThemeData::handle()
+{
+ if (!QWindowsXPStylePrivate::useXP())
+ return nullptr;
+
+ if (!htheme)
+ htheme = QWindowsXPStylePrivate::createTheme(theme, QWindowsXPStylePrivate::winId(window));
+ return htheme;
+}
+
+/* \internal
+ Converts a QRect to the native RECT structure.
+*/
+RECT XPThemeData::toRECT(const QRect &qr)
+{
+ RECT r;
+ r.left = qr.x();
+ r.right = qr.x() + qr.width();
+ r.top = qr.y();
+ r.bottom = qr.y() + qr.height();
+ return r;
+}
+
+/* \internal
+ Returns the native region of a part, if the part is considered
+ transparent. The region is scaled to the parts size (rect).
+*/
+
+// QWindowsXPStylePrivate -------------------------------------------------------------------------
+// Static initializations
+HWND QWindowsXPStylePrivate::m_vistaTreeViewHelper = nullptr;
+HTHEME QWindowsXPStylePrivate::m_themes[NThemes];
+bool QWindowsXPStylePrivate::use_xp = false;
+QBasicAtomicInt QWindowsXPStylePrivate::ref = Q_BASIC_ATOMIC_INITIALIZER(-1); // -1 based refcounting
+
+static void qt_add_rect(HRGN &winRegion, QRect r)
+{
+ HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
+ if (rgn) {
+ HRGN dest = CreateRectRgn(0,0,0,0);
+ int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
+ if (result) {
+ DeleteObject(winRegion);
+ winRegion = dest;
+ }
+ DeleteObject(rgn);
+ }
+}
+
+static HRGN qt_hrgn_from_qregion(const QRegion &region)
+{
+ HRGN hRegion = CreateRectRgn(0,0,0,0);
+ if (region.rectCount() == 1) {
+ qt_add_rect(hRegion, region.boundingRect());
+ return hRegion;
+ }
+ for (const QRect &rect : region)
+ qt_add_rect(hRegion, rect);
+ return hRegion;
+}
+
+/* \internal
+ Checks if the theme engine can/should be used, or if we should
+ fall back to Windows style.
+*/
+bool QWindowsXPStylePrivate::useXP(bool update)
+{
+ if (update) {
+ use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance())
+ && !QWindowsStylePrivate::isDarkMode();
+ }
+ return use_xp;
+}
+
+/* \internal
+ Handles refcounting, and queries the theme engine for usage.
+*/
+void QWindowsXPStylePrivate::init(bool force)
+{
+ if (ref.ref() && !force)
+ return;
+ if (!force) // -1 based atomic refcounting
+ ref.ref();
+
+ useXP(true);
+ std::fill(m_themes, m_themes + NThemes, nullptr);
+}
+
+/* \internal
+ Cleans up all static data.
+*/
+void QWindowsXPStylePrivate::cleanup(bool force)
+{
+ if (bufferBitmap) {
+ if (bufferDC && nullBitmap)
+ SelectObject(bufferDC, nullBitmap);
+ DeleteObject(bufferBitmap);
+ bufferBitmap = nullptr;
+ }
+
+ if (bufferDC)
+ DeleteDC(bufferDC);
+ bufferDC = nullptr;
+
+ if (ref.deref() && !force)
+ return;
+ if (!force) // -1 based atomic refcounting
+ ref.deref();
+
+ use_xp = false;
+ cleanupHandleMap();
+}
+
+/* In order to obtain the correct VistaTreeViewTheme (arrows for PE_IndicatorBranch),
+ * we need to set the windows "explorer" theme explicitly on a native
+ * window and open the "TREEVIEW" theme handle passing its window handle
+ * in order to get Vista-style item view themes (particulary drawBackground()
+ * for selected items needs this).
+ * We invoke a service of the native Windows interface to create
+ * a non-visible window handle, open the theme on it and insert it into
+ * the cache so that it is found by XPThemeData::handle() first.
+ */
+
+static inline HWND createTreeViewHelperWindow()
+{
+ if (QPlatformNativeInterface *ni = QGuiApplication::platformNativeInterface()) {
+ void *hwnd = nullptr;
+ void *wndProc = reinterpret_cast<void *>(DefWindowProc);
+ if (QMetaObject::invokeMethod(ni, "createMessageWindow", Qt::DirectConnection,
+ Q_RETURN_ARG(void*, hwnd),
+ Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindowClass")),
+ Q_ARG(QString, QStringLiteral("QTreeViewThemeHelperWindow")),
+ Q_ARG(void*, wndProc)) && hwnd) {
+ return reinterpret_cast<HWND>(hwnd);
+ }
+ }
+ return nullptr;
+}
+
+bool QWindowsXPStylePrivate::initVistaTreeViewTheming()
+{
+ if (m_vistaTreeViewHelper)
+ return true;
+
+ m_vistaTreeViewHelper = createTreeViewHelperWindow();
+ if (!m_vistaTreeViewHelper) {
+ qWarning("Unable to create the treeview helper window.");
+ return false;
+ }
+ if (FAILED(SetWindowTheme(m_vistaTreeViewHelper, L"explorer", nullptr))) {
+ qErrnoWarning("SetWindowTheme() failed.");
+ cleanupVistaTreeViewTheming();
+ return false;
+ }
+ return true;
+}
+
+void QWindowsXPStylePrivate::cleanupVistaTreeViewTheming()
+{
+ if (m_vistaTreeViewHelper) {
+ DestroyWindow(m_vistaTreeViewHelper);
+ m_vistaTreeViewHelper = nullptr;
+ }
+}
+
+/* \internal
+ Closes all open theme data handles to ensure that we don't leak
+ resources, and that we don't refere to old handles when for
+ example the user changes the theme style.
+*/
+void QWindowsXPStylePrivate::cleanupHandleMap()
+{
+ for (auto &theme : m_themes) {
+ if (theme) {
+ CloseThemeData(theme);
+ theme = nullptr;
+ }
+ }
+ QWindowsXPStylePrivate::cleanupVistaTreeViewTheming();
+}
+
+HTHEME QWindowsXPStylePrivate::createTheme(int theme, HWND hwnd)
+{
+ if (Q_UNLIKELY(theme < 0 || theme >= NThemes || !hwnd)) {
+ qWarning("Invalid parameters #%d, %p", theme, hwnd);
+ return nullptr;
+ }
+ if (!m_themes[theme]) {
+ const wchar_t *name = themeNames[theme];
+ if (theme == VistaTreeViewTheme && QWindowsXPStylePrivate::initVistaTreeViewTheming())
+ hwnd = QWindowsXPStylePrivate::m_vistaTreeViewHelper;
+ m_themes[theme] = OpenThemeData(hwnd, name);
+ if (Q_UNLIKELY(!m_themes[theme]))
+ qErrnoWarning("OpenThemeData() failed for theme %d (%s).",
+ theme, qPrintable(themeName(theme)));
+ }
+ return m_themes[theme];
+}
+
+QString QWindowsXPStylePrivate::themeName(int theme)
+{
+ return theme >= 0 && theme < NThemes ?
+ QString::fromWCharArray(themeNames[theme]) :
+ QString();
+}
+
+/*
+bool QWindowsXPStylePrivate::isItemViewDelegateLineEdit(const QWidget *widget)
+{
+ if (!widget)
+ return false;
+ const QWidget *parent1 = widget->parentWidget();
+ // Exlude dialogs or other toplevels parented on item views.
+ if (!parent1 || parent1->isWindow())
+ return false;
+ const QWidget *parent2 = parent1->parentWidget();
+ return parent2 && widget->inherits("QLineEdit")
+ && parent2->inherits("QAbstractItemView");
+}
+*/
+
+/*
+// Returns whether base color is set for this widget
+bool QWindowsXPStylePrivate::isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget)
+{
+ uint resolveMask = option->palette.resolve();
+ if (widget) {
+ // Since spin box includes a line edit we need to resolve the palette mask also from
+ // the parent, as while the color is always correct on the palette supplied by panel,
+ // the mask can still be empty. If either mask specifies custom base color, use that.
+#if QT_CONFIG(spinbox)
+ if (const QAbstractSpinBox *spinbox = qobject_cast<QAbstractSpinBox*>(widget->parentWidget()))
+ resolveMask |= spinbox->palette().resolve();
+#endif // QT_CONFIG(spinbox)
+ }
+ return (resolveMask & (1 << QPalette::Base)) != 0;
+}
+*/
+
+/*! \internal
+ This function will always return a valid window handle, and might
+ create a limbo widget to do so.
+ We often need a window handle to for example open theme data, so
+ this function ensures that we get one.
+*/
+HWND QWindowsXPStylePrivate::winId(const QWindow *window)
+{
+ if (window)
+ if (const HWND hwnd = reinterpret_cast<HWND>(window->winId()))
+ return hwnd;
+
+ // Find top level with native window (there might be dialogs that do not have one).
+ const auto allWindows = QGuiApplication::allWindows();
+ for (const QWindow *window : allWindows) {
+ if (window->isTopLevel() && window->type() != Qt::Desktop && window->handle() != nullptr)
+ return reinterpret_cast<HWND>(window->winId());
+ }
+
+ return GetDesktopWindow();
+}
+
+/*! \internal
+ Returns a native buffer (DIB section) of at least the size of
+ ( \a x , \a y ). The buffer has a 32 bit depth, to not lose
+ the alpha values on proper alpha-pixmaps.
+*/
+HBITMAP QWindowsXPStylePrivate::buffer(int w, int h)
+{
+ // If we already have a HBITMAP which is of adequate size, just return that
+ if (bufferBitmap) {
+ if (bufferW >= w && bufferH >= h)
+ return bufferBitmap;
+ // Not big enough, discard the old one
+ if (bufferDC && nullBitmap)
+ SelectObject(bufferDC, nullBitmap);
+ DeleteObject(bufferBitmap);
+ bufferBitmap = nullptr;
+ }
+
+ w = qMax(bufferW, w);
+ h = qMax(bufferH, h);
+
+ if (!bufferDC) {
+ HDC displayDC = GetDC(nullptr);
+ bufferDC = CreateCompatibleDC(displayDC);
+ ReleaseDC(nullptr, displayDC);
+ }
+
+ // Define the header
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+
+ // Create the pixmap
+ bufferPixels = nullptr;
+ bufferBitmap = CreateDIBSection(bufferDC, &bmi, DIB_RGB_COLORS, reinterpret_cast<void **>(&bufferPixels), nullptr, 0);
+ GdiFlush();
+ nullBitmap = static_cast<HBITMAP>(SelectObject(bufferDC, bufferBitmap));
+
+ if (Q_UNLIKELY(!bufferBitmap)) {
+ qErrnoWarning("QWindowsXPStylePrivate::buffer(%dx%d), CreateDIBSection() failed.", w, h);
+ bufferW = 0;
+ bufferH = 0;
+ return nullptr;
+ }
+ if (Q_UNLIKELY(!bufferPixels)) {
+ qErrnoWarning("QWindowsXPStylePrivate::buffer(%dx%d), CreateDIBSection() did not allocate pixel data.", w, h);
+ bufferW = 0;
+ bufferH = 0;
+ return nullptr;
+ }
+ bufferW = w;
+ bufferH = h;
+#ifdef DEBUG_XP_STYLE
+ qDebug("Creating new dib section (%d, %d)", w, h);
+#endif
+ return bufferBitmap;
+}
+
+/*! \internal
+ Returns \c true if the part contains any transparency at all. This does
+ not indicate what kind of transparency we're dealing with. It can be
+ - Alpha transparency
+ - Masked transparency
+*/
+bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
+{
+ return IsThemeBackgroundPartiallyTransparent(themeData.handle(), themeData.partId,
+ themeData.stateId);
+}
+
+
+/*! \internal
+ Returns a QRegion of the region of the part
+*/
+QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
+{
+ HRGN hRgn = nullptr;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(themeData.window);
+ RECT rect = themeData.toRECT(QRect(themeData.rect.topLeft() / factor, themeData.rect.size() / factor));
+ if (!SUCCEEDED(GetThemeBackgroundRegion(themeData.handle(), bufferHDC(), themeData.partId,
+ themeData.stateId, &rect, &hRgn))) {
+ return QRegion();
+ }
+
+ HRGN dest = CreateRectRgn(0, 0, 0, 0);
+ const bool success = CombineRgn(dest, hRgn, nullptr, RGN_COPY) != ERROR;
+
+ QRegion region;
+
+ if (success) {
+ const auto numBytes = GetRegionData(dest, 0, nullptr);
+ if (numBytes == 0)
+ return QRegion();
+
+ char *buf = new (std::nothrow) char[numBytes];
+ if (!buf)
+ return QRegion();
+
+ RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
+ if (GetRegionData(dest, numBytes, rd) == 0) {
+ delete [] buf;
+ return QRegion();
+ }
+
+ RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
+ for (uint i = 0; i < rd->rdh.nCount; ++i) {
+ QRect rect;
+ rect.setCoords(int(r->left * factor), int(r->top * factor), int((r->right - 1) * factor), int((r->bottom - 1) * factor));
+ ++r;
+ region |= rect;
+ }
+
+ delete [] buf;
+ }
+
+ DeleteObject(hRgn);
+ DeleteObject(dest);
+
+ return region;
+}
+
+/*! \internal
+ Returns \c true if the native doublebuffer contains pixels with
+ varying alpha value.
+*/
+bool QWindowsXPStylePrivate::hasAlphaChannel(const QRect &rect)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+
+ int firstAlpha = -1;
+ for (int y = startY; y < h/2; ++y) {
+ auto buffer = reinterpret_cast<const DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ int alpha = (*buffer) >> 24;
+ if (firstAlpha == -1)
+ firstAlpha = alpha;
+ else if (alpha != firstAlpha)
+ return true;
+ }
+ }
+ return false;
+}
+
+/*! \internal
+ When the theme engine paints both a true alpha pixmap and a glyph
+ into our buffer, the glyph might not contain a proper alpha value.
+ The rule of thumb for premultiplied pixmaps is that the color
+ values of a pixel can never be higher than the alpha values, so
+ we use this to our advantage here, and fix all instances where
+ this occures.
+*/
+bool QWindowsXPStylePrivate::fixAlphaChannel(const QRect &rect)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+ bool hasFixedAlphaValue = false;
+
+ for (int y = startY; y < h; ++y) {
+ auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ uint pixel = *buffer;
+ int alpha = qAlpha(pixel);
+ if (qRed(pixel) > alpha || qGreen(pixel) > alpha || qBlue(pixel) > alpha) {
+ *buffer |= 0xff000000;
+ hasFixedAlphaValue = true;
+ }
+ }
+ }
+ return hasFixedAlphaValue;
+}
+
+/*! \internal
+ Swaps the alpha values on certain pixels:
+ 0xFF?????? -> 0x00??????
+ 0x00?????? -> 0xFF??????
+ Used to determin the mask of a non-alpha transparent pixmap in
+ the native doublebuffer, and swap the alphas so we may paint
+ the image as a Premultiplied QImage with drawImage(), and obtain
+ the mask transparency.
+*/
+bool QWindowsXPStylePrivate::swapAlphaChannel(const QRect &rect, bool allPixels)
+{
+ const int startX = rect.left();
+ const int startY = rect.top();
+ const int w = rect.width();
+ const int h = rect.height();
+ bool valueChange = false;
+
+ // Flip the alphas, so that 255-alpha pixels are 0, and 0-alpha are 255.
+ for (int y = startY; y < h; ++y) {
+ auto buffer = reinterpret_cast<DWORD *>(bufferPixels) + (y * bufferW);
+ for (int x = startX; x < w; ++x, ++buffer) {
+ if (allPixels) {
+ *buffer |= 0xFF000000;
+ continue;
+ }
+ unsigned int alphaValue = (*buffer) & 0xFF000000;
+ if (alphaValue == 0xFF000000) {
+ *buffer = 0;
+ valueChange = true;
+ } else if (alphaValue == 0) {
+ *buffer |= 0xFF000000;
+ valueChange = true;
+ }
+ }
+ }
+ return valueChange;
+}
+
+enum TransformType { SimpleTransform, HighDpiScalingTransform, ComplexTransform };
+
+static inline TransformType transformType(const QTransform &transform, qreal devicePixelRatio)
+{
+ if (transform.type() <= QTransform::TxTranslate)
+ return SimpleTransform;
+ if (transform.type() > QTransform::TxScale)
+ return ComplexTransform;
+ return qFuzzyCompare(transform.m11(), devicePixelRatio)
+ && qFuzzyCompare(transform.m22(), devicePixelRatio)
+ ? HighDpiScalingTransform : ComplexTransform;
+}
+
+// QTBUG-60571: Exclude known fully opaque theme parts which produce values
+// invalid in ARGB32_Premultiplied (for example, 0x00ffffff).
+static inline bool isFullyOpaque(const XPThemeData &themeData)
+{
+ return themeData.theme == QWindowsXPStylePrivate::TaskDialogTheme && themeData.partId == TDLG_PRIMARYPANEL;
+}
+
+/*! \internal
+ Main theme drawing function.
+ Determines the correct lowlevel drawing method depending on several
+ factors.
+ Use drawBackgroundThruNativeBuffer() if:
+ - Painter does not have an HDC
+ - Theme part is flipped (mirrored horizontally)
+ else use drawBackgroundDirectly().
+ \note drawBackgroundThruNativeBuffer() can return false for large
+ sizes due to buffer()/CreateDIBSection() failing.
+*/
+bool QWindowsXPStylePrivate::drawBackground(XPThemeData &themeData, qreal correctionFactor)
+{
+ if (themeData.rect.isEmpty())
+ return true;
+
+ QPainter *painter = themeData.painter;
+ Q_ASSERT_X(painter != nullptr, "QWindowsXPStylePrivate::drawBackground()", "Trying to draw a theme part without a painter");
+ if (!painter || !painter->isActive())
+ return false;
+
+ painter->save();
+
+ // Access paintDevice via engine since the painter may
+ // return the clip device which can still be a widget device in case of grabWidget().
+
+ //bool translucentToplevel = false;
+ //const QPaintDevice *paintDevice = painter->device();
+ const qreal additionalDevicePixelRatio = themeData.window ? themeData.window->devicePixelRatio() : qreal(1);
+ Q_ASSERT(painter->device()->devType() != QInternal::Widget);
+/*
+ if (paintDevice->devType() == QInternal::Widget) {
+ const QWidget *window = static_cast<const QWidget *>(paintDevice)->window();
+ translucentToplevel = window->testAttribute(Qt::WA_TranslucentBackground);
+ }
+
+ const TransformType tt = transformType(painter->deviceTransform(), aditionalDevicePixelRatio);
+
+ bool canDrawDirectly = false;
+ if (themeData.widget && painter->opacity() == 1.0 && !themeData.rotate
+ && !isFullyOpaque(themeData)
+ && tt != ComplexTransform && !themeData.mirrorVertically
+ && !translucentToplevel) {
+ // Draw on backing store DC only for real widgets or backing store images.
+ const QPaintDevice *enginePaintDevice = painter->paintEngine()->paintDevice();
+ switch (enginePaintDevice->devType()) {
+ case QInternal::Widget:
+ canDrawDirectly = true;
+ break;
+ case QInternal::Image:
+ // Ensure the backing store has received as resize and is initialized.
+ if (QBackingStore *bs = backingStoreForWidget(themeData.widget))
+ if (bs->size().isValid() && bs->paintDevice() == enginePaintDevice)
+ canDrawDirectly = true;
+ }
+ }
+
+ const HDC dc = canDrawDirectly ? hdcForWidgetBackingStore(themeData.widget) : nullptr;
+ const bool result = dc && qFuzzyCompare(correctionFactor, qreal(1))
+ ? drawBackgroundDirectly(dc, themeData, aditionalDevicePixelRatio)
+ : drawBackgroundThruNativeBuffer(themeData, aditionalDevicePixelRatio, correctionFactor);
+ */
+ const bool result = drawBackgroundThruNativeBuffer(themeData, additionalDevicePixelRatio, correctionFactor);
+ painter->restore();
+ return result;
+}
+
+static inline QRectF scaleRect(const QRectF &r, qreal factor)
+{
+ return r.isValid() && factor > 1
+ ? QRectF(r.topLeft() * factor, r.size() * factor)
+ : r;
+}
+
+static QRegion scaleRegion(const QRegion &region, qreal factor)
+{
+ if (region.isEmpty() || qFuzzyCompare(factor, qreal(1)))
+ return region;
+ QRegion result;
+ for (const QRect &rect : region)
+ result += QRectF(QPointF(rect.topLeft()) * factor, QSizeF(rect.size() * factor)).toRect();
+ return result;
+}
+
+/*! \internal
+ This function draws the theme parts directly to the paintengines HDC.
+ Do not use this if you need to perform other transformations on the
+ resulting data.
+*/
+bool QWindowsXPStylePrivate::drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal additionalDevicePixelRatio)
+{
+ QPainter *painter = themeData.painter;
+
+ const auto &deviceTransform = painter->deviceTransform();
+ const QPointF redirectionDelta(deviceTransform.dx(), deviceTransform.dy());
+ const QRect area = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio).translated(redirectionDelta).toRect();
+
+ QRegion sysRgn = painter->paintEngine()->systemClip();
+ if (sysRgn.isEmpty())
+ sysRgn = area;
+ else
+ sysRgn &= area;
+ if (painter->hasClipping())
+ sysRgn &= scaleRegion(painter->clipRegion(), additionalDevicePixelRatio).translated(redirectionDelta.toPoint());
+ HRGN hrgn = qt_hrgn_from_qregion(sysRgn);
+ SelectClipRgn(dc, hrgn);
+
+#ifdef DEBUG_XP_STYLE
+ printf("---[ DIRECT PAINTING ]------------------> Name(%-10s) Part(%d) State(%d)\n",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+ showProperties(themeData);
+#endif
+
+ RECT drawRECT = themeData.toRECT(area);
+ DTBGOPTS drawOptions;
+ memset(&drawOptions, 0, sizeof(drawOptions));
+ drawOptions.dwSize = sizeof(drawOptions);
+ drawOptions.rcClip = themeData.toRECT(sysRgn.boundingRect());
+ drawOptions.dwFlags = DTBG_CLIPRECT
+ | (themeData.noBorder ? DTBG_OMITBORDER : 0)
+ | (themeData.noContent ? DTBG_OMITCONTENT : 0)
+ | (themeData.mirrorHorizontally ? DTBG_MIRRORDC : 0);
+
+ const HRESULT result = DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &(drawRECT), &drawOptions);
+ SelectClipRgn(dc, nullptr);
+ DeleteObject(hrgn);
+ return SUCCEEDED(result);
+}
+
+/*! \internal
+ This function uses a secondary Native doublebuffer for painting parts.
+ It should only be used when the painteengine doesn't provide a proper
+ HDC for direct painting (e.g. when doing a grabWidget(), painting to
+ other pixmaps etc), or when special transformations are needed (e.g.
+ flips (horizonal mirroring only, vertical are handled by the theme
+ engine).
+
+ \a correctionFactor is an additional factor used to scale up controls
+ that are too small on High DPI screens, as has been observed for
+ WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON (QTBUG-75927).
+*/
+bool QWindowsXPStylePrivate::drawBackgroundThruNativeBuffer(XPThemeData &themeData,
+ qreal additionalDevicePixelRatio,
+ qreal correctionFactor)
+{
+ QPainter *painter = themeData.painter;
+ QRectF rectF = scaleRect(QRectF(themeData.rect), additionalDevicePixelRatio);
+
+ if ((themeData.rotate + 90) % 180 == 0) { // Catch 90,270,etc.. degree flips.
+ rectF = QRectF(0, 0, rectF.height(), rectF.width());
+ }
+ rectF.moveTo(0, 0);
+
+ const bool hasCorrectionFactor = !qFuzzyCompare(correctionFactor, qreal(1));
+ QRect rect = rectF.toRect();
+ QRect drawRect = hasCorrectionFactor
+ ? QRectF(rectF.topLeft() / correctionFactor, rectF.size() / correctionFactor).toRect() : rect;
+ int partId = themeData.partId;
+ int stateId = themeData.stateId;
+ int w = rect.width();
+ int h = rect.height();
+
+ // Values initialized later, either from cached values, or from function calls
+ AlphaChannelType alphaType = UnknownAlpha;
+ bool stateHasData = true; // We assume so;
+ bool hasAlpha = false;
+ bool partIsTransparent;
+ bool potentialInvalidAlpha;
+
+ QString pixmapCacheKey = QStringLiteral("$qt_xp_");
+ pixmapCacheKey.append(themeName(themeData.theme));
+ pixmapCacheKey.append(QLatin1Char('p'));
+ pixmapCacheKey.append(QString::number(partId));
+ pixmapCacheKey.append(QLatin1Char('s'));
+ pixmapCacheKey.append(QString::number(stateId));
+ pixmapCacheKey.append(QLatin1Char('s'));
+ pixmapCacheKey.append(themeData.noBorder ? QLatin1Char('0') : QLatin1Char('1'));
+ pixmapCacheKey.append(QLatin1Char('b'));
+ pixmapCacheKey.append(themeData.noContent ? QLatin1Char('0') : QLatin1Char('1'));
+ pixmapCacheKey.append(QString::number(w));
+ pixmapCacheKey.append(QLatin1Char('w'));
+ pixmapCacheKey.append(QString::number(h));
+ pixmapCacheKey.append(QLatin1Char('h'));
+ pixmapCacheKey.append(QString::number(additionalDevicePixelRatio));
+ pixmapCacheKey.append(QLatin1Char('d'));
+ if (hasCorrectionFactor) {
+ pixmapCacheKey.append(QLatin1Char('c'));
+ pixmapCacheKey.append(QString::number(correctionFactor));
+ }
+
+ QPixmap cachedPixmap;
+ ThemeMapKey key(themeData);
+ ThemeMapData data = alphaCache.value(key);
+
+ bool haveCachedPixmap = false;
+ bool isCached = data.dataValid;
+ if (isCached) {
+ partIsTransparent = data.partIsTransparent;
+ hasAlpha = data.hasAlphaChannel;
+ alphaType = data.alphaType;
+ potentialInvalidAlpha = data.hadInvalidAlpha;
+
+ haveCachedPixmap = QPixmapCache::find(pixmapCacheKey, &cachedPixmap);
+
+#ifdef DEBUG_XP_STYLE
+ char buf[25];
+ ::sprintf(buf, "+ Pixmap(%3d, %3d) ]", w, h);
+ printf("---[ CACHED %s--------> Name(%-10s) Part(%d) State(%d)\n",
+ haveCachedPixmap ? buf : "]-------------------",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+#endif
+ } else {
+ // Not cached, so get values from Theme Engine
+ BOOL tmt_borderonly = false;
+ COLORREF tmt_transparentcolor = 0x0;
+ PROPERTYORIGIN proporigin = PO_NOTFOUND;
+ GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERONLY, &tmt_borderonly);
+ GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, TMT_TRANSPARENTCOLOR, &tmt_transparentcolor);
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_CAPTIONMARGINS, &proporigin);
+
+ partIsTransparent = isTransparent(themeData);
+
+ potentialInvalidAlpha = false;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &proporigin);
+ if (proporigin == PO_PART || proporigin == PO_STATE) {
+ int tmt_glyphtype = GT_NONE;
+ GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, TMT_GLYPHTYPE, &tmt_glyphtype);
+ potentialInvalidAlpha = partIsTransparent && tmt_glyphtype == GT_IMAGEGLYPH;
+ }
+
+#ifdef DEBUG_XP_STYLE
+ printf("---[ NOT CACHED ]-----------------------> Name(%-10s) Part(%d) State(%d)\n",
+ qPrintable(themeData.name), themeData.partId, themeData.stateId);
+ printf("-->partIsTransparen = %d\n", partIsTransparent);
+ printf("-->potentialInvalidAlpha = %d\n", potentialInvalidAlpha);
+ showProperties(themeData);
+#endif
+ }
+ bool wasAlphaSwapped = false;
+ bool wasAlphaFixed = false;
+
+ // OLD PSDK Workaround ------------------------------------------------------------------------
+ // See if we need extra clipping for the older PSDK, which does
+ // not have a DrawThemeBackgroundEx function for DTGB_OMITBORDER
+ // and DTGB_OMITCONTENT
+ bool addBorderContentClipping = false;
+ QRegion extraClip;
+ QRect area = drawRect;
+ if (themeData.noBorder || themeData.noContent) {
+ extraClip = area;
+ // We are running on a system where the uxtheme.dll does not have
+ // the DrawThemeBackgroundEx function, so we need to clip away
+ // borders or contents manually.
+
+ int borderSize = 0;
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &origin);
+ GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, TMT_BORDERSIZE, &borderSize);
+ borderSize *= additionalDevicePixelRatio;
+
+ // Clip away border region
+ if ((origin == PO_CLASS || origin == PO_PART || origin == PO_STATE) && borderSize > 0) {
+ if (themeData.noBorder) {
+ extraClip &= area;
+ area = area.adjusted(-borderSize, -borderSize, borderSize, borderSize);
+ }
+
+ // Clip away content region
+ if (themeData.noContent) {
+ QRegion content = area.adjusted(borderSize, borderSize, -borderSize, -borderSize);
+ extraClip ^= content;
+ }
+ }
+ addBorderContentClipping = (themeData.noBorder | themeData.noContent);
+ }
+
+ QImage img;
+ if (!haveCachedPixmap) { // If the pixmap is not cached, generate it! -------------------------
+ if (!buffer(drawRect.width(), drawRect.height())) // Ensure a buffer of at least (w, h) in size
+ return false;
+ HDC dc = bufferHDC();
+
+ // Clear the buffer
+ if (alphaType != NoAlpha) {
+ // Consider have separate "memset" function for small chunks for more speedup
+ memset(bufferPixels, 0x00, bufferW * drawRect.height() * 4);
+ }
+
+ // Difference between area and rect
+ int dx = area.x() - drawRect.x();
+ int dy = area.y() - drawRect.y();
+
+ // Adjust so painting rect starts from Origo
+ rect.moveTo(0,0);
+ area.moveTo(dx,dy);
+ DTBGOPTS drawOptions;
+ drawOptions.dwSize = sizeof(drawOptions);
+ drawOptions.rcClip = themeData.toRECT(rect);
+ drawOptions.dwFlags = DTBG_CLIPRECT
+ | (themeData.noBorder ? DTBG_OMITBORDER : 0)
+ | (themeData.noContent ? DTBG_OMITCONTENT : 0);
+
+ // Drawing the part into the backing store
+ RECT wRect(themeData.toRECT(area));
+ DrawThemeBackgroundEx(themeData.handle(), dc, themeData.partId, themeData.stateId, &wRect, &drawOptions);
+
+ // If not cached, analyze the buffer data to figure
+ // out alpha type, and if it contains data
+ if (!isCached) {
+ // SHORTCUT: If the part's state has no data, cache it for NOOP later
+ if (!stateHasData) {
+ memset(static_cast<void *>(&data), 0, sizeof(data));
+ data.dataValid = true;
+ alphaCache.insert(key, data);
+ return true;
+ }
+ hasAlpha = hasAlphaChannel(rect);
+ if (!hasAlpha && partIsTransparent)
+ potentialInvalidAlpha = true;
+#if defined(DEBUG_XP_STYLE) && 1
+ dumpNativeDIB(drawRect.width(), drawRect.height());
+#endif
+ }
+
+ // Fix alpha values, if needed
+ if (potentialInvalidAlpha)
+ wasAlphaFixed = fixAlphaChannel(drawRect);
+
+ QImage::Format format;
+ if ((partIsTransparent && !wasAlphaSwapped) || (!partIsTransparent && hasAlpha)) {
+ format = QImage::Format_ARGB32_Premultiplied;
+ alphaType = RealAlpha;
+ } else if (wasAlphaSwapped) {
+ format = QImage::Format_ARGB32_Premultiplied;
+ alphaType = MaskAlpha;
+ } else {
+ format = QImage::Format_RGB32;
+ // The image data we got from the theme engine does not have any transparency,
+ // thus the alpha channel is set to 0.
+ // However, Format_RGB32 requires the alpha part to be set to 0xff, thus
+ // we must flip it from 0x00 to 0xff
+ swapAlphaChannel(rect, true);
+ alphaType = NoAlpha;
+ }
+#if defined(DEBUG_XP_STYLE) && 1
+ printf("Image format is: %s\n", alphaType == RealAlpha ? "Real Alpha" : alphaType == MaskAlpha ? "Masked Alpha" : "No Alpha");
+#endif
+ img = QImage(bufferPixels, bufferW, bufferH, format);
+ if (hasCorrectionFactor)
+ img = img.scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ img.setDevicePixelRatio(additionalDevicePixelRatio);
+ }
+
+ // Blitting backing store
+ bool useRegion = partIsTransparent && !hasAlpha && !wasAlphaSwapped;
+
+ QRegion newRegion;
+ QRegion oldRegion;
+ if (useRegion) {
+ newRegion = region(themeData);
+ oldRegion = painter->clipRegion();
+ painter->setClipRegion(newRegion);
+#if defined(DEBUG_XP_STYLE) && 0
+ printf("Using region:\n");
+ for (const QRect &r : newRegion)
+ printf(" (%d, %d, %d, %d)\n", r.x(), r.y(), r.right(), r.bottom());
+#endif
+ }
+
+ if (addBorderContentClipping)
+ painter->setClipRegion(scaleRegion(extraClip, 1.0 / additionalDevicePixelRatio), Qt::IntersectClip);
+
+ if (!themeData.mirrorHorizontally && !themeData.mirrorVertically && !themeData.rotate) {
+ if (!haveCachedPixmap)
+ painter->drawImage(themeData.rect, img, rect);
+ else
+ painter->drawPixmap(themeData.rect, cachedPixmap);
+ } else {
+ // This is _slow_!
+ // Make a copy containing only the necessary data, and mirror
+ // on all wanted axes. Then draw the copy.
+ // If cached, the normal pixmap is cached, instead of caching
+ // all possible orientations for each part and state.
+ QImage imgCopy;
+ if (!haveCachedPixmap)
+ imgCopy = img.copy(rect);
+ else
+ imgCopy = cachedPixmap.toImage();
+
+ if (themeData.rotate) {
+ QTransform rotMatrix;
+ rotMatrix.rotate(themeData.rotate);
+ imgCopy = imgCopy.transformed(rotMatrix);
+ }
+ if (themeData.mirrorHorizontally || themeData.mirrorVertically) {
+ imgCopy = imgCopy.mirrored(themeData.mirrorHorizontally, themeData.mirrorVertically);
+ }
+ painter->drawImage(themeData.rect,
+ imgCopy);
+ }
+
+ if (useRegion || addBorderContentClipping) {
+ if (oldRegion.isEmpty())
+ painter->setClipping(false);
+ else
+ painter->setClipRegion(oldRegion);
+ }
+
+ // Cache the pixmap to avoid expensive swapAlphaChannel() calls
+ if (!haveCachedPixmap && w && h) {
+ QPixmap pix = QPixmap::fromImage(img).copy(rect);
+ QPixmapCache::insert(pixmapCacheKey, pix);
+#ifdef DEBUG_XP_STYLE
+ printf("+++Adding pixmap to cache, size(%d, %d), wasAlphaSwapped(%d), wasAlphaFixed(%d), name(%s)\n",
+ w, h, wasAlphaSwapped, wasAlphaFixed, qPrintable(pixmapCacheKey));
+#endif
+ }
+
+ // Add to theme part cache
+ if (!isCached) {
+ memset(static_cast<void *>(&data), 0, sizeof(data));
+ data.dataValid = true;
+ data.partIsTransparent = partIsTransparent;
+ data.alphaType = alphaType;
+ data.hasAlphaChannel = hasAlpha;
+ data.wasAlphaSwapped = wasAlphaSwapped;
+ data.hadInvalidAlpha = wasAlphaFixed;
+ alphaCache.insert(key, data);
+ }
+ return true;
+}
+
+
+// ------------------------------------------------------------------------------------------------
+
+/*!
+ \class QWindowsXPStyle
+ \brief The QWindowsXPStyle class provides a Microsoft Windows XP-like look and feel.
+
+ \ingroup appearance
+ \inmodule QtWidgets
+ \internal
+
+ \warning This style is only available on the Windows XP platform
+ because it makes use of Windows XP's style engine.
+
+ Most of the functions are documented in the base classes
+ QWindowsStyle, QCommonStyle, and QStyle, but the
+ QWindowsXPStyle overloads of drawComplexControl(), drawControl(),
+ drawControlMask(), drawPrimitive(), proxy()->subControlRect(), and
+ sizeFromContents(), are documented here.
+
+ \image qwindowsxpstyle.png
+ \sa QMacStyle, QWindowsStyle, QFusionStyle
+*/
+
+/*!
+ Constructs a QWindowsStyle
+*/
+QWindowsXPStyle::QWindowsXPStyle()
+ : QWindowsStyle(*new QWindowsXPStylePrivate)
+{
+}
+
+/*!
+ Destroys the style.
+*/
+QWindowsXPStyle::~QWindowsXPStyle() = default;
+
+/*! \reimp */
+QRect QWindowsXPStyle::subElementRect(SubElement sr, const QStyleOption *option) const
+{
+ if (!QWindowsXPStylePrivate::useXP()) {
+ return QWindowsStyle::subElementRect(sr, option);
+ }
+
+ QRect rect(option->rect);
+ switch (sr) {
+ case SE_DockWidgetCloseButton:
+ case SE_DockWidgetFloatButton:
+ rect = QWindowsStyle::subElementRect(sr, option);
+ return rect.translated(0, 1);
+ break;
+#if 0
+ case SE_TabWidgetTabContents:
+ if (qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
+ {
+ rect = QWindowsStyle::subElementRect(sr, option);
+ if (sr == SE_TabWidgetTabContents) {
+ if (const QTabWidget *tabWidget = qobject_cast<const QTabWidget *>(widget)) {
+ if (tabWidget->documentMode())
+ break;
+ }
+
+ rect.adjust(0, 0, -2, -2);
+ }
+ }
+ break;
+ case SE_TabWidgetTabBar: {
+ rect = QWindowsStyle::subElementRect(sr, option);
+ const QStyleOptionTabWidgetFrame *twfOption =
+ qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option);
+ if (twfOption && twfOption->direction == Qt::RightToLeft
+ && (twfOption->shape == QTabBar::RoundedNorth
+ || twfOption->shape == QTabBar::RoundedSouth))
+ {
+ QStyleOptionTab otherOption;
+ otherOption.shape = (twfOption->shape == QTabBar::RoundedNorth
+ ? QTabBar::RoundedEast : QTabBar::RoundedSouth);
+ int overlap = proxy()->pixelMetric(PM_TabBarBaseOverlap, &otherOption);
+ int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option);
+ rect.adjust(-overlap + borderThickness, 0, -overlap + borderThickness, 0);
+ }
+ break;}
+#endif
+ case SE_PushButtonContents:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ MARGINS borderSize;
+ if (option->window) {
+ XPThemeData buttontheme(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme);
+ HTHEME theme = buttontheme.handle();
+ if (theme) {
+ int stateId;
+ if (!(option->state & State_Enabled))
+ stateId = PBS_DISABLED;
+ else if (option->state & State_Sunken)
+ stateId = PBS_PRESSED;
+ else if (option->state & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton)
+ stateId = PBS_DEFAULTED;
+ else
+ stateId = PBS_NORMAL;
+
+ int border = proxy()->pixelMetric(PM_DefaultFrameWidth, btn);
+ rect = option->rect.adjusted(border, border, -border, -border);
+
+ if (SUCCEEDED(GetThemeMargins(theme, nullptr, BP_PUSHBUTTON, stateId, TMT_CONTENTMARGINS, nullptr, &borderSize))) {
+ rect.adjust(borderSize.cxLeftWidth, borderSize.cyTopHeight,
+ -borderSize.cxRightWidth, -borderSize.cyBottomHeight);
+ rect = visualRect(option->direction, option->rect, rect);
+ }
+ }
+ }
+ }
+ break;
+ case SE_ProgressBarContents:
+ rect = QCommonStyle::subElementRect(SE_ProgressBarGroove, option);
+ if (option->state & QStyle::State_Horizontal)
+ rect.adjust(4, 3, -4, -3);
+ else
+ rect.adjust(3, 2, -3, -2);
+ break;
+ default:
+ rect = QWindowsStyle::subElementRect(sr, option);
+ }
+ return rect;
+}
+
+/*!
+ \reimp
+*/
+void QWindowsXPStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *option, QPainter *p) const
+{
+ QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
+
+ if (!QWindowsXPStylePrivate::useXP()) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+
+ int themeNumber = -1;
+ int partId = 0;
+ int stateId = 0;
+ QRect rect = option->rect;
+ State flags = option->state;
+ bool hMirrored = false;
+ bool vMirrored = false;
+ bool noBorder = false;
+ bool noContent = false;
+ int rotate = 0;
+
+ switch (pe) {
+#if 0
+ case PE_FrameTabBarBase:
+ if (const QStyleOptionTabBarBase *tbb
+ = qstyleoption_cast<const QStyleOptionTabBarBase *>(option)) {
+ p->save();
+ switch (tbb->shape) {
+ case QTabBar::RoundedNorth:
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.topLeft(), tbb->rect.topRight());
+ break;
+ case QTabBar::RoundedWest:
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.left(), tbb->rect.top(), tbb->rect.left(), tbb->rect.bottom());
+ break;
+ case QTabBar::RoundedSouth:
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.left(), tbb->rect.top(),
+ tbb->rect.right(), tbb->rect.top());
+ break;
+ case QTabBar::RoundedEast:
+ p->setPen(QPen(tbb->palette.dark(), 0));
+ p->drawLine(tbb->rect.topLeft(), tbb->rect.bottomLeft());
+ break;
+ case QTabBar::TriangularNorth:
+ case QTabBar::TriangularEast:
+ case QTabBar::TriangularWest:
+ case QTabBar::TriangularSouth:
+ p->restore();
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ p->restore();
+ }
+ return;
+#endif
+ case PE_PanelButtonBevel:
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_PUSHBUTTON;
+ if (!(flags & State_Enabled))
+ stateId = PBS_DISABLED;
+ else if ((flags & State_Sunken) || (flags & State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = PBS_HOT;
+ //else if (flags & State_ButtonDefault)
+ // stateId = PBS_DEFAULTED;
+ else
+ stateId = PBS_NORMAL;
+ break;
+
+ case PE_PanelButtonTool:
+// if (widget && widget->inherits("QDockWidgetTitleButton")) {
+// if (const QWidget *dw = widget->parentWidget())
+// if (dw->isWindow())
+// return;
+// }
+ themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
+ partId = TP_BUTTON;
+ if (!(flags & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (flags & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (flags & State_On)
+ stateId = TS_CHECKED;
+ else if (!(flags & State_AutoRaise))
+ stateId = TS_HOT;
+ else
+ stateId = TS_NORMAL;
+ break;
+
+ case PE_IndicatorButtonDropDown:
+ themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
+ partId = TP_SPLITBUTTONDROPDOWN;
+ if (!(flags & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (flags & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (flags & State_On)
+ stateId = TS_CHECKED;
+ else if (!(flags & State_AutoRaise))
+ stateId = TS_HOT;
+ else
+ stateId = TS_NORMAL;
+ if (option->direction == Qt::RightToLeft)
+ hMirrored = true;
+ break;
+
+ case PE_IndicatorCheckBox:
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_CHECKBOX;
+ if (!(flags & State_Enabled))
+ stateId = CBS_UNCHECKEDDISABLED;
+ else if (flags & State_Sunken)
+ stateId = CBS_UNCHECKEDPRESSED;
+ else if (flags & State_MouseOver)
+ stateId = CBS_UNCHECKEDHOT;
+ else
+ stateId = CBS_UNCHECKEDNORMAL;
+
+ if (flags & State_On)
+ stateId += CBS_CHECKEDNORMAL-1;
+ else if (flags & State_NoChange)
+ stateId += CBS_MIXEDNORMAL-1;
+
+ break;
+
+ case PE_IndicatorRadioButton:
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_RADIOBUTTON;
+ if (!(flags & State_Enabled))
+ stateId = RBS_UNCHECKEDDISABLED;
+ else if (flags & State_Sunken)
+ stateId = RBS_UNCHECKEDPRESSED;
+ else if (flags & State_MouseOver)
+ stateId = RBS_UNCHECKEDHOT;
+ else
+ stateId = RBS_UNCHECKEDNORMAL;
+
+ if (flags & State_On)
+ stateId += RBS_CHECKEDNORMAL-1;
+ break;
+
+ case PE_IndicatorDockWidgetResizeHandle:
+ return;
+
+case PE_Frame:
+ {
+ if (flags & State_Raised)
+ return;
+ themeNumber = QWindowsXPStylePrivate::ListViewTheme;
+ partId = LVP_LISTGROUP;
+ XPThemeData theme(option->window, nullptr, themeNumber, partId);
+
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else
+ stateId = ETS_NORMAL;
+ int fillType;
+ if (GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &fillType) == S_OK) {
+ if (fillType == BT_BORDERFILL) {
+ COLORREF bcRef;
+ GetThemeColor(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &bcRef);
+ QColor bordercolor(qRgb(GetRValue(bcRef), GetGValue(bcRef), GetBValue(bcRef)));
+ QPen oldPen = p->pen();
+ // int borderSize = 1;
+ // GetThemeInt(theme.handle(), partId, stateId, TMT_BORDERCOLOR, &borderSize);
+
+ // Inner white border
+ p->setPen(QPen(option->palette.base().color(), 0));
+ const qreal dpi = QStyleHelper::dpi(option);
+ const auto topLevelAdjustment = QStyleHelper::dpiScaled(0.5, dpi);
+ const auto bottomRightAdjustment = QStyleHelper::dpiScaled(-1, dpi);
+ p->drawRect(QRectF(option->rect).adjusted(topLevelAdjustment, topLevelAdjustment,
+ bottomRightAdjustment, bottomRightAdjustment));
+ // Outer dark border
+ p->setPen(QPen(bordercolor, 0));
+ p->drawRect(QRectF(option->rect).adjusted(0, 0, -topLevelAdjustment, -topLevelAdjustment));
+ p->setPen(oldPen);
+ return;
+ }
+ if (fillType == BT_NONE)
+ return;
+ }
+ break;
+ }
+ case PE_FrameLineEdit: {
+ // we try to check if this lineedit is a delegate on a QAbstractItemView-derived class.
+ /*
+ if (QWindowsXPStylePrivate::isItemViewDelegateLineEdit(widget)) {
+ QPen oldPen = p->pen();
+ // Inner white border
+ p->setPen(QPen(option->palette.base().color(), 1));
+ p->drawRect(option->rect.adjusted(1, 1, -2, -2));
+ // Outer dark border
+ p->setPen(QPen(option->palette.shadow().color(), 1));
+ p->drawRect(option->rect.adjusted(0, 0, -1, -1));
+ p->setPen(oldPen);
+ return;
+ }
+ */
+ if (qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ themeNumber = QWindowsXPStylePrivate::EditTheme;
+ partId = EP_EDITTEXT;
+ noContent = true;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else
+ stateId = ETS_NORMAL;
+ }
+ break;
+ }
+
+ case PE_PanelLineEdit:
+ if (const QStyleOptionFrame *panel = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ themeNumber = QWindowsXPStylePrivate::EditTheme;
+ partId = EP_EDITTEXT;
+ noBorder = true;
+ bool isEnabled = flags & State_Enabled;
+
+ stateId = isEnabled ? ETS_NORMAL : ETS_DISABLED;
+
+ /*if (QWindowsXPStylePrivate::isLineEditBaseColorSet(option, widget)) {
+ p->fillRect(panel->rect, panel->palette.brush(QPalette::Base));
+ } else*/ {
+ XPThemeData theme(nullptr, p, themeNumber, partId, stateId, rect);
+ if (!theme.isValid()) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ int bgType;
+ GetThemeEnumValue(theme.handle(), partId, stateId, TMT_BGTYPE, &bgType);
+ if ( bgType == BT_IMAGEFILE ) {
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ theme.noBorder = noBorder;
+ theme.noContent = noContent;
+ theme.rotate = rotate;
+ d->drawBackground(theme);
+ } else {
+ QBrush fillColor = option->palette.brush(QPalette::Base);
+
+ if (!isEnabled) {
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(theme.handle(), theme.partId, theme.stateId, TMT_FILLCOLOR, &origin);
+ // Use only if the fill property comes from our part
+ if ((origin == PO_PART || origin == PO_STATE)) {
+ COLORREF bgRef;
+ GetThemeColor(theme.handle(), partId, stateId, TMT_FILLCOLOR, &bgRef);
+ fillColor = QBrush(qRgb(GetRValue(bgRef), GetGValue(bgRef), GetBValue(bgRef)));
+ }
+ }
+ p->fillRect(option->rect, fillColor);
+ }
+ }
+
+ if (panel->lineWidth > 0)
+ proxy()->drawPrimitive(PE_FrameLineEdit, panel, p);
+ return;
+ }
+ break;
+#if 0
+ case PE_FrameTabWidget:
+ if (const QStyleOptionTabWidgetFrame *tab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::TabTheme;
+ partId = TABP_PANE;
+
+ if (option->window) {
+ bool useGradient = true;
+ const int maxlength = 256;
+ wchar_t themeFileName[maxlength];
+ wchar_t themeColor[maxlength];
+ // Due to a a scaling issue with the XP Silver theme, tab gradients are not used with it
+ if (GetCurrentThemeName(themeFileName, maxlength, themeColor, maxlength, nullptr, 0) == S_OK) {
+ wchar_t *offset = nullptr;
+ if ((offset = wcsrchr(themeFileName, QChar(QLatin1Char('\\')).unicode())) != nullptr) {
+ offset++;
+ if (!lstrcmp(offset, L"Luna.msstyles") && !lstrcmp(offset, L"Metallic")) {
+ useGradient = false;
+ }
+ }
+ }
+ // This should work, but currently there's an error in the ::drawBackgroundDirectly()
+ // code, when using the HDC directly..
+ if (useGradient) {
+ QStyleOptionTabWidgetFrame frameOpt = *tab;
+ //frameOpt.rect = widget->rect();
+
+ QRect contentsRect = subElementRect(SE_TabWidgetTabContents, &frameOpt);
+ QRegion reg = option->rect;
+ reg -= contentsRect;
+ p->setClipRegion(reg);
+ XPThemeData theme(option->window, p, themeNumber, partId, stateId, rect);
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ d->drawBackground(theme);
+ p->setClipRect(contentsRect);
+ partId = TABP_BODY;
+ }
+ }
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ vMirrored = true;
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ rotate = 90;
+ break;
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ rotate = 90;
+ hMirrored = true;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+#endif
+ case PE_FrameMenu:
+ p->save();
+ p->setPen(option->palette.dark().color());
+ p->drawRect(rect.adjusted(0, 0, -1, -1));
+ p->restore();
+ return;
+
+ case PE_PanelMenuBar:
+ break;
+
+ case PE_FrameDockWidget:
+ if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::WindowTheme;
+ if (flags & State_Active)
+ stateId = FS_ACTIVE;
+ else
+ stateId = FS_INACTIVE;
+
+ int fwidth = proxy()->pixelMetric(PM_DockWidgetFrameWidth, frm);
+
+ XPThemeData theme(option->window, p, themeNumber, 0, stateId);
+ if (!theme.isValid())
+ break;
+ theme.rect = QRect(frm->rect.x(), frm->rect.y(), frm->rect.x()+fwidth, frm->rect.height()-fwidth); theme.partId = WP_SMALLFRAMELEFT;
+ d->drawBackground(theme);
+ theme.rect = QRect(frm->rect.width()-fwidth, frm->rect.y(), fwidth, frm->rect.height()-fwidth);
+ theme.partId = WP_SMALLFRAMERIGHT;
+ d->drawBackground(theme);
+ theme.rect = QRect(frm->rect.x(), frm->rect.bottom()-fwidth+1, frm->rect.width(), fwidth);
+ theme.partId = WP_SMALLFRAMEBOTTOM;
+ d->drawBackground(theme);
+ return;
+ }
+ break;
+
+ case PE_IndicatorHeaderArrow:
+ {
+#if 0 // XP theme engine doesn't know about this :(
+ name = QWindowsXPStylePrivate::HeaderTheme;
+ partId = HP_HEADERSORTARROW;
+ if (flags & State_Down)
+ stateId = HSAS_SORTEDDOWN;
+ else
+ stateId = HSAS_SORTEDUP;
+#else
+ if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) {
+ p->save();
+ p->setPen(option->palette.dark().color());
+ p->translate(0, option->rect.height()/2 - 4);
+ if (header->sortIndicator & QStyleOptionHeader::SortUp) { // invert logic to follow Windows style guide
+ p->drawLine(option->rect.x(), option->rect.y(), option->rect.x()+8, option->rect.y());
+ p->drawLine(option->rect.x()+1, option->rect.y()+1, option->rect.x()+7, option->rect.y()+1);
+ p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
+ p->drawLine(option->rect.x()+3, option->rect.y()+3, option->rect.x()+5, option->rect.y()+3);
+ p->drawPoint(option->rect.x()+4, option->rect.y()+4);
+ } else if (header->sortIndicator & QStyleOptionHeader::SortDown) {
+ p->drawLine(option->rect.x(), option->rect.y()+4, option->rect.x()+8, option->rect.y()+4);
+ p->drawLine(option->rect.x()+1, option->rect.y()+3, option->rect.x()+7, option->rect.y()+3);
+ p->drawLine(option->rect.x()+2, option->rect.y()+2, option->rect.x()+6, option->rect.y()+2);
+ p->drawLine(option->rect.x()+3, option->rect.y()+1, option->rect.x()+5, option->rect.y()+1);
+ p->drawPoint(option->rect.x()+4, option->rect.y());
+ }
+ p->restore();
+ return;
+ }
+#endif
+ }
+ break;
+
+ case PE_FrameStatusBarItem:
+ themeNumber = QWindowsXPStylePrivate::StatusTheme;
+ partId = SP_PANE;
+ break;
+
+ case PE_FrameGroupBox:
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_GROUPBOX;
+ if (!(flags & State_Enabled))
+ stateId = GBS_DISABLED;
+ else
+ stateId = GBS_NORMAL;
+ if (const QStyleOptionFrame *frame = qstyleoption_cast<const QStyleOptionFrame *>(option)) {
+ if (frame->features & QStyleOptionFrame::Flat) {
+ // Windows XP does not have a theme part for a flat GroupBox, paint it with the windows style
+ QRect fr = frame->rect;
+ QPoint p1(fr.x(), fr.y() + 1);
+ QPoint p2(fr.x() + fr.width(), p1.y() + 1);
+ rect = QRect(p1, p2);
+ themeNumber = -1;
+ }
+ }
+ break;
+
+ case PE_IndicatorProgressChunk:
+ {
+ Qt::Orientation orient = Qt::Horizontal;
+ bool inverted = false;
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option)) {
+ orient = pb->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical;
+ inverted = pb->invertedAppearance;
+ }
+ if (orient == Qt::Horizontal) {
+ partId = PP_CHUNK;
+ rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height() );
+ if (inverted && option->direction == Qt::LeftToRight)
+ hMirrored = true;
+ } else {
+ partId = PP_CHUNKVERT;
+ rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.height());
+ }
+ themeNumber = QWindowsXPStylePrivate::ProgressTheme;
+ stateId = 1;
+ }
+ break;
+
+ case PE_FrameWindow:
+ if (const QStyleOptionFrame *frm = qstyleoption_cast<const QStyleOptionFrame *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::WindowTheme;
+ if (flags & State_Active)
+ stateId = FS_ACTIVE;
+ else
+ stateId = FS_INACTIVE;
+
+ int fwidth = int((frm->lineWidth + frm->midLineWidth) / QWindowsStylePrivate::nativeMetricScaleFactor(option));
+
+ XPThemeData theme(option->window, p, themeNumber, 0, stateId);
+ if (!theme.isValid())
+ break;
+
+ // May fail due to too-large buffers for large widgets, fall back to Windows style.
+ theme.rect = QRect(option->rect.x(), option->rect.y()+fwidth, option->rect.x()+fwidth, option->rect.height()-fwidth);
+ theme.partId = WP_FRAMELEFT;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ theme.rect = QRect(option->rect.width()-fwidth, option->rect.y()+fwidth, fwidth, option->rect.height()-fwidth);
+ theme.partId = WP_FRAMERIGHT;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ theme.rect = QRect(option->rect.x(), option->rect.height()-fwidth, option->rect.width(), fwidth);
+ theme.partId = WP_FRAMEBOTTOM;
+ if (!d->drawBackground(theme)) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ theme.rect = QRect(option->rect.x(), option->rect.y(), option->rect.width(), option->rect.y()+fwidth);
+ theme.partId = WP_CAPTION;
+ if (!d->drawBackground(theme))
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ break;
+
+ case PE_IndicatorBranch:
+ {
+ static const int decoration_size = 9;
+ int mid_h = option->rect.x() + option->rect.width() / 2;
+ int mid_v = option->rect.y() + option->rect.height() / 2;
+ int bef_h = mid_h;
+ int bef_v = mid_v;
+ int aft_h = mid_h;
+ int aft_v = mid_v;
+ QBrush brush(option->palette.dark().color(), Qt::Dense4Pattern);
+ if (option->state & State_Item) {
+ if (option->direction == Qt::RightToLeft)
+ p->fillRect(option->rect.left(), mid_v, bef_h - option->rect.left(), 1, brush);
+ else
+ p->fillRect(aft_h, mid_v, option->rect.right() - aft_h + 1, 1, brush);
+ }
+ if (option->state & State_Sibling)
+ p->fillRect(mid_h, aft_v, 1, option->rect.bottom() - aft_v + 1, brush);
+ if (option->state & (State_Open | State_Children | State_Item | State_Sibling))
+ p->fillRect(mid_h, option->rect.y(), 1, bef_v - option->rect.y(), brush);
+ if (option->state & State_Children) {
+ int delta = decoration_size / 2;
+ bef_h -= delta;
+ bef_v -= delta;
+ aft_h += delta;
+ aft_v += delta;
+ XPThemeData theme(nullptr, p, QWindowsXPStylePrivate::XpTreeViewTheme);
+ theme.rect = QRect(bef_h, bef_v, decoration_size, decoration_size);
+ theme.partId = TVP_GLYPH;
+ theme.stateId = flags & QStyle::State_Open ? GLPS_OPENED : GLPS_CLOSED;
+ d->drawBackground(theme);
+ }
+ }
+ return;
+
+ case PE_IndicatorToolBarSeparator:
+ if (option->rect.height() < 3) {
+ // XP style requires a few pixels for the separator
+ // to be visible.
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ themeNumber = QWindowsXPStylePrivate::ToolBarTheme;
+ partId = TP_SEPARATOR;
+
+ if (option->state & State_Horizontal)
+ partId = TP_SEPARATOR;
+ else
+ partId = TP_SEPARATORVERT;
+
+ break;
+
+ case PE_IndicatorToolBarHandle:
+
+ themeNumber = QWindowsXPStylePrivate::RebarTheme;
+ partId = RP_GRIPPER;
+ if (option->state & State_Horizontal) {
+ partId = RP_GRIPPER;
+ rect.adjust(0, 0, -2, 0);
+ }
+ else {
+ partId = RP_GRIPPERVERT;
+ rect.adjust(0, 0, 0, -2);
+ }
+ break;
+
+ case PE_IndicatorItemViewItemCheck: {
+ QStyleOptionButton button;
+ button.QStyleOption::operator=(*option);
+ button.state &= ~State_MouseOver;
+ proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, p);
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ XPThemeData theme(option->window, p, themeNumber, partId, stateId, rect);
+ if (!theme.isValid()) {
+ QWindowsStyle::drawPrimitive(pe, option, p);
+ return;
+ }
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ theme.noBorder = noBorder;
+ theme.noContent = noContent;
+ theme.rotate = rotate;
+ d->drawBackground(theme);
+}
+
+/*!
+ \reimp
+*/
+void QWindowsXPStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *p) const
+{
+ QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
+ if (!QWindowsXPStylePrivate::useXP()) {
+ QWindowsStyle::drawControl(element, option, p);
+ return;
+ }
+
+ QRect rect(option->rect);
+ State flags = option->state;
+
+ int rotate = 0;
+ bool hMirrored = false;
+ bool vMirrored = false;
+
+ int themeNumber = -1;
+ int partId = 0;
+ int stateId = 0;
+ switch (element) {
+ case CE_SizeGrip:
+ {
+ themeNumber = QWindowsXPStylePrivate::StatusTheme;
+ partId = SP_GRIPPER;
+ XPThemeData theme(nullptr, p, themeNumber, partId);
+ QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ size.rheight()--;
+ if (const QStyleOptionSizeGrip *sg = qstyleoption_cast<const QStyleOptionSizeGrip *>(option)) {
+ switch (sg->corner) {
+ case Qt::BottomRightCorner:
+ rect = QRect(QPoint(rect.right() - size.width(), rect.bottom() - size.height()), size);
+ break;
+ case Qt::BottomLeftCorner:
+ rect = QRect(QPoint(rect.left() + 1, rect.bottom() - size.height()), size);
+ hMirrored = true;
+ break;
+ case Qt::TopRightCorner:
+ rect = QRect(QPoint(rect.right() - size.width(), rect.top() + 1), size);
+ vMirrored = true;
+ break;
+ case Qt::TopLeftCorner:
+ rect = QRect(rect.topLeft() + QPoint(1, 1), size);
+ hMirrored = vMirrored = true;
+ }
+ }
+ }
+ break;
+
+ case CE_HeaderSection:
+ themeNumber = QWindowsXPStylePrivate::HeaderTheme;
+ partId = HP_HEADERITEM;
+ if (flags & State_Sunken)
+ stateId = HIS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = HIS_HOT;
+ else
+ stateId = HIS_NORMAL;
+ break;
+
+ case CE_Splitter:
+ p->eraseRect(option->rect);
+ return;
+
+ case CE_PushButtonBevel:
+ if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::ButtonTheme;
+ partId = BP_PUSHBUTTON;
+ bool justFlat = ((btn->features & QStyleOptionButton::Flat) && !(flags & (State_On|State_Sunken)))
+ || ((btn->features & QStyleOptionButton::CommandLinkButton)
+ && !(flags & State_MouseOver)
+ && !(btn->features & QStyleOptionButton::DefaultButton));
+ if (!(flags & State_Enabled) && !(btn->features & QStyleOptionButton::Flat))
+ stateId = PBS_DISABLED;
+ else if (justFlat)
+ ;
+ else if (flags & (State_Sunken | State_On))
+ stateId = PBS_PRESSED;
+ else if (flags & State_MouseOver)
+ stateId = PBS_HOT;
+ else if (btn->features & QStyleOptionButton::DefaultButton)
+ stateId = PBS_DEFAULTED;
+ else
+ stateId = PBS_NORMAL;
+
+ if (!justFlat) {
+ XPThemeData theme(option->window, p, themeNumber, partId, stateId, rect);
+ d->drawBackground(theme);
+ }
+
+ if (btn->features & QStyleOptionButton::HasMenu) {
+ int mbiw = 0, mbih = 0;
+ XPThemeData theme(option->window, nullptr,
+ QWindowsXPStylePrivate::ToolBarTheme,
+ TP_SPLITBUTTONDROPDOWN);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ mbiw = size.width();
+ mbih = size.height();
+ }
+
+ QRect ir = btn->rect;
+ QStyleOptionButton newBtn = *btn;
+ newBtn.rect = QRect(ir.right() - mbiw - 1, 1 + (ir.height()/2) - (mbih/2), mbiw, mbih);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p);
+ }
+ return;
+ }
+ break;
+ case CE_TabBarTab:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
+ {
+ stateId = tab->state & State_Enabled ? TIS_NORMAL : TIS_DISABLED;
+ }
+ break;
+#if 0
+ case CE_TabBarTabShape:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option))
+ {
+ themeNumber = QWindowsXPStylePrivate::TabTheme;
+ bool isDisabled = !(tab->state & State_Enabled);
+ bool hasFocus = tab->state & State_HasFocus;
+ bool isHot = tab->state & State_MouseOver;
+ bool selected = tab->state & State_Selected;
+ bool lastTab = tab->position == QStyleOptionTab::End;
+ bool firstTab = tab->position == QStyleOptionTab::Beginning;
+ bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab;
+ bool leftAligned = proxy()->styleHint(SH_TabBar_Alignment, tab) == Qt::AlignLeft;
+ bool centerAligned = proxy()->styleHint(SH_TabBar_Alignment, tab) == Qt::AlignCenter;
+ int borderThickness = proxy()->pixelMetric(PM_DefaultFrameWidth, option);
+ int tabOverlap = proxy()->pixelMetric(PM_TabBarTabOverlap, option);
+
+ if (isDisabled)
+ stateId = TIS_DISABLED;
+ else if (selected)
+ stateId = TIS_SELECTED;
+ else if (hasFocus)
+ stateId = TIS_FOCUSED;
+ else if (isHot)
+ stateId = TIS_HOT;
+ else
+ stateId = TIS_NORMAL;
+
+ // Selecting proper part depending on position
+ if (firstTab || onlyOne) {
+ if (leftAligned) {
+ partId = TABP_TABITEMLEFTEDGE;
+ } else if (centerAligned) {
+ partId = TABP_TABITEM;
+ } else { // rightAligned
+ partId = TABP_TABITEMRIGHTEDGE;
+ }
+ } else {
+ partId = TABP_TABITEM;
+ }
+
+ if (tab->direction == Qt::RightToLeft
+ && (tab->shape == QTabBar::RoundedNorth
+ || tab->shape == QTabBar::RoundedSouth)) {
+ bool temp = firstTab;
+ firstTab = lastTab;
+ lastTab = temp;
+ }
+ bool begin = firstTab || onlyOne;
+ bool end = lastTab || onlyOne;
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ if (selected)
+ rect.adjust(begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap, borderThickness);
+ else
+ rect.adjust(begin? tabOverlap : 0, tabOverlap, end ? -tabOverlap : 0, 0);
+ break;
+ case QTabBar::RoundedSouth:
+ //vMirrored = true;
+ rotate = 180; // Not 100% correct, but works
+ if (selected)
+ rect.adjust(begin ? 0 : -tabOverlap , -borderThickness, end ? 0 : tabOverlap, 0);
+ else
+ rect.adjust(begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0 , -tabOverlap);
+ break;
+ case QTabBar::RoundedEast:
+ rotate = 90;
+ if (selected) {
+ rect.adjust(-borderThickness, begin ? 0 : -tabOverlap, 0, end ? 0 : tabOverlap);
+ }else{
+ rect.adjust(0, begin ? tabOverlap : 0, -tabOverlap, end ? -tabOverlap : 0);
+ }
+ break;
+ case QTabBar::RoundedWest:
+ hMirrored = true;
+ rotate = 90;
+ if (selected) {
+ rect.adjust(0, begin ? 0 : -tabOverlap, borderThickness, end ? 0 : tabOverlap);
+ }else{
+ rect.adjust(tabOverlap, begin ? tabOverlap : 0, 0, end ? -tabOverlap : 0);
+ }
+ break;
+ default:
+ themeNumber = -1; // Do our own painting for triangular
+ break;
+ }
+
+ if (!selected) {
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ rect.adjust(0,0, 0,-1);
+ break;
+ case QTabBar::RoundedSouth:
+ rect.adjust(0,1, 0,0);
+ break;
+ case QTabBar::RoundedEast:
+ rect.adjust( 1,0, 0,0);
+ break;
+ case QTabBar::RoundedWest:
+ rect.adjust(0,0, -1,0);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ break;
+#endif
+ case CE_ProgressBarGroove:
+ {
+ Qt::Orientation orient = Qt::Horizontal;
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
+ orient = pb->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical;
+ partId = (orient == Qt::Horizontal) ? PP_BAR : PP_BARVERT;
+ themeNumber = QWindowsXPStylePrivate::ProgressTheme;
+ stateId = 1;
+ }
+ break;
+
+ case CE_MenuEmptyArea:
+ case CE_MenuItem:
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
+ {
+ int tab = menuitem->tabWidth;
+ bool dis = !(menuitem->state & State_Enabled);
+ bool act = menuitem->state & State_Selected;
+ bool checkable = menuitem->menuHasCheckableItems;
+ bool checked = checkable ? menuitem->checked : false;
+
+ // windows always has a check column, regardless whether we have an icon or not
+ int checkcol = qMax(menuitem->maxIconWidth, 12);
+
+ int x, y, w, h;
+ rect.getRect(&x, &y, &w, &h);
+
+ QBrush fill = menuitem->palette.brush(act ? QPalette::Highlight : QPalette::Button);
+ p->fillRect(rect, fill);
+
+ if (element == CE_MenuEmptyArea)
+ break;
+
+ // draw separator -------------------------------------------------
+ if (menuitem->menuItemType == QStyleOptionMenuItem::Separator) {
+ int yoff = y-1 + h / 2;
+ p->setPen(menuitem->palette.dark().color());
+ p->drawLine(x, yoff, x+w, yoff);
+ ++yoff;
+ p->setPen(menuitem->palette.light().color());
+ p->drawLine(x, yoff, x+w, yoff);
+ return;
+ }
+
+ int xpos = x;
+
+ // draw icon ------------------------------------------------------
+ if (!menuitem->icon.isNull()) {
+ QIcon::Mode mode = dis ? QIcon::Disabled : QIcon::Normal;
+ if (act && !dis)
+ mode = QIcon::Active;
+ QPixmap pixmap = checked ?
+ menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option), mode, QIcon::On) :
+ menuitem->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option), mode);
+ const int pixw = pixmap.width() / pixmap.devicePixelRatio();
+ const int pixh = pixmap.height() / pixmap.devicePixelRatio();
+ QRect iconRect(0, 0, pixw, pixh);
+ iconRect.moveCenter(QRect(xpos, y, checkcol, h).center());
+ QRect vIconRect = visualRect(option->direction, option->rect, iconRect);
+ p->setPen(menuitem->palette.text().color());
+ p->setBrush(Qt::NoBrush);
+ if (checked)
+ p->drawRect(vIconRect.adjusted(-1, -1, 0, 0));
+ p->drawPixmap(vIconRect.topLeft(), pixmap);
+
+ // draw checkmark -------------------------------------------------
+ } else if (checked) {
+ QStyleOptionMenuItem newMi = *menuitem;
+ newMi.state = State_None;
+ if (!dis)
+ newMi.state |= State_Enabled;
+ if (act)
+ newMi.state |= State_On;
+
+ QRect checkMarkRect = QRect(menuitem->rect.x() + windowsItemFrame,
+ menuitem->rect.y() + windowsItemFrame,
+ checkcol - 2 * windowsItemFrame,
+ menuitem->rect.height() - 2*windowsItemFrame);
+ newMi.rect = visualRect(option->direction, option->rect, checkMarkRect);
+ proxy()->drawPrimitive(PE_IndicatorMenuCheckMark, &newMi, p);
+ }
+
+ QColor textColor = dis ? menuitem->palette.text().color() :
+ act ? menuitem->palette.highlightedText().color() : menuitem->palette.buttonText().color();
+ p->setPen(textColor);
+
+ // draw text ------------------------------------------------------
+ int xm = windowsItemFrame + checkcol + windowsItemHMargin;
+ xpos = menuitem->rect.x() + xm;
+ QRect textRect(xpos, y + windowsItemVMargin, w - xm - windowsRightBorder - tab + 1, h - 2 * windowsItemVMargin);
+ QRect vTextRect = visualRect(option->direction, option->rect, textRect);
+ QString s = menuitem->text;
+ if (!s.isEmpty()) {
+ p->save();
+ int t = s.indexOf(QLatin1Char('\t'));
+ int text_flags = Qt::AlignVCenter|Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine | Qt::AlignLeft;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, menuitem))
+ text_flags |= Qt::TextHideMnemonic;
+ // draw tab text ----------------
+ if (t >= 0) {
+ QRect vShortcutRect = visualRect(option->direction, option->rect, QRect(textRect.topRight(), menuitem->rect.bottomRight()));
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option)) {
+ p->setPen(menuitem->palette.light().color());
+ p->drawText(vShortcutRect.adjusted(1,1,1,1), text_flags, s.mid(t + 1));
+ p->setPen(textColor);
+ }
+ p->drawText(vShortcutRect, text_flags, s.mid(t + 1));
+ s = s.left(t);
+ }
+ QFont font = menuitem->font;
+ if (menuitem->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ font.setBold(true);
+ p->setFont(font);
+ if (dis && !act && proxy()->styleHint(SH_EtchDisabledText, option)) {
+ p->setPen(menuitem->palette.light().color());
+ p->drawText(vTextRect.adjusted(1,1,1,1), text_flags, s.left(t));
+ p->setPen(textColor);
+ }
+ p->drawText(vTextRect, text_flags, s);
+ p->restore();
+ }
+
+ // draw sub menu arrow --------------------------------------------
+ if (menuitem->menuItemType == QStyleOptionMenuItem::SubMenu) {
+ int dim = (h - 2) / 2;
+ PrimitiveElement arrow;
+ arrow = (option->direction == Qt::RightToLeft) ? PE_IndicatorArrowLeft : PE_IndicatorArrowRight;
+ xpos = x + w - windowsArrowHMargin - windowsItemFrame - dim;
+ QRect vSubMenuRect = visualRect(option->direction, option->rect, QRect(xpos, y + h / 2 - dim / 2, dim, dim));
+ QStyleOptionMenuItem newMI = *menuitem;
+ newMI.rect = vSubMenuRect;
+ newMI.state = dis ? State_None : State_Enabled;
+ if (act)
+ newMI.palette.setColor(QPalette::ButtonText, newMI.palette.highlightedText().color());
+ proxy()->drawPrimitive(arrow, &newMI, p);
+ }
+ }
+ return;
+
+ case CE_MenuBarItem:
+ if (const QStyleOptionMenuItem *mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
+ {
+ if (mbi->menuItemType == QStyleOptionMenuItem::DefaultItem)
+ break;
+
+ bool act = mbi->state & State_Selected;
+ bool dis = !(mbi->state & State_Enabled);
+
+ QBrush fill = mbi->palette.brush(act ? QPalette::Highlight : QPalette::Button);
+ QPalette::ColorRole textRole = dis ? QPalette::Text:
+ act ? QPalette::HighlightedText : QPalette::ButtonText;
+ QPixmap pix = mbi->icon.pixmap(proxy()->pixelMetric(PM_SmallIconSize, option), QIcon::Normal);
+
+ uint alignment = Qt::AlignCenter | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, mbi))
+ alignment |= Qt::TextHideMnemonic;
+
+ p->fillRect(rect, fill);
+ if (!pix.isNull())
+ drawItemPixmap(p, mbi->rect, alignment, pix);
+ else
+ drawItemText(p, mbi->rect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole);
+ }
+ return;
+#if 0 && QT_CONFIG(dockwidget)
+ case CE_DockWidgetTitle:
+ if (const QStyleOptionDockWidget *dwOpt = qstyleoption_cast<const QStyleOptionDockWidget *>(option))
+ {
+ int buttonMargin = 4;
+ int mw = proxy()->pixelMetric(QStyle::PM_DockWidgetTitleMargin, dwOpt);
+ int fw = proxy()->pixelMetric(PM_DockWidgetFrameWidth, dwOpt);
+ bool isFloating = false; // widget && widget->isWindow();
+ bool isActive = dwOpt->state & State_Active;
+
+ const bool verticalTitleBar = dwOpt->verticalTitleBar;
+
+ if (verticalTitleBar) {
+ rect = rect.transposed();
+
+ p->translate(rect.left() - 1, rect.top() + rect.width());
+ p->rotate(-90);
+ p->translate(-rect.left() + 1, -rect.top());
+ }
+ QRect r = rect.adjusted(0, 2, -1, -3);
+ QRect titleRect = r;
+
+ if (dwOpt->closable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarCloseButton, dwOpt).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (dwOpt->floatable) {
+ QSize sz = proxy()->standardIcon(QStyle::SP_TitleBarMaxButton, dwOpt).actualSize(QSize(10, 10));
+ titleRect.adjust(0, 0, -sz.width() - mw - buttonMargin, 0);
+ }
+
+ if (isFloating) {
+ titleRect.adjust(0, -fw, 0, 0);
+ if (option->window && option->window->icon().cacheKey() != QApplication::windowIcon().cacheKey())
+ titleRect.adjust(titleRect.height() + mw, 0, 0, 0);
+ } else {
+ titleRect.adjust(mw, 0, 0, 0);
+ if (!dwOpt->floatable && !dwOpt->closable)
+ titleRect.adjust(0, 0, -mw, 0);
+ }
+
+ if (!verticalTitleBar)
+ titleRect = visualRect(dwOpt->direction, r, titleRect);
+
+ if (!isFloating) {
+ QPen oldPen = p->pen();
+ QString titleText = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
+ p->setPen(dwOpt->palette.color(QPalette::Dark));
+ p->drawRect(r);
+
+ if (!titleText.isEmpty()) {
+ drawItemText(p, titleRect,
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText,
+ QPalette::WindowText);
+ }
+
+ p->setPen(oldPen);
+ } else {
+ themeNumber = QWindowsXPStylePrivate::WindowTheme;
+ if (isActive)
+ stateId = CS_ACTIVE;
+ else
+ stateId = CS_INACTIVE;
+
+ int titleHeight = rect.height() - 2;
+ rect = rect.adjusted(-fw, -fw, fw, 0);
+
+ XPThemeData theme(option->window, p, themeNumber, 0, stateId);
+ if (!theme.isValid())
+ break;
+
+ // Draw small type title bar
+ theme.rect = rect;
+ theme.partId = WP_SMALLCAPTION;
+ d->drawBackground(theme);
+
+ // Figure out maximal button space on title bar
+
+ QIcon ico = option->window->icon();
+ bool hasIcon = (ico.cacheKey() != QApplication::windowIcon().cacheKey());
+ if (hasIcon) {
+ QPixmap pxIco = ico.pixmap(titleHeight);
+ if (!verticalTitleBar && dwOpt->direction == Qt::RightToLeft)
+ p->drawPixmap(rect.width() - titleHeight - pxIco.width(), rect.bottom() - titleHeight - 2, pxIco);
+ else
+ p->drawPixmap(fw, rect.bottom() - titleHeight - 2, pxIco);
+ }
+ if (!dwOpt->title.isEmpty()) {
+ QPen oldPen = p->pen();
+ QFont oldFont = p->font();
+ QFont titleFont = oldFont;
+ titleFont.setBold(true);
+ p->setFont(titleFont);
+ QString titleText
+ = p->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width());
+
+ int result = TST_NONE;
+ GetThemeEnumValue(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
+ if (result != TST_NONE) {
+ COLORREF textShadowRef;
+ GetThemeColor(theme.handle(), WP_SMALLCAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
+ QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
+ p->setPen(textShadow);
+ drawItemText(p, titleRect.adjusted(1, 1, 1, 1),
+ Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText);
+ }
+
+ COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
+ QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
+ p->setPen(textColor);
+ drawItemText(p, titleRect,
+ Qt::AlignLeft | Qt::AlignBottom, dwOpt->palette,
+ dwOpt->state & State_Enabled, titleText);
+ p->setFont(oldFont);
+ p->setPen(oldPen);
+ }
+
+ }
+
+ return;
+ }
+ break;
+#endif // QT_CONFIG(dockwidget)
+#if 0 && QT_CONFIG(rubberband)
+ case CE_RubberBand:
+ if (qstyleoption_cast<const QStyleOptionRubberBand *>(option)) {
+ QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight);
+ p->save();
+ p->setPen(highlight.darker(120));
+ QColor dimHighlight(qMin(highlight.red()/2 + 110, 255),
+ qMin(highlight.green()/2 + 110, 255),
+ qMin(highlight.blue()/2 + 110, 255),
+ 127);
+ //(widget && widget->isTopLevel())? 255 : 127);
+ p->setBrush(dimHighlight);
+ p->drawRect(option->rect.adjusted(0, 0, -1, -1));
+ p->restore();
+ return;
+ }
+ break;
+#endif // QT_CONFIG(rubberband)
+ case CE_HeaderEmptyArea:
+ if (option->state & State_Horizontal)
+ {
+ themeNumber = QWindowsXPStylePrivate::HeaderTheme;
+ stateId = HIS_NORMAL;
+ }
+ else {
+ QWindowsStyle::drawControl(CE_HeaderEmptyArea, option, p);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ XPThemeData theme(option->window, p, themeNumber, partId, stateId, rect);
+ if (!theme.isValid()) {
+ QWindowsStyle::drawControl(element, option, p);
+ return;
+ }
+
+ theme.rotate = rotate;
+ theme.mirrorHorizontally = hMirrored;
+ theme.mirrorVertically = vMirrored;
+ d->drawBackground(theme);
+}
+
+QRect QWindowsXPStylePrivate::scrollBarGripperBounds(QStyle::State flags, XPThemeData *theme)
+{
+ const bool horizontal = flags & QStyle::State_Horizontal;
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(theme->window);
+ const QMargins contentsMargin =
+ (theme->margins(theme->rect, TMT_SIZINGMARGINS) * factor).toMargins();
+ theme->partId = horizontal ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT;
+ const QSize size = (theme->size() * factor).toSize();
+
+ const int hSpace = theme->rect.width() - size.width();
+ const int vSpace = theme->rect.height() - size.height();
+ const bool sufficientSpace = (horizontal && hSpace > (contentsMargin.left() + contentsMargin.right()))
+ || vSpace > contentsMargin.top() + contentsMargin.bottom();
+ return sufficientSpace ? QRect(theme->rect.topLeft() + QPoint(hSpace, vSpace) / 2, size) : QRect();
+}
+
+#if 0 && QT_CONFIG(mdiarea)
+// Helper for drawing MDI buttons into the corner widget of QMenuBar in case a
+// QMdiSubWindow is maximized.
+static void populateMdiButtonTheme(const QStyle *proxy,
+ const QStyleOptionComplex *option,
+ QStyle::SubControl subControl, int part,
+ XPThemeData *theme)
+{
+ theme->partId = part;
+ theme->rect = proxy->subControlRect(QStyle::CC_MdiControls, option, subControl);
+ if (!option->state.testFlag(QStyle::State_Enabled))
+ theme->stateId = CBS_INACTIVE;
+ else if (option->state.testFlag(QStyle::State_Sunken) && option->activeSubControls.testFlag(subControl))
+ theme->stateId = CBS_PUSHED;
+ else if (option->state.testFlag(QStyle::State_MouseOver) && option->activeSubControls.testFlag(subControl))
+ theme->stateId = CBS_HOT;
+ else
+ theme->stateId = CBS_NORMAL;
+}
+
+// Calculate an small (max 2), empirical correction factor for scaling up
+// WP_MDICLOSEBUTTON, WP_MDIRESTOREBUTTON, WP_MDIMINBUTTON, which are too
+// small on High DPI screens (QTBUG-75927).
+qreal mdiButtonCorrectionFactor(XPThemeData &theme, const QPaintDevice *pd = nullptr)
+{
+ const auto dpr = pd ? pd->devicePixelRatioF() : qApp->devicePixelRatio();
+ const QSizeF nativeSize = QSizeF(theme.size()) / dpr;
+ const QSizeF requestedSize(theme.rect.size());
+ const auto rawFactor = qMin(requestedSize.width() / nativeSize.width(),
+ requestedSize.height() / nativeSize.height());
+ const auto factor = rawFactor >= qreal(2) ? qreal(2) : qreal(1);
+ return factor;
+}
+#endif // QT_CONFIG(mdiarea)
+
+static void populateTitleBarButtonTheme(const QStyle *proxy,
+ const QStyleOptionComplex *option,
+ QStyle::SubControl subControl,
+ bool isTitleBarActive, int part,
+ XPThemeData *theme)
+{
+ theme->rect = proxy->subControlRect(QStyle::CC_TitleBar, option, subControl);
+ theme->partId = part;
+ if (!(option->state & QStyle::State_Enabled))
+ theme->stateId = RBS_DISABLED;
+ else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_Sunken))
+ theme->stateId = RBS_PUSHED;
+ else if (option->activeSubControls == subControl && option->state.testFlag(QStyle::State_MouseOver))
+ theme->stateId = RBS_HOT;
+ else if (!isTitleBarActive)
+ theme->stateId = RBS_INACTIVE;
+ else
+ theme->stateId = RBS_NORMAL;
+}
+
+/*!
+ \reimp
+*/
+void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option,
+ QPainter *p) const
+{
+ QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
+
+ if (!QWindowsXPStylePrivate::useXP()) {
+ QWindowsStyle::drawComplexControl(cc, option, p);
+ return;
+ }
+
+ State flags = option->state;
+ SubControls sub = option->subControls;
+ QRect r = option->rect;
+
+ int partId = 0;
+ int stateId = 0;
+ if (option->window && option->window->isActive())
+ flags |= State_MouseOver;
+
+ switch (cc) {
+//#if QT_CONFIG(spinbox)
+ case CC_SpinBox:
+ if (const QStyleOptionSpinBox *sb = qstyleoption_cast<const QStyleOptionSpinBox *>(option))
+ {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::SpinTheme);
+
+ if (sb->frame && (sub & SC_SpinBoxFrame)) {
+ partId = EP_EDITTEXT;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_HasFocus)
+ stateId = ETS_FOCUSED;
+ else
+ stateId = ETS_NORMAL;
+
+ XPThemeData ftheme(option->window, p, QWindowsXPStylePrivate::EditTheme,
+ partId, stateId, r);
+ ftheme.noContent = true;
+ d->drawBackground(ftheme);
+ }
+ if (sub & SC_SpinBoxUp) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxUp);
+ partId = SPNP_UP;
+ if (!(sb->stepEnabled & QStyleOptionSpinBox::StepUpEnabled) || !(flags & State_Enabled))
+ stateId = UPS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_Sunken))
+ stateId = UPS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxUp && (sb->state & State_MouseOver))
+ stateId = UPS_HOT;
+ else
+ stateId = UPS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_SpinBoxDown) {
+ theme.rect = proxy()->subControlRect(CC_SpinBox, option, SC_SpinBoxDown);
+ partId = SPNP_DOWN;
+ if (!(sb->stepEnabled & QStyleOptionSpinBox::StepDownEnabled) || !(flags & State_Enabled))
+ stateId = DNS_DISABLED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_Sunken))
+ stateId = DNS_PRESSED;
+ else if (sb->activeSubControls == SC_SpinBoxDown && (sb->state & State_MouseOver))
+ stateId = DNS_HOT;
+ else
+ stateId = DNS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ }
+ break;
+//#endif // QT_CONFIG(spinbox)
+//#if QT_CONFIG(combobox)
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option))
+ {
+ if (cmb->editable) {
+ if (sub & SC_ComboBoxEditField) {
+ partId = EP_EDITBORDER_NOSCROLL;
+ if (!(flags & State_Enabled))
+ stateId = ETS_DISABLED;
+ else if (flags & State_MouseOver)
+ stateId = ETS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = ETS_FOCUSED;
+ else
+ stateId = ETS_NORMAL;
+
+ XPThemeData theme(option->window, p,
+ QWindowsXPStylePrivate::EditTheme,
+ partId, stateId, r);
+
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ QRect subRect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow);
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = subRect;
+ partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+
+ if (!(cmb->state & State_Enabled))
+ stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver && option->activeSubControls & SC_ComboBoxArrow)
+ stateId = CBXS_HOT;
+ else
+ stateId = CBXS_NORMAL;
+
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+
+ } else {
+ if (sub & SC_ComboBoxFrame) {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = option->rect;
+ theme.partId = CP_READONLY;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else if (cmb->state & State_Sunken || cmb->state & State_On)
+ theme.stateId = CBXS_PRESSED;
+ else if (cmb->state & State_MouseOver)
+ theme.stateId = CBXS_HOT;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ComboBoxArrow) {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::ComboboxTheme);
+ theme.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxArrow);
+ theme.partId = option->direction == Qt::RightToLeft ? CP_DROPDOWNBUTTONLEFT : CP_DROPDOWNBUTTONRIGHT;
+ if (!(cmb->state & State_Enabled))
+ theme.stateId = CBXS_DISABLED;
+ else
+ theme.stateId = CBXS_NORMAL;
+ d->drawBackground(theme);
+ }
+ if ((sub & SC_ComboBoxEditField) && (flags & State_HasFocus)) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*cmb);
+ fropt.rect = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ }
+ break;
+//#endif // QT_CONFIG(combobox)
+ case CC_ScrollBar:
+ if (const QStyleOptionSlider *scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option))
+ {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::ScrollBarTheme);
+ bool maxedOut = (scrollbar->maximum == scrollbar->minimum);
+ if (maxedOut)
+ flags &= ~State_Enabled;
+
+ bool isHorz = flags & State_Horizontal;
+ bool isRTL = option->direction == Qt::RightToLeft;
+ if (sub & SC_ScrollBarAddLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddLine);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTDISABLED : ABS_RIGHTDISABLED) : ABS_DOWNDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTPRESSED : ABS_RIGHTPRESSED) : ABS_DOWNPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_LEFTHOT : ABS_RIGHTHOT) : ABS_DOWNHOT);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL) : ABS_DOWNNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSubLine) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubLine);
+ partId = SBP_ARROWBTN;
+ if (!(flags & State_Enabled))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTDISABLED : ABS_LEFTDISABLED) : ABS_UPDISABLED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_Sunken))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTPRESSED : ABS_LEFTPRESSED) : ABS_UPPRESSED);
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubLine && (scrollbar->state & State_MouseOver))
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTHOT : ABS_LEFTHOT) : ABS_UPHOT);
+ else
+ stateId = (isHorz ? (isRTL ? ABS_RIGHTNORMAL : ABS_LEFTNORMAL) : ABS_UPNORMAL);
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (maxedOut) {
+ if (sub & SC_ScrollBarSlider) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSlider);
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage));
+ theme.rect = theme.rect.united(proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage));
+ partId = scrollbar->orientation == Qt::Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ stateId = SCRBS_DISABLED;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ } else {
+ if (sub & SC_ScrollBarSubPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarSubPage);
+ partId = flags & State_Horizontal ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSubPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarAddPage) {
+ theme.rect = proxy()->subControlRect(CC_ScrollBar, option, SC_ScrollBarAddPage);
+ partId = flags & State_Horizontal ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarAddPage && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_ScrollBarSlider) {
+ // The style paint the slider handle so that it is surrounded by transparent areas
+ // on each side. These areas have the same size as the Left/Right (or Top/Left) buttons.
+ // This is probaly done in order for the handle to travel all along the geometry
+ // of the slider, while the handle still not occluding the buttons.
+ // We do not want those transparent areas, so we clip them off here.
+ const int extentForButton = proxy()->pixelMetric(PM_ScrollBarExtent, scrollbar);
+ QSize extend(extentForButton, 0);
+ if (scrollbar->orientation == Qt::Vertical)
+ extend.transpose();
+
+ QRect rect = r; // 'r' is the rect for the scrollbar handle
+ rect.setSize(rect.size() + 2 * extend); // 'rect' is the rect for the whole scrollbar
+ p->setClipRect(r); // clip off button areas
+ p->translate(-extend.width(), -extend.height()); // translate left button area away
+
+ theme.rect = rect;
+ if (!(flags & State_Enabled))
+ stateId = SCRBS_DISABLED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_Sunken))
+ stateId = SCRBS_PRESSED;
+ else if (scrollbar->activeSubControls & SC_ScrollBarSlider && (scrollbar->state & State_MouseOver))
+ stateId = SCRBS_HOT;
+ else
+ stateId = SCRBS_NORMAL;
+
+ // Draw handle
+ theme.partId = flags & State_Horizontal ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+
+ const QRect gripperBounds = QWindowsXPStylePrivate::scrollBarGripperBounds(flags, &theme);
+ // Draw gripper if there is enough space
+ if (!gripperBounds.isEmpty()) {
+ p->save();
+ theme.rect = gripperBounds;
+ p->setClipRegion(d->region(theme));// Only change inside the region of the gripper
+ d->drawBackground(theme); // Transparent gripper ontop of background
+ p->restore();
+ }
+ }
+ }
+ }
+ break;
+
+//#if QT_CONFIG(slider)
+ case CC_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option))
+ {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::TrackBarTheme);
+ QRect slrect = slider->rect;
+ QRegion tickreg = slrect;
+ if (sub & SC_SliderGroove) {
+ theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove);
+ if (slider->orientation == Qt::Horizontal) {
+ partId = TKP_TRACK;
+ stateId = TRS_NORMAL;
+ theme.rect = QRect(slrect.left(), theme.rect.center().y() - 2, slrect.width(), 4);
+ } else {
+ partId = TKP_TRACKVERT;
+ stateId = TRVS_NORMAL;
+ theme.rect = QRect(theme.rect.center().x() - 2, slrect.top(), 4, slrect.height());
+ }
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ tickreg -= theme.rect;
+ }
+ if (sub & SC_SliderTickmarks) {
+ int tickOffset = proxy()->pixelMetric(PM_SliderTickmarkOffset, slider);
+ int ticks = slider->tickPosition;
+ int thickness = proxy()->pixelMetric(PM_SliderControlThickness, slider);
+ int len = proxy()->pixelMetric(PM_SliderLength, slider);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (!interval)
+ interval = 1;
+ int fudge = len / 2;
+ int pos;
+ int bothOffset = (ticks & QStyleOptionSlider::TicksAbove && ticks & QStyleOptionSlider::TicksBelow) ? 1 : 0;
+ p->setPen(d->sliderTickColor);
+ QVarLengthArray<QLine, 32> lines;
+ int v = slider->minimum;
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int tickLength = (v_ == slider->minimum || v_ >= slider->maximum) ? 4 : 3;
+ pos = QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, available) + fudge;
+ if (slider->orientation == Qt::Horizontal) {
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ lines.append(QLine(pos, tickOffset - 1 - bothOffset,
+ pos, tickOffset - 1 - bothOffset - tickLength));
+
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ lines.append(QLine(pos, tickOffset + thickness + bothOffset,
+ pos, tickOffset + thickness + bothOffset + tickLength));
+ } else {
+ if (ticks & QStyleOptionSlider::TicksAbove)
+ lines.append(QLine(tickOffset - 1 - bothOffset, pos,
+ tickOffset - 1 - bothOffset - tickLength, pos));
+
+ if (ticks & QStyleOptionSlider::TicksBelow)
+ lines.append(QLine(tickOffset + thickness + bothOffset, pos,
+ tickOffset + thickness + bothOffset + tickLength, pos));
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ if (!lines.isEmpty()) {
+ p->save();
+ p->translate(slrect.topLeft());
+ p->drawLines(lines.constData(), lines.size());
+ p->restore();
+ }
+ }
+ if (sub & SC_SliderHandle) {
+ theme.rect = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle);
+ if (slider->orientation == Qt::Horizontal) {
+ if (slider->tickPosition == QStyleOptionSlider::TicksAbove)
+ partId = TKP_THUMBTOP;
+ else if (slider->tickPosition == QStyleOptionSlider::TicksBelow)
+ partId = TKP_THUMBBOTTOM;
+ else
+ partId = TKP_THUMB;
+
+ if (!(slider->state & State_Enabled))
+ stateId = TUS_DISABLED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
+ stateId = TUS_PRESSED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
+ stateId = TUS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = TUS_FOCUSED;
+ else
+ stateId = TUS_NORMAL;
+ } else {
+ if (slider->tickPosition == QStyleOptionSlider::TicksLeft)
+ partId = TKP_THUMBLEFT;
+ else if (slider->tickPosition == QStyleOptionSlider::TicksRight)
+ partId = TKP_THUMBRIGHT;
+ else
+ partId = TKP_THUMBVERT;
+
+ if (!(slider->state & State_Enabled))
+ stateId = TUVS_DISABLED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_Sunken))
+ stateId = TUVS_PRESSED;
+ else if (slider->activeSubControls & SC_SliderHandle && (slider->state & State_MouseOver))
+ stateId = TUVS_HOT;
+ else if (flags & State_HasFocus)
+ stateId = TUVS_FOCUSED;
+ else
+ stateId = TUVS_NORMAL;
+ }
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ }
+ if (sub & SC_SliderGroove && slider->state & State_HasFocus) {
+ QStyleOptionFocusRect fropt;
+ fropt.QStyleOption::operator=(*slider);
+ fropt.rect = subElementRect(SE_SliderFocusRect, slider);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p);
+ }
+ }
+ break;
+//#endif
+#if 0 && QT_CONFIG(toolbutton)
+ case CC_ToolButton:
+ if (const QStyleOptionToolButton *toolbutton
+ = qstyleoption_cast<const QStyleOptionToolButton *>(option)) {
+ QRect button, menuarea;
+ button = proxy()->subControlRect(cc, toolbutton, SC_ToolButton);
+ menuarea = proxy()->subControlRect(cc, toolbutton, SC_ToolButtonMenu);
+
+ State bflags = toolbutton->state & ~State_Sunken;
+ State mflags = bflags;
+ bool autoRaise = flags & State_AutoRaise;
+ if (autoRaise) {
+ if (!(bflags & State_MouseOver) || !(bflags & State_Enabled)) {
+ bflags &= ~State_Raised;
+ }
+ }
+
+ if (toolbutton->state & State_Sunken) {
+ if (toolbutton->activeSubControls & SC_ToolButton) {
+ bflags |= State_Sunken;
+ mflags |= State_MouseOver | State_Sunken;
+ } else if (toolbutton->activeSubControls & SC_ToolButtonMenu) {
+ mflags |= State_Sunken;
+ bflags |= State_MouseOver;
+ }
+ }
+
+ QStyleOption tool = *toolbutton;
+ if (toolbutton->subControls & SC_ToolButton) {
+ if (flags & (State_Sunken | State_On | State_Raised) || !autoRaise) {
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup && autoRaise) {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::ToolBarTheme);
+ theme.partId = TP_SPLITBUTTON;
+ theme.rect = button;
+ if (!(bflags & State_Enabled))
+ stateId = TS_DISABLED;
+ else if (bflags & State_Sunken)
+ stateId = TS_PRESSED;
+ else if (bflags & State_MouseOver || !(flags & State_AutoRaise))
+ stateId = flags & State_On ? TS_HOTCHECKED : TS_HOT;
+ else if (bflags & State_On)
+ stateId = TS_CHECKED;
+ else
+ stateId = TS_NORMAL;
+ if (option->direction == Qt::RightToLeft)
+ theme.mirrorHorizontally = true;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+ } else {
+ tool.rect = option->rect;
+ tool.state = bflags;
+ if (autoRaise) // for tool bars
+ proxy()->drawPrimitive(PE_PanelButtonTool, &tool, p);
+ else
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, p);
+ }
+ }
+ }
+
+ if (toolbutton->state & State_HasFocus) {
+ QStyleOptionFocusRect fr;
+ fr.QStyleOption::operator=(*toolbutton);
+ fr.rect.adjust(3, 3, -3, -3);
+ if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup)
+ fr.rect.adjust(0, 0, -proxy()->pixelMetric(QStyle::PM_MenuButtonIndicator,
+ toolbutton), 0);
+ proxy()->drawPrimitive(PE_FrameFocusRect, &fr, p);
+ }
+ QStyleOptionToolButton label = *toolbutton;
+ label.state = bflags;
+ int fw = 2;
+ if (!autoRaise)
+ label.state &= ~State_Sunken;
+ label.rect = button.adjusted(fw, fw, -fw, -fw);
+ proxy()->drawControl(CE_ToolButtonLabel, &label, p);
+
+ if (toolbutton->subControls & SC_ToolButtonMenu) {
+ tool.rect = menuarea;
+ tool.state = mflags;
+ if (autoRaise) {
+ proxy()->drawPrimitive(PE_IndicatorButtonDropDown, &tool, p);
+ } else {
+ tool.state = mflags;
+ menuarea.adjust(-2, 0, 0, 0);
+ // Draw menu button
+ if ((bflags & State_Sunken) != (mflags & State_Sunken)){
+ p->save();
+ p->setClipRect(menuarea);
+ tool.rect = option->rect;
+ proxy()->drawPrimitive(PE_PanelButtonBevel, &tool, p);
+ p->restore();
+ }
+ // Draw arrow
+ p->save();
+ p->setPen(option->palette.dark().color());
+ p->drawLine(menuarea.left(), menuarea.top() + 3,
+ menuarea.left(), menuarea.bottom() - 3);
+ p->setPen(option->palette.light().color());
+ p->drawLine(menuarea.left() - 1, menuarea.top() + 3,
+ menuarea.left() - 1, menuarea.bottom() - 3);
+
+ tool.rect = menuarea.adjusted(2, 3, -2, -1);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &tool, p);
+ p->restore();
+ }
+ } else if (toolbutton->features & QStyleOptionToolButton::HasMenu) {
+ int mbi = proxy()->pixelMetric(PM_MenuButtonIndicator, toolbutton);
+ QRect ir = toolbutton->rect;
+ QStyleOptionToolButton newBtn = *toolbutton;
+ newBtn.rect = QRect(ir.right() + 4 - mbi, ir.height() - mbi + 4, mbi - 5, mbi - 5);
+ proxy()->drawPrimitive(PE_IndicatorArrowDown, &newBtn, p);
+ }
+ }
+ break;
+#endif // QT_CONFIG(toolbutton)
+
+ case CC_TitleBar:
+ {
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option))
+ {
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(option);
+ bool isActive = tb->titleBarState & QStyle::State_Active;
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::WindowTheme);
+ if (sub & SC_TitleBarLabel) {
+
+ partId = (tb->titleBarState & Qt::WindowMinimized) ? WP_MINCAPTION : WP_CAPTION;
+ theme.rect = option->rect;
+ if (!(option->state & QStyle::State_Enabled))
+ stateId = CS_DISABLED;
+ else if (isActive)
+ stateId = CS_ACTIVE;
+ else
+ stateId = CS_INACTIVE;
+
+ theme.partId = partId;
+ theme.stateId = stateId;
+ d->drawBackground(theme);
+
+ QRect ir = proxy()->subControlRect(CC_TitleBar, tb, SC_TitleBarLabel);
+
+ int result = TST_NONE;
+ GetThemeEnumValue(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWTYPE, &result);
+ if (result != TST_NONE) {
+ COLORREF textShadowRef;
+ GetThemeColor(theme.handle(), WP_CAPTION, isActive ? CS_ACTIVE : CS_INACTIVE, TMT_TEXTSHADOWCOLOR, &textShadowRef);
+ QColor textShadow = qRgb(GetRValue(textShadowRef), GetGValue(textShadowRef), GetBValue(textShadowRef));
+ p->setPen(textShadow);
+ p->drawText(int(ir.x() + 3 * factor), int(ir.y() + 2 * factor),
+ int(ir.width() - 1 * factor), ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
+ }
+ COLORREF captionText = GetSysColor(isActive ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT);
+ QColor textColor = qRgb(GetRValue(captionText), GetGValue(captionText), GetBValue(captionText));
+ p->setPen(textColor);
+ p->drawText(int(ir.x() + 2 * factor), int(ir.y() + 1 * factor),
+ int(ir.width() - 2 * factor), ir.height(),
+ Qt::AlignLeft | Qt::AlignVCenter | Qt::TextSingleLine, tb->text);
+ }
+ if (sub & SC_TitleBarSysMenu && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ theme.rect = proxy()->subControlRect(CC_TitleBar, option, SC_TitleBarSysMenu);
+ partId = WP_SYSBUTTON;
+ if (!(option->state & QStyle::State_Enabled) || !isActive)
+ stateId = SBS_DISABLED;
+ else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_Sunken))
+ stateId = SBS_PUSHED;
+ else if (option->activeSubControls == SC_TitleBarSysMenu && (option->state & State_MouseOver))
+ stateId = SBS_HOT;
+ else
+ stateId = SBS_NORMAL;
+ if (!tb->icon.isNull()) {
+ tb->icon.paint(p, theme.rect);
+ } else {
+ theme.partId = partId;
+ theme.stateId = stateId;
+ if (theme.size().isEmpty()) {
+ int iconSize = proxy()->pixelMetric(PM_SmallIconSize, tb);
+ QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, tb).pixmap(iconSize, iconSize);
+ p->save();
+ drawItemPixmap(p, theme.rect, Qt::AlignCenter, pm);
+ p->restore();
+ } else {
+ d->drawBackground(theme);
+ }
+ }
+ }
+
+ if (sub & SC_TitleBarMinButton && tb->titleBarFlags & Qt::WindowMinimizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarMinButton, isActive, WP_MINBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarMaxButton && tb->titleBarFlags & Qt::WindowMaximizeButtonHint
+ && !(tb->titleBarState & Qt::WindowMaximized)) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarMaxButton, isActive, WP_MAXBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarContextHelpButton
+ && tb->titleBarFlags & Qt::WindowContextHelpButtonHint) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarContextHelpButton, isActive, WP_HELPBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ bool drawNormalButton = (sub & SC_TitleBarNormalButton)
+ && (((tb->titleBarFlags & Qt::WindowMinimizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMinimized))
+ || ((tb->titleBarFlags & Qt::WindowMaximizeButtonHint)
+ && (tb->titleBarState & Qt::WindowMaximized)));
+ if (drawNormalButton) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarNormalButton, isActive, WP_RESTOREBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarShadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && !(tb->titleBarState & Qt::WindowMinimized)) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarShadeButton, isActive, WP_MINBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarUnshadeButton && tb->titleBarFlags & Qt::WindowShadeButtonHint
+ && tb->titleBarState & Qt::WindowMinimized) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarUnshadeButton, isActive, WP_RESTOREBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ if (sub & SC_TitleBarCloseButton && tb->titleBarFlags & Qt::WindowSystemMenuHint) {
+ populateTitleBarButtonTheme(proxy(), option, SC_TitleBarCloseButton, isActive, WP_CLOSEBUTTON, &theme);
+ d->drawBackground(theme);
+ }
+ }
+ }
+ break;
+
+#if 0 && QT_CONFIG(mdiarea)
+ case CC_MdiControls:
+ {
+ XPThemeData theme(option->window, p, QWindowsXPStylePrivate::WindowTheme, WP_MDICLOSEBUTTON, CBS_NORMAL);
+ if (Q_UNLIKELY(!theme.isValid()))
+ return;
+
+ if (option->subControls.testFlag(SC_MdiCloseButton)) {
+ populateMdiButtonTheme(proxy(), option, SC_MdiCloseButton, WP_MDICLOSEBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme));
+ }
+ if (option->subControls.testFlag(SC_MdiNormalButton)) {
+ populateMdiButtonTheme(proxy(), option, SC_MdiNormalButton, WP_MDIRESTOREBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme));
+ }
+ if (option->subControls.testFlag(QStyle::SC_MdiMinButton)) {
+ populateMdiButtonTheme(proxy(), option, SC_MdiMinButton, WP_MDIMINBUTTON, &theme);
+ d->drawBackground(theme, mdiButtonCorrectionFactor(theme));
+ }
+ }
+ break;
+#endif // QT_CONFIG(mdiarea)
+#if 0 && QT_CONFIG(dial)
+ case CC_Dial:
+ if (const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(option))
+ QStyleHelper::drawDial(dial, p);
+ break;
+#endif // QT_CONFIG(dial)
+ default:
+ QWindowsStyle::drawComplexControl(cc, option, p);
+ break;
+ }
+}
+
+static inline Qt::Orientation progressBarOrientation(const QStyleOption *option = nullptr)
+{
+ if (const QStyleOptionProgressBar *pb = qstyleoption_cast<const QStyleOptionProgressBar *>(option))
+ return pb->state & QStyle::State_Horizontal ? Qt::Horizontal : Qt::Vertical;
+ return Qt::Horizontal;
+}
+
+int QWindowsXPStylePrivate::pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option)
+{
+ switch (pm) {
+ case QStyle::PM_IndicatorWidth:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).width();
+ case QStyle::PM_IndicatorHeight:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_CHECKBOX, CBS_UNCHECKEDNORMAL).height();
+ case QStyle::PM_ExclusiveIndicatorWidth:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).width();
+ case QStyle::PM_ExclusiveIndicatorHeight:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_RADIOBUTTON, RBS_UNCHECKEDNORMAL).height();
+ case QStyle::PM_ProgressBarChunkWidth:
+ return progressBarOrientation(option) == Qt::Horizontal
+ ? XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ProgressTheme, PP_CHUNK).width()
+ : XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::ProgressTheme, PP_CHUNKVERT).height();
+ case QStyle::PM_SliderThickness:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::TrackBarTheme, TKP_THUMB).height();
+ case QStyle::PM_TitleBarHeight:
+ return option->window && (option->window->type() == Qt::Tool)
+ ? GetSystemMetrics(SM_CYSMCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME)
+ : GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CXSIZEFRAME);
+ case QStyle::PM_MdiSubWindowFrameWidth:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_FRAMELEFT, FS_ACTIVE).width();
+ case QStyle::PM_DockWidgetFrameWidth:
+ return XPThemeData::themeSize(option->window, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_SMALLFRAMERIGHT, FS_ACTIVE).width();
+ default:
+ break;
+ }
+ return QWindowsXPStylePrivate::InvalidMetric;
+}
+
+/*! \reimp */
+int QWindowsXPStyle::pixelMetric(PixelMetric pm, const QStyleOption *option) const
+{
+ if (!QWindowsXPStylePrivate::useXP())
+ return QWindowsStyle::pixelMetric(pm, option);
+
+ int res = QWindowsXPStylePrivate::pixelMetricFromSystemDp(pm, option);
+ if (res != QWindowsStylePrivate::InvalidMetric)
+ return qRound(qreal(res) * QWindowsStylePrivate::nativeMetricScaleFactor(option));
+
+ res = 0;
+ switch (pm) {
+ case PM_MenuBarPanelWidth:
+ case PM_ButtonDefaultIndicator:
+ res = 0;
+ break;
+
+ case PM_DefaultFrameWidth:
+ res = 1;
+ //res = qobject_cast<const QListView*>(widget) ? 2 : 1;
+ break;
+ case PM_MenuPanelWidth:
+ case PM_SpinBoxFrameWidth:
+ res = 1;
+ break;
+
+ case PM_TabBarTabOverlap:
+ case PM_MenuHMargin:
+ case PM_MenuVMargin:
+ res = 2;
+ break;
+#if 0
+ case PM_TabBarBaseOverlap:
+ if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(option)) {
+ switch (tab->shape) {
+ case QTabBar::RoundedNorth:
+ case QTabBar::TriangularNorth:
+ case QTabBar::RoundedWest:
+ case QTabBar::TriangularWest:
+ res = 1;
+ break;
+ case QTabBar::RoundedSouth:
+ case QTabBar::TriangularSouth:
+ res = 2;
+ break;
+ case QTabBar::RoundedEast:
+ case QTabBar::TriangularEast:
+ res = 3;
+ break;
+ }
+ }
+ break;
+#endif
+ case PM_SplitterWidth:
+ res = QStyleHelper::dpiScaled(5., option);
+ break;
+
+ case PM_MdiSubWindowMinimizedWidth:
+ res = 160;
+ break;
+
+#if 0 && QT_CONFIG(toolbar)
+ case PM_ToolBarHandleExtent:
+ res = int(QStyleHelper::dpiScaled(8., option));
+ break;
+
+#endif // QT_CONFIG(toolbar)
+ case PM_DockWidgetSeparatorExtent:
+ case PM_DockWidgetTitleMargin:
+ res = int(QStyleHelper::dpiScaled(4., option));
+ break;
+
+ case PM_ButtonShiftHorizontal:
+ case PM_ButtonShiftVertical:
+ res = qstyleoption_cast<const QStyleOptionToolButton *>(option) ? 1 : 0;
+ break;
+
+ default:
+ res = QWindowsStyle::pixelMetric(pm, option);
+ }
+
+ return res;
+}
+
+/*
+ This function is used by subControlRect to check if a button
+ should be drawn for the given subControl given a set of window flags.
+*/
+static bool buttonVisible(const QStyle::SubControl sc, const QStyleOptionTitleBar *tb){
+
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+ const uint flags = tb->titleBarFlags;
+ bool retVal = false;
+ switch (sc) {
+ case QStyle::SC_TitleBarContextHelpButton:
+ if (flags & Qt::WindowContextHelpButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMinButton:
+ if (!isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarNormalButton:
+ if (isMinimized && (flags & Qt::WindowMinimizeButtonHint))
+ retVal = true;
+ else if (isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarMaxButton:
+ if (!isMaximized && (flags & Qt::WindowMaximizeButtonHint))
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarShadeButton:
+ if (!isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarUnshadeButton:
+ if (isMinimized && flags & Qt::WindowShadeButtonHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarCloseButton:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ case QStyle::SC_TitleBarSysMenu:
+ if (flags & Qt::WindowSystemMenuHint)
+ retVal = true;
+ break;
+ default :
+ retVal = true;
+ }
+ return retVal;
+}
+
+/*!
+ \reimp
+*/
+QRect QWindowsXPStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *option,
+ SubControl subControl) const
+{
+ if (!QWindowsXPStylePrivate::useXP())
+ return QWindowsStyle::subControlRect(cc, option, subControl);
+
+ QRect rect;
+
+ switch (cc) {
+ case CC_GroupBox:
+ rect = visualRect(option->direction, option->rect,
+ QWindowsStyle::subControlRect(cc, option, subControl));
+ if (subControl == QStyle::SC_GroupBoxContents) {
+ // This will add the margins that was added by QLayouts in QtWidgets
+ // (default to 9 for layouts inside a QGroupBox)
+ rect.adjust(9, 9, -9, -9);
+ }
+ break;
+ case CC_TitleBar:
+ if (const QStyleOptionTitleBar *tb = qstyleoption_cast<const QStyleOptionTitleBar *>(option)) {
+ if (!buttonVisible(subControl, tb))
+ return rect;
+ const bool isToolTitle = false;
+ const int height = tb->rect.height();
+ const int width = tb->rect.width();
+ const int buttonMargin = int(QStyleHelper::dpiScaled(4, option));
+ const qreal factor = QWindowsStylePrivate::nativeMetricScaleFactor(option);
+ int buttonHeight = qRound(qreal(GetSystemMetrics(SM_CYSIZE)) * factor)
+ - buttonMargin;
+ int buttonWidth = qRound(qreal(GetSystemMetrics(SM_CXSIZE)) * factor)
+ - buttonMargin;
+ const int delta = buttonWidth + 2;
+ int controlTop = option->rect.bottom() - buttonHeight - 2;
+ const int frameWidth = proxy()->pixelMetric(PM_MdiSubWindowFrameWidth, option);
+ const bool sysmenuHint = (tb->titleBarFlags & Qt::WindowSystemMenuHint) != 0;
+ const bool minimizeHint = (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) != 0;
+ const bool maximizeHint = (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) != 0;
+ const bool contextHint = (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) != 0;
+ const bool shadeHint = (tb->titleBarFlags & Qt::WindowShadeButtonHint) != 0;
+ bool isMinimized = tb->titleBarState & Qt::WindowMinimized;
+ bool isMaximized = tb->titleBarState & Qt::WindowMaximized;
+ int offset = 0;
+
+ switch (subControl) {
+ case SC_TitleBarLabel:
+ rect = QRect(frameWidth, 0, width - (buttonWidth + frameWidth + 10), height);
+ if (isToolTitle) {
+ if (sysmenuHint) {
+ rect.adjust(0, 0, -buttonWidth - 3, 0);
+ }
+ if (minimizeHint || maximizeHint)
+ rect.adjust(0, 0, -buttonWidth - 2, 0);
+ } else {
+ if (sysmenuHint) {
+ const int leftOffset = height - 8;
+ rect.adjust(leftOffset, 0, 0, 0);
+ }
+ if (minimizeHint)
+ rect.adjust(0, 0, -buttonWidth - 2, 0);
+ if (maximizeHint)
+ rect.adjust(0, 0, -buttonWidth - 2, 0);
+ if (contextHint)
+ rect.adjust(0, 0, -buttonWidth - 2, 0);
+ if (shadeHint)
+ rect.adjust(0, 0, -buttonWidth - 2, 0);
+ }
+ break;
+
+ case SC_TitleBarContextHelpButton:
+ if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint)
+ offset += delta;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMinButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarMinButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarNormalButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint))
+ offset += delta;
+ else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarNormalButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarMaxButton:
+ if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarMaxButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarShadeButton:
+ if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarShadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarUnshadeButton:
+ if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint))
+ offset += delta;
+ else if (subControl == SC_TitleBarUnshadeButton)
+ break;
+ Q_FALLTHROUGH();
+ case SC_TitleBarCloseButton:
+ if (tb->titleBarFlags & Qt::WindowSystemMenuHint)
+ offset += delta;
+ else if (subControl == SC_TitleBarCloseButton)
+ break;
+
+ rect.setRect(width - offset - controlTop + 1, controlTop,
+ buttonWidth, buttonHeight);
+ break;
+
+ case SC_TitleBarSysMenu:
+ {
+ const int controlTop = 6;
+ const int controlHeight = height - controlTop - 3;
+ const int iconExtent = proxy()->pixelMetric(PM_SmallIconSize, option);
+ QSize iconSize = tb->icon.actualSize(QSize(iconExtent, iconExtent));
+ if (tb->icon.isNull())
+ iconSize = QSize(controlHeight, controlHeight);
+ int hPad = (controlHeight - iconSize.height())/2;
+ int vPad = (controlHeight - iconSize.width())/2;
+ rect = QRect(frameWidth + hPad, controlTop + vPad, iconSize.width(), iconSize.height());
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case CC_ComboBox:
+ if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) {
+ const int x = cmb->rect.x(), y = cmb->rect.y(), wi = cmb->rect.width(), he = cmb->rect.height();
+ const int xpos = x + wi - qRound(QStyleHelper::dpiScaled(1 + 16, option));
+
+ switch (subControl) {
+ case SC_ComboBoxFrame:
+ rect = cmb->rect;
+ break;
+
+ case SC_ComboBoxArrow: {
+ const qreal dpi = QStyleHelper::dpi(option);
+ rect = QRect(xpos, y + qRound(QStyleHelper::dpiScaled(1, dpi)),
+ qRound(QStyleHelper::dpiScaled(16, dpi)),
+ he - qRound(QStyleHelper::dpiScaled(2, dpi)));
+ }
+ break;
+
+ case SC_ComboBoxEditField: {
+ const qreal dpi = QStyleHelper::dpi(option);
+ const int frame = qRound(QStyleHelper::dpiScaled(2, dpi));
+ rect = QRect(x + frame, y + frame,
+ wi - qRound(QStyleHelper::dpiScaled(3 + 16, dpi)),
+ he - qRound(QStyleHelper::dpiScaled(4, dpi)));
+ }
+ break;
+
+ case SC_ComboBoxListBoxPopup:
+ rect = cmb->rect;
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+#if 0 && QT_CONFIG(mdiarea)
+ case CC_MdiControls:
+ {
+ int numSubControls = 0;
+ if (option->subControls & SC_MdiCloseButton)
+ ++numSubControls;
+ if (option->subControls & SC_MdiMinButton)
+ ++numSubControls;
+ if (option->subControls & SC_MdiNormalButton)
+ ++numSubControls;
+ if (numSubControls == 0)
+ break;
+
+ int buttonWidth = option->rect.width() / numSubControls;
+ int offset = 0;
+ switch (subControl) {
+ case SC_MdiCloseButton:
+ // Only one sub control, no offset needed.
+ if (numSubControls == 1)
+ break;
+ offset += buttonWidth;
+ Q_FALLTHROUGH();
+ case SC_MdiNormalButton:
+ // No offset needed if
+ // 1) There's only one sub control
+ // 2) We have a close button and a normal button (offset already added in SC_MdiClose)
+ if (numSubControls == 1 || (numSubControls == 2 && !(option->subControls & SC_MdiMinButton)))
+ break;
+ if (option->subControls & SC_MdiNormalButton)
+ offset += buttonWidth;
+ break;
+ default:
+ break;
+ }
+ rect = QRect(offset, 0, buttonWidth, option->rect.height());
+ break;
+ }
+#endif // QT_CONFIG(mdiarea)
+
+ default:
+ rect = visualRect(option->direction, option->rect,
+ QWindowsStyle::subControlRect(cc, option, subControl));
+ break;
+ }
+ return visualRect(option->direction, option->rect, rect);
+}
+
+/*!
+ \reimp
+*/
+QSize QWindowsXPStyle::sizeFromContents(ContentsType ct, const QStyleOption *option,
+ const QSize &contentsSize) const
+{
+ if (!QWindowsXPStylePrivate::useXP())
+ return QWindowsStyle::sizeFromContents(ct, option, contentsSize);
+
+ QSize sz(contentsSize);
+ switch (ct) {
+ case CT_LineEdit:
+ case CT_ComboBox:
+ {
+ if (contentsSize.isEmpty()) {
+ // Minimum size
+ return QSize(20, 20);
+ }
+ XPThemeData buttontheme(option->window, nullptr, QWindowsXPStylePrivate::ButtonTheme, BP_PUSHBUTTON, PBS_NORMAL);
+ if (buttontheme.isValid()) {
+ const QMarginsF borderSize = buttontheme.margins();
+ if (!borderSize.isNull()) {
+ const qreal margin = qreal(2);
+ sz.rwidth() += qRound(borderSize.left() + borderSize.right() - margin);
+ sz.rheight() += int(borderSize.bottom() + borderSize.top() - margin);
+ }
+ const int textMargins = 2*(proxy()->pixelMetric(PM_FocusFrameHMargin, option) + 1);
+ sz += QSize(qMax(pixelMetric(QStyle::PM_ScrollBarExtent, option)
+ + textMargins, 23), 0); //arrow button
+ }
+ }
+ break;
+ case CT_TabWidget:
+ sz += QSize(6, 6);
+ break;
+ case CT_Menu:
+ sz += QSize(1, 0);
+ break;
+#if 0 && QT_CONFIG(menubar)
+ case CT_MenuBarItem:
+ if (!sz.isEmpty())
+ sz += QSize(windowsItemHMargin * 5 + 1, 6);
+ break;
+#endif
+ case CT_MenuItem:
+ if (const QStyleOptionMenuItem *menuitem = qstyleoption_cast<const QStyleOptionMenuItem *>(option))
+ {
+ if (menuitem->menuItemType != QStyleOptionMenuItem::Separator) {
+ sz = QWindowsStyle::sizeFromContents(ct, option, sz);
+ sz.setHeight(sz.height() - 2);
+ return sz;
+ }
+ }
+ sz = QWindowsStyle::sizeFromContents(ct, option, sz);
+ break;
+
+ case CT_MdiControls: {
+ sz.setHeight(int(QStyleHelper::dpiScaled(19, option)));
+ int width = 54;
+ if (const QStyleOptionComplex *styleOpt = qstyleoption_cast<const QStyleOptionComplex *>(option)) {
+ width = 0;
+ if (styleOpt->subControls & SC_MdiMinButton)
+ width += 17 + 1;
+ if (styleOpt->subControls & SC_MdiNormalButton)
+ width += 17 + 1;
+ if (styleOpt->subControls & SC_MdiCloseButton)
+ width += 17 + 1;
+ }
+ sz.setWidth(int(QStyleHelper::dpiScaled(width, option)));
+ }
+ break;
+
+ case CT_Slider:
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QStyle::SubControls sub = slider->subControls;
+ const int TickSpace = 5;
+ int thick = proxy()->pixelMetric(QStyle::PM_SliderThickness, slider);
+
+ if (slider->tickPosition & QStyleOptionSlider::TicksAbove)
+ thick += TickSpace;
+ if (slider->tickPosition & QStyleOptionSlider::TicksBelow)
+ thick += TickSpace;
+ sz.setWidth(thick);
+
+ if (sub & SC_SliderGroove) {
+ const int SliderLength = 84;
+ sz.setHeight(SliderLength);
+ }
+ if (slider->orientation == Qt::Horizontal)
+ sz.transpose();
+ if (sub & SC_SliderHandle) {
+ const QSize s = proxy()->subControlRect(CC_Slider, slider, SC_SliderHandle).size();
+ sz = sz.expandedTo(s);
+ }
+ }
+ break;
+ case CT_ScrollBar :
+ // Make sure that the scroll bar is large enough to display the thumb indicator.
+ if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ const int scrollBarHeight = proxy()->pixelMetric(QStyle::PM_ScrollBarExtent, slider);
+ const int scrollBarSliderMin = proxy()->pixelMetric(QStyle::PM_ScrollBarSliderMin, slider);
+ int &szw = slider->orientation == Qt::Horizontal ? sz.rwidth() : sz.rheight();
+ int &szh = slider->orientation == Qt::Horizontal ? sz.rheight() : sz.rwidth();
+ if (slider->subControls & SC_ScrollBarSlider) {
+ szw = qMax(szw, scrollBarSliderMin);
+ szh = scrollBarHeight;
+ } else if (slider->subControls & SC_ScrollBarGroove) {
+ szw = qMax(szw, scrollBarSliderMin + 2 * scrollBarHeight);
+ szh = scrollBarHeight;
+ } else if (slider->subControls & (SC_ScrollBarAddLine| SC_ScrollBarSubLine)) {
+ // Assume that the AddLine and SubLine buttons have the same size, and just query
+ // for the size of AddLine
+ const int sbextent = proxy()->pixelMetric(PM_ScrollBarExtent, slider);
+ szw = qMax(szw, sbextent);
+ szh = scrollBarHeight;
+ }
+ }
+ break;
+ default:
+ sz = QWindowsStyle::sizeFromContents(ct, option, sz);
+ break;
+ }
+
+ return sz;
+}
+
+
+/*! \reimp */
+int QWindowsXPStyle::styleHint(StyleHint hint, const QStyleOption *option,
+ QStyleHintReturn *returnData) const
+{
+ QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
+ if (!QWindowsXPStylePrivate::useXP())
+ return QWindowsStyle::styleHint(hint, option, returnData);
+
+ int res = 0;
+ switch (hint) {
+
+ case SH_EtchDisabledText:
+ //res = (qobject_cast<const QLabel*>(widget) != 0);
+ res = 0;
+ break;
+
+ case SH_SpinControls_DisableOnBounds:
+ res = 0;
+ break;
+
+ case SH_TitleBar_AutoRaise:
+ case SH_TitleBar_NoBorder:
+ res = 1;
+ break;
+
+ case SH_GroupBox_TextLabelColor:
+ if (option->state & QStyle::State_Enabled)
+ res = d->groupBoxTextColor;
+ else
+ res = d->groupBoxTextColorDisabled;
+ break;
+
+ case SH_Table_GridLineColor:
+ res = 0xC0C0C0;
+ break;
+
+ case SH_WindowFrame_Mask:
+ {
+ res = 1;
+ QStyleHintReturnMask *mask = qstyleoption_cast<QStyleHintReturnMask *>(returnData);
+ const QStyleOptionTitleBar *titlebar = qstyleoption_cast<const QStyleOptionTitleBar *>(option);
+ if (mask && titlebar) {
+ // Note certain themes will not return the whole window frame but only the titlebar part when
+ // queried This function needs to return the entire window mask, hence we will only fetch the mask for the
+ // titlebar itself and add the remaining part of the window rect at the bottom.
+ int tbHeight = proxy()->pixelMetric(PM_TitleBarHeight, option);
+ QRect titleBarRect = option->rect;
+ titleBarRect.setHeight(tbHeight);
+ XPThemeData themeData;
+ if (titlebar->titleBarState & Qt::WindowMinimized) {
+ themeData = XPThemeData(option->window, nullptr,
+ QWindowsXPStylePrivate::WindowTheme,
+ WP_MINCAPTION, CS_ACTIVE, titleBarRect);
+ } else {
+ themeData = XPThemeData(option->window, nullptr,
+ QWindowsXPStylePrivate::WindowTheme,
+ WP_CAPTION, CS_ACTIVE, titleBarRect);
+ }
+ mask->region = d->region(themeData) +
+ QRect(0, tbHeight, option->rect.width(), option->rect.height() - tbHeight);
+ }
+ }
+ break;
+#if 0 && QT_CONFIG(rubberband)
+ case SH_RubberBand_Mask:
+ if (qstyleoption_cast<const QStyleOptionRubberBand *>(option))
+ res = 0;
+ break;
+#endif // QT_CONFIG(rubberband)
+
+ case SH_ItemView_DrawDelegateFrame:
+ res = 1;
+ break;
+
+ default:
+ res =QWindowsStyle::styleHint(hint, option, returnData);
+ }
+
+ return res;
+}
+
+QMargins QWindowsXPStyle::ninePatchMargins(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const
+{
+ QMargins margins;
+
+ switch (cc) {
+ case CC_ScrollBar: {
+ margins = QWindowsStyle::ninePatchMargins(cc, opt, imageSize);
+ if (const auto option = qstyleoption_cast<const QStyleOptionSlider *>(opt)) {
+ if (option->orientation == Qt::Horizontal) {
+ margins.setTop(-1);
+ margins.setBottom(-1);
+ } else {
+ margins.setLeft(-1);
+ margins.setRight(-1);
+ }
+ }
+ break; }
+ default:
+ margins = QWindowsStyle::ninePatchMargins(cc, opt, imageSize);
+ break;
+ }
+
+ return margins;
+}
+
+
+/*! \reimp */
+QPalette QWindowsXPStyle::standardPalette() const
+{
+ return QWindowsXPStylePrivate::useXP() ? QPalette() : QWindowsStyle::standardPalette();
+}
+
+/*!
+ \reimp
+*/
+QPixmap QWindowsXPStyle::standardPixmap(StandardPixmap standardPixmap, const QStyleOption *option) const
+{
+ if (!QWindowsXPStylePrivate::useXP())
+ return QWindowsStyle::standardPixmap(standardPixmap, option);
+
+#if 0
+ switch (standardPixmap) {
+ case SP_TitleBarMaxButton:
+ case SP_TitleBarCloseButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
+ {
+ if (widget && widget->isWindow()) {
+ XPThemeData theme(widget, nullptr, QWindowsXPStylePrivate::WindowTheme, WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ return QIcon(QWindowsStyle::standardPixmap(standardPixmap, option, widget)).pixmap(size);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ return QWindowsStyle::standardPixmap(standardPixmap, option);
+}
+
+/*!
+ \reimp
+*/
+QIcon QWindowsXPStyle::standardIcon(StandardPixmap standardIcon,
+ const QStyleOption *option) const
+{
+ if (!QWindowsXPStylePrivate::useXP()) {
+ return QWindowsStyle::standardIcon(standardIcon, option);
+ }
+#if 0
+ QWindowsXPStylePrivate *d = const_cast<QWindowsXPStylePrivate*>(d_func());
+ switch (standardIcon) {
+ case SP_TitleBarMaxButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
+ {
+ if (d->dockFloat.isNull()) {
+ XPThemeData themeSize(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
+ WP_MAXBUTTON, MAXBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_HOT;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = MAXBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockFloat;
+
+ }
+ break;
+ case SP_TitleBarCloseButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
+ {
+ if (d->dockClose.isNull()) {
+ XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (theme.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.partId = WP_CLOSEBUTTON; // ####
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_HOT;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = CBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockClose.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockClose;
+ }
+ break;
+ case SP_TitleBarNormalButton:
+ if (qstyleoption_cast<const QStyleOptionDockWidget *>(option))
+ {
+ if (d->dockFloat.isNull()) {
+ XPThemeData themeSize(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
+ WP_SMALLCLOSEBUTTON, CBS_NORMAL);
+ XPThemeData theme(nullptr, nullptr, QWindowsXPStylePrivate::WindowTheme,
+ WP_RESTOREBUTTON, RBS_NORMAL);
+ if (theme.isValid()) {
+ const QSize size = (themeSize.size() * QWindowsStylePrivate::nativeMetricScaleFactor(option)).toSize();
+ QPixmap pm(size);
+ pm.fill(Qt::transparent);
+ QPainter p(&pm);
+ theme.painter = &p;
+ theme.rect = QRect(QPoint(0, 0), size);
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::Off); // Normal
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_PUSHED;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Normal, QIcon::On); // Pressed
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_HOT;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Active, QIcon::Off); // Hover
+ pm.fill(Qt::transparent);
+ theme.stateId = RBS_INACTIVE;
+ d->drawBackground(theme);
+ d->dockFloat.addPixmap(pm, QIcon::Disabled, QIcon::Off); // Disabled
+ }
+ }
+ if (widget && widget->isWindow())
+ return d->dockFloat;
+
+ }
+ break;
+ default:
+ break;
+ }
+#endif
+ return QWindowsStyle::standardIcon(standardIcon, option);
+}
+
+/*!
+ \internal
+
+ Constructs a QWindowsXPStyle object.
+*/
+QWindowsXPStyle::QWindowsXPStyle(QWindowsXPStylePrivate &dd) : QWindowsStyle(dd)
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const XPThemeData &t)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "XPThemeData(" << t.window << ", theme=#" << t.theme << ", " << t.htheme
+ << ", partId=" << t.partId << ", stateId=" << t.stateId << ", rect=" << t.rect
+ << ", mirrorHorizontally=" << t.mirrorHorizontally << ", mirrorVertically="
+ << t.mirrorVertically << ", noBorder=" << t.noBorder << ", noContent=" << t.noContent
+ << ", rotate=" << t.rotate << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const ThemeMapKey &k)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "ThemeMapKey(theme=#" << k.theme
+ << ", partId=" << k.partId << ", stateId=" << k.stateId
+ << ", noBorder=" << k.noBorder << ", noContent=" << k.noContent << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const ThemeMapData &td)
+{
+ QDebugStateSaver saver(d);
+ d.nospace();
+ d << "ThemeMapData(alphaType=" << td.alphaType
+ << ", dataValid=" << td.dataValid << ", partIsTransparent=" << td.partIsTransparent
+ << ", hasAlphaChannel=" << td.hasAlphaChannel << ", wasAlphaSwapped=" << td.wasAlphaSwapped
+ << ", hadInvalidAlpha=" << td.hadInvalidAlpha << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+// Debugging code ---------------------------------------------------------------------[ START ]---
+// The code for this point on is not compiled by default, but only used as assisting
+// debugging code when you uncomment the DEBUG_XP_STYLE define at the top of the file.
+
+#ifdef DEBUG_XP_STYLE
+// The schema file expects these to be defined by the user.
+#define TMT_ENUMDEF 8
+#define TMT_ENUMVAL TEXT('A')
+#define TMT_ENUM TEXT('B')
+#define SCHEMA_STRINGS // For 2nd pass on schema file
+QT_BEGIN_INCLUDE_NAMESPACE
+#include <tmschema.h>
+QT_END_INCLUDE_NAMESPACE
+
+// A property's value, type and name combo
+struct PropPair {
+ int propValue;
+ int propType;
+ LPCWSTR propName;
+};
+
+// Operator for sorting of PropPairs
+bool operator<(PropPair a, PropPair b) {
+ return wcscmp(a.propName, b.propName) < 0;
+}
+
+// Our list of all possible properties
+static QList<PropPair> all_props;
+
+
+/*! \internal
+ Dumps a portion of the full native DIB section double buffer.
+ The DIB section double buffer is only used when doing special
+ transformations to the theme part, or when the real double
+ buffer in the paintengine does not have an HDC we may use
+ directly.
+ Since we cannot rely on the pixel data we get from Microsoft
+ when drawing into the DIB section, we use this function to
+ see the actual data we got, and can determin the appropriate
+ action.
+*/
+void QWindowsXPStylePrivate::dumpNativeDIB(int w, int h)
+{
+ if (w && h) {
+ static int pCount = 0;
+ DWORD *bufPix = (DWORD*)bufferPixels;
+
+ char *bufferDump = new char[bufferH * bufferW * 16];
+ char *bufferPos = bufferDump;
+
+ memset(bufferDump, 0, sizeof(bufferDump));
+ bufferPos += sprintf(bufferPos, "const int pixelBufferW%d = %d;\n", pCount, w);
+ bufferPos += sprintf(bufferPos, "const int pixelBufferH%d = %d;\n", pCount, h);
+ bufferPos += sprintf(bufferPos, "const unsigned DWORD pixelBuffer%d[] = {", pCount);
+ for (int iy = 0; iy < h; ++iy) {
+ bufferPos += sprintf(bufferPos, "\n ");
+ bufPix = (DWORD*)(bufferPixels + (iy * bufferW * 4));
+ for (int ix = 0; ix < w; ++ix) {
+ bufferPos += sprintf(bufferPos, "0x%08x, ", *bufPix);
+ ++bufPix;
+ }
+ }
+ bufferPos += sprintf(bufferPos, "\n};\n\n");
+ printf(bufferDump);
+
+ delete[] bufferDump;
+ ++pCount;
+ }
+}
+
+/*! \internal
+ Shows the value of a given property for a part.
+*/
+static void showProperty(XPThemeData &themeData, const PropPair &prop)
+{
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
+ const char *originStr;
+ switch (origin) {
+ case PO_STATE:
+ originStr = "State ";
+ break;
+ case PO_PART:
+ originStr = "Part ";
+ break;
+ case PO_CLASS:
+ originStr = "Class ";
+ break;
+ case PO_GLOBAL:
+ originStr = "Globl ";
+ break;
+ case PO_NOTFOUND:
+ default:
+ originStr = "Unkwn ";
+ break;
+ }
+
+ switch (prop.propType) {
+ case TMT_STRING:
+ {
+ wchar_t buffer[512];
+ GetThemeString(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
+ printf(" (%sString) %-20S: %S\n", originStr, prop.propName, buffer);
+ }
+ break;
+ case TMT_ENUM:
+ {
+ int result = -1;
+ GetThemeEnumValue(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sEnum) %-20S: %d\n", originStr, prop.propName, result);
+ }
+ break;
+ case TMT_INT:
+ {
+ int result = -1;
+ GetThemeInt(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sint) %-20S: %d\n", originStr, prop.propName, result);
+ }
+ break;
+ case TMT_BOOL:
+ {
+ BOOL result = false;
+ GetThemeBool(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sbool) %-20S: %d\n", originStr, prop.propName, result);
+ }
+ break;
+ case TMT_COLOR:
+ {
+ COLORREF result = 0;
+ GetThemeColor(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%scolor) %-20S: 0x%08X\n", originStr, prop.propName, result);
+ }
+ break;
+ case TMT_MARGINS:
+ {
+ MARGINS result;
+ memset(&result, 0, sizeof(result));
+ GetThemeMargins(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, 0, &result);
+ printf(" (%smargins) %-20S: (%d, %d, %d, %d)\n", originStr,
+ prop.propName, result.cxLeftWidth, result.cyTopHeight, result.cxRightWidth, result.cyBottomHeight);
+ }
+ break;
+ case TMT_FILENAME:
+ {
+ wchar_t buffer[512];
+ GetThemeFilename(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, buffer, 512);
+ printf(" (%sfilename)%-20S: %S\n", originStr, prop.propName, buffer);
+ }
+ break;
+ case TMT_SIZE:
+ {
+ SIZE result1;
+ SIZE result2;
+ SIZE result3;
+ memset(&result1, 0, sizeof(result1));
+ memset(&result2, 0, sizeof(result2));
+ memset(&result3, 0, sizeof(result3));
+ GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_MIN, &result1);
+ GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_TRUE, &result2);
+ GetThemePartSize(themeData.handle(), 0, themeData.partId, themeData.stateId, 0, TS_DRAW, &result3);
+ printf(" (%ssize) %-20S: Min (%d, %d), True(%d, %d), Draw(%d, %d)\n", originStr, prop.propName,
+ result1.cx, result1.cy, result2.cx, result2.cy, result3.cx, result3.cy);
+ }
+ break;
+ case TMT_POSITION:
+ {
+ POINT result;
+ memset(&result, 0, sizeof(result));
+ GetThemePosition(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sPosition)%-20S: (%d, %d)\n", originStr, prop.propName, result.x, result.y);
+ }
+ break;
+ case TMT_RECT:
+ {
+ RECT result;
+ memset(&result, 0, sizeof(result));
+ GetThemeRect(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sRect) %-20S: (%d, %d, %d, %d)\n", originStr, prop.propName, result.left, result.top, result.right, result.bottom);
+ }
+ break;
+ case TMT_FONT:
+ {
+ LOGFONT result;
+ memset(&result, 0, sizeof(result));
+ GetThemeFont(themeData.handle(), 0, themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sFont) %-20S: %S height(%d) width(%d) weight(%d)\n", originStr, prop.propName,
+ result.lfFaceName, result.lfHeight, result.lfWidth, result.lfWeight);
+ }
+ break;
+ case TMT_INTLIST:
+ {
+ INTLIST result;
+ memset(&result, 0, sizeof(result));
+ GetThemeIntList(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &result);
+ printf(" (%sInt list)%-20S: { ", originStr, prop.propName);
+ for (int i = 0; i < result.iValueCount; ++i)
+ printf("%d ", result.iValues[i]);
+ printf("}\n");
+ }
+ break;
+ default:
+ printf(" %s%S : Unknown property type (%d)!\n", originStr, prop.propName, prop.propType);
+ }
+}
+
+/*! \internal
+ Dump all valid properties for a part.
+ If it's the first time this function is called, then the name,
+ enum value and documentation of all properties are shown, as
+ well as all global properties.
+*/
+void QWindowsXPStylePrivate::showProperties(XPThemeData &themeData)
+{
+ if (!all_props.count()) {
+ const TMSCHEMAINFO *infoTable = GetSchemaInfo();
+ for (int i = 0; i < infoTable->iPropCount; ++i) {
+ int propType = infoTable->pPropTable[i].bPrimVal;
+ int propValue = infoTable->pPropTable[i].sEnumVal;
+ LPCWSTR propName = infoTable->pPropTable[i].pszName;
+
+ switch (propType) {
+ case TMT_ENUMDEF:
+ case TMT_ENUMVAL:
+ continue;
+ default:
+ if (propType != propValue) {
+ PropPair prop;
+ prop.propValue = propValue;
+ prop.propName = propName;
+ prop.propType = propType;
+ all_props.append(prop);
+ }
+ }
+ }
+ std::sort(all_props.begin(), all_props.end());
+
+ {// List all properties
+ printf("part properties count = %d:\n", all_props.count());
+ printf(" Enum Property Name Description\n");
+ printf("-----------------------------------------------------------\n");
+ wchar_t themeName[256];
+ pGetCurrentThemeName(themeName, 256, 0, 0, 0, 0);
+ for (int j = 0; j < all_props.count(); ++j) {
+ PropPair prop = all_props.at(j);
+ wchar_t buf[500];
+ GetThemeDocumentationProperty(themeName, prop.propName, buf, 500);
+ printf("%3d: (%4d) %-20S %S\n", j, prop.propValue, prop.propName, buf);
+ }
+ }
+
+ {// Show Global values
+ printf("Global Properties:\n");
+ for (int j = 0; j < all_props.count(); ++j) {
+ PropPair prop = all_props.at(j);
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
+ if (origin == PO_GLOBAL) {
+ showProperty(themeData, prop);
+ }
+ }
+ }
+ }
+
+ for (int j = 0; j < all_props.count(); ++j) {
+ PropPair prop = all_props.at(j);
+ PROPERTYORIGIN origin = PO_NOTFOUND;
+ GetThemePropertyOrigin(themeData.handle(), themeData.partId, themeData.stateId, prop.propValue, &origin);
+ if (origin != PO_NOTFOUND)
+ {
+ showProperty(themeData, prop);
+ }
+ }
+}
+#endif
+// Debugging code -----------------------------------------------------------------------[ END ]---
+
+} //namespace QQC2
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p.h
new file mode 100644
index 0000000000..89a5347777
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOWSXPSTYLE_P_H
+#define QQUICKWINDOWSXPSTYLE_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 "qquickwindowsstyle_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQC2 {
+
+class QWindowsXPStylePrivate;
+class QWindowsXPStyle : public QWindowsStyle
+{
+ Q_OBJECT
+public:
+ QWindowsXPStyle();
+ QWindowsXPStyle(QWindowsXPStylePrivate &dd);
+ ~QWindowsXPStyle() override;
+
+/*
+ void polish(QApplication*) override;
+ void unpolish(QApplication*) override;
+ void polish(QWidget*) override;
+ void unpolish(QWidget*) override;
+ void polish(QPalette&) override;
+*/
+ void drawPrimitive(PrimitiveElement pe, const QStyleOption *option, QPainter *p) const override;
+ void drawControl(ControlElement element, const QStyleOption *option, QPainter *p) const override;
+ QRect subElementRect(SubElement r, const QStyleOption *option) const override;
+ QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *option, SubControl sc) const override;
+ void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *option, QPainter *p) const override;
+ QSize sizeFromContents(ContentsType ct, const QStyleOption *option, const QSize &contentsSize) const override;
+ int pixelMetric(PixelMetric pm, const QStyleOption *option = nullptr) const override;
+ int styleHint(StyleHint hint, const QStyleOption *option = nullptr,
+ QStyleHintReturn *returnData = nullptr) const override;
+
+ QPalette standardPalette() const override;
+ QPixmap standardPixmap(StandardPixmap standardIcon, const QStyleOption *option) const override;
+ QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr) const override;
+
+ QMargins ninePatchMargins(QStyle::ComplexControl cc, const QStyleOptionComplex *opt, const QSize &imageSize) const override;
+
+private:
+ Q_DISABLE_COPY_MOVE(QWindowsXPStyle)
+ Q_DECLARE_PRIVATE(QWindowsXPStyle)
+ friend class QStyleFactory;
+};
+
+} // namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif // QQUICKWINDOWSXPSTYLE_P_H
diff --git a/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p_p.h b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p_p.h
new file mode 100644
index 0000000000..a449ecdda7
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/qquickwindowsxpstyle_p_p.h
@@ -0,0 +1,348 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWidgets module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKWINDOWSXPSTYLE_P_P_H
+#define QQUICKWINDOWSXPSTYLE_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 <QtWidgets/private/qtwidgetsglobal_p.h>
+#include "qquickwindowsxpstyle_p.h"
+#include "qquickwindowsstyle_p_p.h"
+#include <QtCore/qmap.h>
+#include <qt_windows.h>
+
+#include <uxtheme.h>
+#include <vssym32.h>
+
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDebug;
+
+namespace QQC2 {
+
+// TMT_TEXTSHADOWCOLOR is wrongly defined in mingw
+#if TMT_TEXTSHADOWCOLOR != 3818
+#undef TMT_TEXTSHADOWCOLOR
+#define TMT_TEXTSHADOWCOLOR 3818
+#endif
+#ifndef TST_NONE
+# define TST_NONE 0
+#endif
+
+// These defines are missing from the tmschema, but still exist as
+// states for their parts
+#ifndef MINBS_INACTIVE
+#define MINBS_INACTIVE 5
+#endif
+#ifndef MAXBS_INACTIVE
+#define MAXBS_INACTIVE 5
+#endif
+#ifndef RBS_INACTIVE
+#define RBS_INACTIVE 5
+#endif
+#ifndef HBS_INACTIVE
+#define HBS_INACTIVE 5
+#endif
+#ifndef CBS_INACTIVE
+#define CBS_INACTIVE 5
+#endif
+
+// Uncomment define below to build debug assisting code, and output
+// #define DEBUG_XP_STYLE
+
+// Declarations -----------------------------------------------------------------------------------
+class XPThemeData
+{
+public:
+ explicit XPThemeData(const QWindow *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
+ int part = 0, int state = 0, const QRect &r = QRect())
+ : window(w), painter(p), theme(themeIn), partId(part), stateId(state),
+ mirrorHorizontally(false), mirrorVertically(false), noBorder(false),
+ noContent(false), rect(r)
+ {}
+
+ HTHEME handle();
+
+ static RECT toRECT(const QRect &qr);
+ bool isValid();
+
+ QSizeF size();
+ QMarginsF margins(const QRect &rect, int propId = TMT_CONTENTMARGINS);
+ QMarginsF margins(int propId = TMT_CONTENTMARGINS);
+
+ static QSizeF themeSize(const QWindow *w = nullptr, QPainter *p = nullptr, int themeIn = -1, int part = 0, int state = 0);
+ static QMarginsF themeMargins(const QRect &rect, const QWindow *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
+ int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
+ static QMarginsF themeMargins(const QWindow *w = nullptr, QPainter *p = nullptr, int themeIn = -1,
+ int part = 0, int state = 0, int propId = TMT_CONTENTMARGINS);
+
+ const QWindow *window;
+ QPainter *painter;
+
+ int theme;
+ HTHEME htheme = nullptr;
+ int partId;
+ int stateId;
+
+ uint mirrorHorizontally : 1;
+ uint mirrorVertically : 1;
+ uint noBorder : 1;
+ uint noContent : 1;
+ uint rotate = 0;
+ QRect rect;
+};
+
+struct ThemeMapKey {
+ int theme = 0;
+ int partId = -1;
+ int stateId = -1;
+ bool noBorder = false;
+ bool noContent = false;
+
+ ThemeMapKey() = default;
+ ThemeMapKey(const XPThemeData &data)
+ : theme(data.theme), partId(data.partId), stateId(data.stateId),
+ noBorder(data.noBorder), noContent(data.noContent) {}
+
+};
+
+inline size_t qHash(const ThemeMapKey &key)
+{ return key.theme ^ key.partId ^ key.stateId; }
+
+inline bool operator==(const ThemeMapKey &k1, const ThemeMapKey &k2)
+{
+ return k1.theme == k2.theme
+ && k1.partId == k2.partId
+ && k1.stateId == k2.stateId;
+}
+
+enum AlphaChannelType {
+ UnknownAlpha = -1, // Alpha of part & state not yet known
+ NoAlpha, // Totally opaque, no need to touch alpha (RGB)
+ MaskAlpha, // Alpha channel must be fixed (ARGB)
+ RealAlpha // Proper alpha values from Windows (ARGB_Premultiplied)
+};
+
+struct ThemeMapData {
+ AlphaChannelType alphaType = UnknownAlpha; // Which type of alpha on part & state
+
+ bool dataValid : 1; // Only used to detect if hash value is ok
+ bool partIsTransparent : 1;
+ bool hasAlphaChannel : 1; // True = part & state has real Alpha
+ bool wasAlphaSwapped : 1; // True = alpha channel needs to be swapped
+ bool hadInvalidAlpha : 1; // True = alpha channel contained invalid alpha values
+
+ ThemeMapData() : dataValid(false), partIsTransparent(false),
+ hasAlphaChannel(false), wasAlphaSwapped(false), hadInvalidAlpha(false) {}
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const XPThemeData &t);
+QDebug operator<<(QDebug d, const ThemeMapKey &k);
+QDebug operator<<(QDebug d, const ThemeMapData &td);
+#endif
+
+class QWindowsXPStylePrivate : public QWindowsStylePrivate
+{
+ Q_DECLARE_PUBLIC(QWindowsXPStyle)
+public:
+ enum Theme {
+ ButtonTheme,
+ ComboboxTheme,
+ EditTheme,
+ HeaderTheme,
+ ListViewTheme,
+ MenuTheme,
+ ProgressTheme,
+ RebarTheme,
+ ScrollBarTheme,
+ SpinTheme,
+ TabTheme,
+ TaskDialogTheme,
+ ToolBarTheme,
+ ToolTipTheme,
+ TrackBarTheme,
+ XpTreeViewTheme, // '+'/'-' shape treeview indicators (XP)
+ WindowTheme,
+ StatusTheme,
+ VistaTreeViewTheme, // arrow shape treeview indicators (Vista) obtained from "explorer" theme.
+ NThemes
+ };
+
+ QWindowsXPStylePrivate()
+ { init(); }
+
+ ~QWindowsXPStylePrivate()
+ { cleanup(); }
+
+ static int pixelMetricFromSystemDp(QStyle::PixelMetric pm, const QStyleOption *option = nullptr);
+ static int fixedPixelMetric(QStyle::PixelMetric pm, const QStyleOption *option = nullptr, const QWidget *widget = nullptr);
+
+ static HWND winId(const QWindow *window);
+
+ void init(bool force = false);
+ void cleanup(bool force = false);
+ void cleanupHandleMap();
+
+ HBITMAP buffer(int w = 0, int h = 0);
+ HDC bufferHDC()
+ { return bufferDC;}
+
+ static bool useXP(bool update = false);
+ static QRect scrollBarGripperBounds(QStyle::State flags, XPThemeData *theme);
+
+ bool isTransparent(XPThemeData &themeData);
+ QRegion region(XPThemeData &themeData);
+
+ bool drawBackground(XPThemeData &themeData, qreal correctionFactor = 1);
+ bool drawBackgroundThruNativeBuffer(XPThemeData &themeData, qreal aditionalDevicePixelRatio, qreal correctionFactor);
+ bool drawBackgroundDirectly(HDC dc, XPThemeData &themeData, qreal aditionalDevicePixelRatio);
+
+ bool hasAlphaChannel(const QRect &rect);
+ bool fixAlphaChannel(const QRect &rect);
+ bool swapAlphaChannel(const QRect &rect, bool allPixels = false);
+
+ QRgb groupBoxTextColor = 0;
+ QRgb groupBoxTextColorDisabled = 0;
+ QRgb sliderTickColor = 0;
+ bool hasInitColors = false;
+
+ static HTHEME createTheme(int theme, HWND hwnd);
+ static QString themeName(int theme);
+ static inline bool hasTheme(int theme) { return theme >= 0 && theme < NThemes && m_themes[theme]; }
+ static bool isItemViewDelegateLineEdit(const QWidget *widget);
+ static bool isLineEditBaseColorSet(const QStyleOption *option, const QWidget *widget);
+
+ QIcon dockFloat, dockClose;
+
+private:
+#ifdef DEBUG_XP_STYLE
+ void dumpNativeDIB(int w, int h);
+ void showProperties(XPThemeData &themeData);
+#endif
+
+ static bool initVistaTreeViewTheming();
+ static void cleanupVistaTreeViewTheming();
+
+ static QBasicAtomicInt ref;
+ static bool use_xp;
+
+ QHash<ThemeMapKey, ThemeMapData> alphaCache;
+ HDC bufferDC = nullptr;
+ HBITMAP bufferBitmap = nullptr;
+ HBITMAP nullBitmap = nullptr;
+ uchar *bufferPixels = nullptr;
+ int bufferW = 0;
+ int bufferH = 0;
+
+ static HWND m_vistaTreeViewHelper;
+ static HTHEME m_themes[NThemes];
+};
+
+inline QSizeF XPThemeData::size()
+{
+ QSizeF result(0, 0);
+ if (isValid()) {
+ SIZE size;
+ if (SUCCEEDED(GetThemePartSize(handle(), nullptr, partId, stateId, nullptr, TS_TRUE, &size)))
+ result = QSize(size.cx, size.cy);
+ }
+ return result;
+}
+
+inline QMarginsF XPThemeData::margins(const QRect &qRect, int propId)
+{
+ QMarginsF result(0, 0, 0 ,0);
+ if (isValid()) {
+ MARGINS margins;
+ RECT rect = XPThemeData::toRECT(qRect);
+ if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, &rect, &margins)))
+ result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
+ }
+ return result;
+}
+
+inline QMarginsF XPThemeData::margins(int propId)
+{
+ QMarginsF result(0, 0, 0 ,0);
+ if (isValid()) {
+ MARGINS margins;
+ if (SUCCEEDED(GetThemeMargins(handle(), nullptr, partId, stateId, propId, nullptr, &margins)))
+ result = QMargins(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
+ }
+ return result;
+}
+
+inline QSizeF XPThemeData::themeSize(const QWindow *w, QPainter *p, int themeIn, int part, int state)
+{
+ XPThemeData theme(w, p, themeIn, part, state);
+ return theme.size();
+}
+
+inline QMarginsF XPThemeData::themeMargins(const QRect &rect, const QWindow *w, QPainter *p, int themeIn,
+ int part, int state, int propId)
+{
+ XPThemeData theme(w, p, themeIn, part, state);
+ return theme.margins(rect, propId);
+}
+
+inline QMarginsF XPThemeData::themeMargins(const QWindow *w, QPainter *p, int themeIn,
+ int part, int state, int propId)
+{
+ XPThemeData theme(w, p, themeIn, part, state);
+ return theme.margins(propId);
+}
+
+} //namespace QQC2
+
+QT_END_NAMESPACE
+
+#endif //QQUICKWINDOWSXPSTYLE_P_P_H
diff --git a/src/quicknativestyle/qstyle/windows/windows.pri b/src/quicknativestyle/qstyle/windows/windows.pri
new file mode 100644
index 0000000000..beb50a5b20
--- /dev/null
+++ b/src/quicknativestyle/qstyle/windows/windows.pri
@@ -0,0 +1,18 @@
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qquickwindowsstyle_p.h \
+ $$PWD/qquickwindowsstyle_p_p.h \
+# $$PWD/qquickwindowsvistastyle_p.h \
+# $$PWD/qquickwindowsvistastyle_p_p.h \
+ $$PWD/qquickwindowsxpstyle_p.h \
+ $$PWD/qquickwindowsxpstyle_p_p.h
+
+SOURCES += \
+ $$PWD/qquickwindowsstyle.cpp \
+# $$PWD/qquickwindowsvistastyle.cpp \
+ $$PWD/qquickwindowsxpstyle.cpp
+
+QMAKE_USE_PRIVATE += user32 gdi32
+LIBS_PRIVATE *= -luxtheme
diff --git a/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp
new file mode 100644
index 0000000000..1b6945849e
--- /dev/null
+++ b/src/quicknativestyle/qtquickcontrols2nativestyleplugin.cpp
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+#include <QtQuickControls2/private/qquickstyleplugin_p.h>
+#include <QtGui/qguiapplication.h>
+
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#include "qquicknativestyle.h"
+#include "qquickcommonstyle.h"
+
+#if defined(Q_OS_MACOS)
+#include "qquickmacstyle_mac_p.h"
+#include "qquickmacfocusframe.h"
+#elif defined(Q_OS_WINDOWS)
+# include "qquickwindowsxpstyle_p.h"
+#endif
+
+extern void qml_register_types_QtQuick_NativeStyle();
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_NativeStyle);
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQC2;
+
+class QtQuickControls2NativeStylePlugin : public QQuickStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickControls2NativeStylePlugin(QObject *parent = nullptr);
+ ~QtQuickControls2NativeStylePlugin() override;
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override;
+ void initializeTheme(QQuickTheme *theme) override;
+ QString name() const override;
+
+#if defined(Q_OS_MACOS)
+ QScopedPointer<QQuickMacFocusFrame> m_focusFrame;
+#endif
+};
+
+static void deleteQStyle()
+{
+ // When we delete QStyle, it will free up it's own internal resources. Especially
+ // on macOS, this means releasing a lot of NSViews and NSCells from the QMacStyle
+ // destructor. If we did this from ~QtQuickControls2NativeStylePlugin, it would
+ // happen when the plugin was unloaded from a Q_DESTRUCTOR_FUNCTION in QLibrary,
+ // which is very late in the tear-down process, and after qGuiApp has been set to
+ // nullptr, NSApplication has stopped running, and perhaps also other static platform
+ // variables (e.g in AppKit?) has been deleted. And to our best guess, this is also why
+ // we see a crash in AppKit from the destructor in QMacStyle. So for this reason, we
+ // delete QStyle from a post routine rather than from the destructor.
+ QQuickNativeStyle::setStyle(nullptr);
+}
+
+QtQuickControls2NativeStylePlugin::QtQuickControls2NativeStylePlugin(QObject *parent):
+ QQuickStylePlugin(parent)
+{
+ volatile auto registration = &qml_register_types_QtQuick_NativeStyle;
+ Q_UNUSED(registration);
+}
+
+QtQuickControls2NativeStylePlugin::~QtQuickControls2NativeStylePlugin()
+{
+ if (!qGuiApp)
+ return;
+
+ // QGuiApplication is still running, so we need to remove the post
+ // routine to not be called after we have been unloaded.
+ qRemovePostRoutine(deleteQStyle);
+ QQuickNativeStyle::setStyle(nullptr);
+}
+
+QString QtQuickControls2NativeStylePlugin::name() const
+{
+ return QStringLiteral("NativeStyle");
+}
+
+void QtQuickControls2NativeStylePlugin::initializeEngine(QQmlEngine *engine, const char *uri)
+{
+ Q_UNUSED(engine);
+ Q_UNUSED(uri);
+ // Enable commonstyle as a reference style while
+ // the native styles are under development.
+ QStyle *style = nullptr;
+ if (qEnvironmentVariable("QQC2_COMMONSTYLE") == QStringLiteral("true")) {
+ style = new QCommonStyle;
+ } else {
+ const QString envStyle = qEnvironmentVariable("QQC2_STYLE");
+ if (!envStyle.isNull()) {
+ if (envStyle == QLatin1String("common"))
+ style = new QCommonStyle;
+#if defined(Q_OS_MACOS)
+ else if (envStyle == QLatin1String("mac"))
+ style = new QMacStyle;
+#endif
+#if defined(Q_OS_WINDOWS)
+ else if (envStyle == QLatin1String("windows"))
+ style = new QWindowsStyle;
+ else if (envStyle == QLatin1String("windowsxp"))
+ style = new QWindowsXPStyle;
+#endif
+ }
+ if (!style) {
+#if defined(Q_OS_MACOS)
+ style = new QMacStyle;
+#elif defined(Q_OS_WINDOWS)
+ style = new QWindowsXPStyle;
+#else
+ style = new QCommonStyle;
+#endif
+ }
+ }
+
+#if defined(Q_OS_MACOS)
+ m_focusFrame.reset(new QQuickMacFocusFrame());
+#endif
+
+ qAddPostRoutine(deleteQStyle);
+ QQuickNativeStyle::setStyle(style);
+}
+
+void QtQuickControls2NativeStylePlugin::initializeTheme(QQuickTheme * /*theme*/)
+{
+}
+
+QT_END_NAMESPACE
+
+#include "qtquickcontrols2nativestyleplugin.moc"
diff --git a/src/quicknativestyle/util/FocusFrame.qml b/src/quicknativestyle/util/FocusFrame.qml
new file mode 100644
index 0000000000..2da96436fe
--- /dev/null
+++ b/src/quicknativestyle/util/FocusFrame.qml
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ // It's important that this item has a zero size. Otherwise, if the parent of the
+ // targetItem is e.g a layout, we will change the layout if we parent this item inside it.
+ width: 0
+ height: 0
+ // Stack on top of all siblings of the targetItem
+ z: 100
+
+ function moveToItem(item, margins, radius) {
+ if (!item) {
+ targetItem = null;
+ parent = null;
+ visible = false;
+ return;
+ }
+ visible = true
+ parent = item.parent
+ targetItem = item
+ leftOffset = margins.left
+ rightOffset = margins.right
+ topOffset = margins.top
+ bottomOffset = margins.bottom
+ frameRadius = radius
+ animation.restart()
+ }
+
+ property Item targetItem
+ property real leftOffset: 0
+ property real rightOffset: 0
+ property real topOffset: 0
+ property real bottomOffset: 0
+ property real frameOpacity: 0
+ property real frameSize: 0
+ property real frameRadius: 0
+
+ // systemFrameColor is set to NSColor.keyboardFocusIndicatorColor from cpp
+ property color systemFrameColor
+
+ Rectangle {
+ id: focusFrame
+ z: 10
+ x: targetItem ? targetItem.x + leftOffset - frameSize : 0
+ y: targetItem ? targetItem.y + topOffset - frameSize : 0
+ width: targetItem ? targetItem.width - leftOffset - rightOffset + (frameSize * 2) : 0
+ height: targetItem ? targetItem.height - topOffset - bottomOffset + (frameSize * 2) : 0
+ radius: frameRadius
+ visible: targetItem && targetItem.visible
+ color: "transparent"
+
+ border.color: systemFrameColor
+ border.width: frameSize
+ }
+
+ ParallelAnimation {
+ id: animation
+ NumberAnimation {
+ target: root
+ property: "frameSize"
+ duration: 300
+ from: 15
+ to: 2.5
+ easing.type: Easing.OutCubic
+ }
+ NumberAnimation {
+ target: focusFrame
+ property: "opacity"
+ duration: 300
+ from: 0
+ to: 0.55
+ easing.type: Easing.OutCubic
+ }
+ }
+}
diff --git a/src/quicknativestyle/util/qquickmacfocusframe.h b/src/quicknativestyle/util/qquickmacfocusframe.h
new file mode 100644
index 0000000000..425b2a6827
--- /dev/null
+++ b/src/quicknativestyle/util/qquickmacfocusframe.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMACFOCUSFRAME_H
+#define QQUICKMACFOCUSFRAME_H
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquicktextedit_p.h>
+#include "qquickstyleitem.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcFocusFrame)
+
+struct QQuickFocusFrameDescription {
+ QQuickItem *target;
+ QQuickStyleMargins margins;
+ const qreal radius = 3;
+ bool isValid() const { return target != nullptr; }
+ static QQuickFocusFrameDescription Invalid;
+};
+
+class QQuickMacFocusFrame : public QObject
+{
+ Q_OBJECT
+
+public:
+ QQuickMacFocusFrame();
+
+private:
+ static QScopedPointer<QQuickItem> m_focusFrame;
+
+ void createFocusFrame(QQmlContext *context);
+ void moveToItem(QQuickItem *item);
+ QQuickFocusFrameDescription getDescriptionForItem(QQuickItem *focusItem) const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMACFOCUSFRAME_H
diff --git a/src/quicknativestyle/util/qquickmacfocusframe.mm b/src/quicknativestyle/util/qquickmacfocusframe.mm
new file mode 100644
index 0000000000..5a2052dbbc
--- /dev/null
+++ b/src/quicknativestyle/util/qquickmacfocusframe.mm
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmacfocusframe.h"
+
+#include <AppKit/AppKit.h>
+
+#include <QtCore/qmetaobject.h>
+
+#include <QtGui/qguiapplication.h>
+#include <QtGui/private/qcoregraphics_p.h>
+
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+
+#include <QtQuickTemplates2/private/qquickframe_p.h>
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
+#include <QtQuickTemplates2/private/qquickscrollview_p.h>
+#include <QtQuickTemplates2/private/qquickslider_p.h>
+#include <QtQuickTemplates2/private/qquickcombobox_p.h>
+#include <QtQuickTemplates2/private/qquickcheckbox_p.h>
+#include <QtQuickTemplates2/private/qquickradiobutton_p.h>
+#include <QtQuickTemplates2/private/qquickspinbox_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+#include <QtQuickTemplates2/private/qquicktextarea_p.h>
+
+#include "items/qquickstyleitem.h"
+#include "qquicknativestyle.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcFocusFrame, "qt.quick.controls.focusframe")
+
+QQuickFocusFrameDescription QQuickFocusFrameDescription::Invalid = { nullptr, QQuickStyleMargins(), 0 };
+QScopedPointer<QQuickItem> QQuickMacFocusFrame::m_focusFrame;
+
+QQuickMacFocusFrame::QQuickMacFocusFrame()
+{
+ connect(qGuiApp, &QGuiApplication::focusObjectChanged, [=]{
+ if (auto item = qobject_cast<QQuickItem *>(qGuiApp->focusObject()))
+ moveToItem(item);
+ });
+}
+
+void QQuickMacFocusFrame::moveToItem(QQuickItem *item)
+{
+ if (!m_focusFrame) {
+ const auto context = QQmlEngine::contextForObject(item);
+ if (!context)
+ return;
+ createFocusFrame(context);
+ }
+
+ const QQuickFocusFrameDescription &config = getDescriptionForItem(item);
+ QMetaObject::invokeMethod(m_focusFrame.data(), "moveToItem",
+ Q_ARG(QVariant, QVariant::fromValue(config.target)),
+ Q_ARG(QVariant, QVariant::fromValue(config.margins)),
+ Q_ARG(QVariant, QVariant::fromValue(config.radius)));
+}
+
+void QQuickMacFocusFrame::createFocusFrame(QQmlContext *context)
+{
+ QQmlComponent component(
+ context->engine(),
+ QUrl(QStringLiteral(
+ "qrc:/qt-project.org/imports/QtQuick/NativeStyle/util/FocusFrame.qml")));
+ m_focusFrame.reset(qobject_cast<QQuickItem *>(component.create()));
+
+ auto indicatorColor = qt_mac_toQColor(NSColor.keyboardFocusIndicatorColor.CGColor);
+ indicatorColor.setAlpha(255);
+ m_focusFrame->setProperty("systemFrameColor", indicatorColor);
+}
+
+QQuickFocusFrameDescription QQuickMacFocusFrame::getDescriptionForItem(QQuickItem *focusItem) const
+{
+ qCDebug(lcFocusFrame) << "new focusobject:" << focusItem;
+ const auto parentItem = focusItem->parentItem();
+ if (!parentItem)
+ return QQuickFocusFrameDescription::Invalid;
+
+ // The item that gets active focus can be a child of the control (e.g
+ // editable ComboBox). In that case, resolve the actual control first.
+ const auto proxy = focusItem->property("__focusFrameControl").value<QQuickItem *>();
+ const auto control = proxy ? proxy : focusItem;
+ auto target = control->property("__focusFrameTarget").value<QQuickItem *>();
+ qCDebug(lcFocusFrame) << "target:" << target;
+ qCDebug(lcFocusFrame) << "control:" << control;
+
+ if (!target) {
+ // __focusFrameTarget points to the item in the control that should
+ // get the focus frame. This is usually the control itself, but can
+ // sometimes be a child (CheckBox). We anyway require
+ // this property to be set if we are to show the focus frame around
+ // the control in the first place. So for controls that don't want
+ // a frame (ProgressBar), we simply skip setting it.
+ // Also, we should never show a focus frame around custom controls.
+ // None of the built-in styles do that, so to be consistent, we
+ // shouldn't either. Besides, drawing a focus frame around an unknown
+ // item without any way to turn it off can easily be unwanted. A better
+ // way for custom controls to get a native focus frame is for us to offer
+ // a FocusFrame control (QTBUG-86818).
+ return QQuickFocusFrameDescription::Invalid;
+ }
+
+ // If the control gives us a QQuickStyleItem, we use that to configure the focus frame.
+ // By default we assume that the background delegate is a QQuickStyleItem, but the
+ // control can override this by setting __focusFrameStyleItem.
+ const auto styleItemProperty = control->property("__focusFrameStyleItem");
+ auto item = styleItemProperty.value<QQuickItem *>();
+ if (!item) {
+ const auto styleItemProperty = control->property("background");
+ item = styleItemProperty.value<QQuickItem *>();
+ }
+ qCDebug(lcFocusFrame) << "styleItem:" << item;
+ if (!item)
+ return QQuickFocusFrameDescription::Invalid;
+ if (QQuickStyleItem *styleItem = qobject_cast<QQuickStyleItem *>(item))
+ return { target, QQuickStyleMargins(styleItem->layoutMargins()), styleItem->focusFrameRadius() };
+
+ // Some controls don't have a QQuickStyleItem. But if the __focusFrameStyleItem
+ // has a "__isDefaultDelegate" property set, we show a default focus frame instead.
+ if (item->property("__isDefaultDelegate").toBool() == true) {
+ qCDebug(lcFocusFrame) << "'__isDefaultDelegate' property found, showing a default focus frame";
+ const QStyleOption opt;
+ const qreal radius = QQuickNativeStyle::style()->pixelMetric(QStyle::PM_TextFieldFocusFrameRadius, &opt);
+ return { target, QQuickStyleMargins(), radius };
+ }
+
+ // The application has set a custom delegate on the control. In that
+ // case, it's the delegates responsibility to draw a focus frame.
+ qCDebug(lcFocusFrame) << "custom delegates in use, skip showing focus frame";
+ return QQuickFocusFrameDescription::Invalid;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicknativestyle/util/util.pri b/src/quicknativestyle/util/util.pri
new file mode 100644
index 0000000000..96786eacaa
--- /dev/null
+++ b/src/quicknativestyle/util/util.pri
@@ -0,0 +1,11 @@
+INCLUDEPATH += $$PWD
+
+macos {
+ HEADERS += \
+ $$PWD/qquickmacfocusframe.h \
+
+ SOURCES += \
+ $$PWD/qquickmacfocusframe.mm \
+
+ RESOURCES += $$PWD/FocusFrame.qml
+}
diff --git a/src/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp
index fce4c3d680..4baf9a7123 100644
--- a/src/quickshapes/qquickshape.cpp
+++ b/src/quickshapes/qquickshape.cpp
@@ -1476,6 +1476,7 @@ static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradie
{
int pos = 0;
const QGradientStops &s = gradient.stops;
+ Q_ASSERT(!s.isEmpty());
const bool colorInterpolation = true;
uint alpha = qRound(opacity * 256);
@@ -1513,8 +1514,6 @@ static void generateGradientColorTable(const QQuickShapeGradientCacheKey &gradie
current_color = next_color;
}
- Q_ASSERT(s.size() > 0);
-
uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha)));
for ( ; pos < size; ++pos)
colorTable[pos] = last_color;
@@ -1549,7 +1548,10 @@ QSGTexture *QQuickShapeGradientCache::get(const QQuickShapeGradientCacheKey &gra
if (!tx) {
static const int W = 1024; // texture size is 1024x1
QImage gradTab(W, 1, QImage::Format_RGBA8888_Premultiplied);
- generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
+ if (!grad.stops.isEmpty())
+ generateGradientColorTable(grad, reinterpret_cast<uint *>(gradTab.bits()), W, 1.0f);
+ else
+ gradTab.fill(Qt::black);
tx = new QSGPlainTexture;
tx->setImage(gradTab);
switch (grad.spread) {
diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp
index f5fcd72152..c44ef2d4e1 100644
--- a/src/quickshapes/qquickshapegenericrenderer.cpp
+++ b/src/quickshapes/qquickshapegenericrenderer.cpp
@@ -145,8 +145,12 @@ void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path)
void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color)
{
ShapePathData &d(m_sp[index]);
+ const bool wasTransparent = d.strokeColor.a == 0;
d.strokeColor = colorToColor4ub(color);
+ const bool isTransparent = d.strokeColor.a == 0;
d.syncDirty |= DirtyColor;
+ if (wasTransparent && !isTransparent)
+ d.syncDirty |= DirtyStrokeGeom;
}
void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w)
@@ -841,7 +845,7 @@ bool QQuickShapeRadialGradientRhiShader::updateUniformData(RenderState &state,
QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
- QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
Q_ASSERT(buf->size() >= 92);
@@ -901,7 +905,7 @@ void QQuickShapeRadialGradientRhiShader::updateSampledImage(RenderState &state,
if (binding != 1)
return;
- QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ QQuickShapeRadialGradientMaterial *m = static_cast<QQuickShapeRadialGradientMaterial *>(newMaterial);
QQuickShapeGenericStrokeFillNode *node = m->node();
const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread);
QSGTexture *t = QQuickShapeGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
@@ -975,7 +979,7 @@ bool QQuickShapeConicalGradientRhiShader::updateUniformData(RenderState &state,
QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
{
Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type());
- QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
bool changed = false;
QByteArray *buf = state.uniformData();
Q_ASSERT(buf->size() >= 80);
@@ -1019,7 +1023,7 @@ void QQuickShapeConicalGradientRhiShader::updateSampledImage(RenderState &state,
if (binding != 1)
return;
- QQuickShapeLinearGradientMaterial *m = static_cast<QQuickShapeLinearGradientMaterial *>(newMaterial);
+ QQuickShapeConicalGradientMaterial *m = static_cast<QQuickShapeConicalGradientMaterial *>(newMaterial);
QQuickShapeGenericStrokeFillNode *node = m->node();
const QQuickShapeGradientCacheKey cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread);
QSGTexture *t = QQuickShapeGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
@@ -1075,3 +1079,5 @@ QSGMaterialShader *QQuickShapeConicalGradientMaterial::createShader(QSGRendererI
}
QT_END_NAMESPACE
+
+#include "moc_qquickshapegenericrenderer_p.cpp"
diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp
index dc9ccb340d..d68fc22388 100644
--- a/src/quickshapes/qquickshapesoftwarerenderer.cpp
+++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp
@@ -180,10 +180,8 @@ void QQuickShapeSoftwareRenderer::endSync(bool)
void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node)
{
- if (m_node != node) {
- m_node = node;
- m_accDirty |= DirtyList;
- }
+ m_node = node;
+ m_accDirty |= DirtyList;
}
void QQuickShapeSoftwareRenderer::updateNode()
diff --git a/src/quickshapes/qquickshapesplugin.cpp b/src/quickshapes/qquickshapesplugin.cpp
index 587c546fca..513160db60 100644
--- a/src/quickshapes/qquickshapesplugin.cpp
+++ b/src/quickshapes/qquickshapesplugin.cpp
@@ -41,6 +41,9 @@
#include <QtQml/qqml.h>
#include <QtQuickShapes/private/qquickshape_p.h>
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Shapes);
+Q_GHS_KEEP_REFERENCE(QQuickShapes_initializeModule);
+
QT_BEGIN_NAMESPACE
class QmlShapesPlugin : public QQmlEngineExtensionPlugin
diff --git a/src/quicktemplates2/CMakeLists.txt b/src/quicktemplates2/CMakeLists.txt
new file mode 100644
index 0000000000..3ddb994cc1
--- /dev/null
+++ b/src/quicktemplates2/CMakeLists.txt
@@ -0,0 +1,169 @@
+#####################################################################
+## QuickTemplates2 Module:
+#####################################################################
+
+qt_internal_add_qml_module(QuickTemplates2
+ URI "QtQuick.Templates"
+ VERSION "${PROJECT_VERSION}"
+ CLASSNAME QtQuickTemplates2Plugin
+ DEPENDENCIES
+ QtQuick/auto
+ PLUGIN_TARGET qtquicktemplates2plugin
+ NO_PLUGIN_OPTIONAL
+ NO_GENERATE_PLUGIN_SOURCE
+ SOURCES
+ qquickabstractbutton.cpp qquickabstractbutton_p.h
+ qquickabstractbutton_p_p.h
+ qquickaction.cpp qquickaction_p.h
+ qquickactiongroup.cpp qquickactiongroup_p.h
+ qquickapplicationwindow.cpp qquickapplicationwindow_p.h
+ qquickbusyindicator.cpp qquickbusyindicator_p.h
+ qquickbutton.cpp qquickbutton_p.h
+ qquickbutton_p_p.h
+ qquickbuttongroup.cpp qquickbuttongroup_p.h
+ qquickcheckbox.cpp qquickcheckbox_p.h
+ qquickcheckdelegate.cpp qquickcheckdelegate_p.h
+ qquickcombobox.cpp qquickcombobox_p.h
+ qquickcontainer.cpp qquickcontainer_p.h
+ qquickcontainer_p_p.h
+ qquickcontentitem.cpp qquickcontentitem_p.h
+ qquickcontrol.cpp qquickcontrol_p.h
+ qquickcontrol_p_p.h
+ qquickdeferredexecute.cpp
+ qquickdeferredexecute_p_p.h
+ qquickdeferredpointer_p_p.h
+ qquickdelaybutton.cpp qquickdelaybutton_p.h
+ qquickdial.cpp qquickdial_p.h
+ qquickdialog.cpp qquickdialog_p.h
+ qquickdialog_p_p.h
+ qquickdialogbuttonbox.cpp qquickdialogbuttonbox_p.h
+ qquickdialogbuttonbox_p_p.h
+ qquickdrawer.cpp qquickdrawer_p.h
+ qquickdrawer_p_p.h
+ qquickframe.cpp qquickframe_p.h
+ qquickframe_p_p.h
+ qquickgroupbox.cpp qquickgroupbox_p.h
+ qquickicon.cpp qquickicon_p.h
+ qquickindicatorbutton_p.cpp qquickindicatorbutton_p.h
+ qquickitemdelegate.cpp qquickitemdelegate_p.h
+ qquickitemdelegate_p_p.h
+ qquicklabel.cpp qquicklabel_p.h
+ qquicklabel_p_p.h
+ qquickmenu.cpp qquickmenu_p.h
+ qquickmenu_p_p.h
+ qquickmenubar.cpp qquickmenubar_p.h
+ qquickmenubar_p_p.h
+ qquickmenubaritem.cpp qquickmenubaritem_p.h
+ qquickmenubaritem_p_p.h
+ qquickmenuitem.cpp qquickmenuitem_p.h
+ qquickmenuitem_p_p.h
+ qquickmenuseparator.cpp qquickmenuseparator_p.h
+ qquickoverlay.cpp qquickoverlay_p.h
+ qquickoverlay_p_p.h
+ qquickpage.cpp qquickpage_p.h
+ qquickpage_p_p.h
+ qquickpageindicator.cpp qquickpageindicator_p.h
+ qquickpane.cpp qquickpane_p.h
+ qquickpane_p_p.h
+ qquickpopup.cpp qquickpopup_p.h
+ qquickpopup_p_p.h
+ qquickpopupanchors.cpp qquickpopupanchors_p.h
+ qquickpopupanchors_p_p.h
+ qquickpopupitem.cpp
+ qquickpopupitem_p_p.h
+ qquickpopuppositioner.cpp
+ qquickpopuppositioner_p_p.h
+ qquickpresshandler.cpp
+ qquickpresshandler_p_p.h
+ qquickprogressbar.cpp qquickprogressbar_p.h
+ qquickradiobutton.cpp qquickradiobutton_p.h
+ qquickradiodelegate.cpp qquickradiodelegate_p.h
+ qquickrangeslider.cpp qquickrangeslider_p.h
+ qquickroundbutton.cpp qquickroundbutton_p.h
+ qquickscrollbar.cpp qquickscrollbar_p.h
+ qquickscrollbar_p_p.h
+ qquickscrollindicator.cpp qquickscrollindicator_p.h
+ qquickscrollview.cpp qquickscrollview_p.h
+ qquickselectionrectangle.cpp qquickselectionrectangle_p.h
+ qquickselectionrectangle_p_p.h
+ qquickshortcutcontext.cpp
+ qquickshortcutcontext_p_p.h
+ qquickslider.cpp qquickslider_p.h
+ qquickspinbox.cpp qquickspinbox_p.h
+ qquicksplitview.cpp qquicksplitview_p.h
+ qquickstackelement.cpp
+ qquickstackelement_p_p.h
+ qquickstacktransition.cpp
+ qquickstacktransition_p_p.h
+ qquickstackview.cpp qquickstackview_p.cpp qquickstackview_p.h
+ qquickstackview_p_p.h
+ qquickswipe_p.h
+ qquickswipedelegate.cpp qquickswipedelegate_p.h
+ qquickswipedelegate_p_p.h
+ qquickswipeview.cpp qquickswipeview_p.h
+ qquickswitch.cpp qquickswitch_p.h
+ qquickswitchdelegate.cpp qquickswitchdelegate_p.h
+ qquicktabbar.cpp qquicktabbar_p.h
+ qquicktabbutton.cpp qquicktabbutton_p.h
+ qquicktextarea.cpp qquicktextarea_p.h
+ qquicktextarea_p_p.h
+ qquicktextfield.cpp qquicktextfield_p.h
+ qquicktextfield_p_p.h
+ qquicktheme.cpp qquicktheme_p.h
+ qquicktheme_p_p.h
+ qquicktoolbar.cpp qquicktoolbar_p.h
+ qquicktoolbutton.cpp qquicktoolbutton_p.h
+ qquicktoolseparator.cpp qquicktoolseparator_p.h
+ qquicktooltip.cpp qquicktooltip_p.h
+ qquickvelocitycalculator.cpp
+ qquickvelocitycalculator_p_p.h
+ qtquicktemplates2global.cpp qtquicktemplates2global_p.h
+ DEFINES
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ LIBRARIES
+ Qt::CorePrivate
+ Qt::GuiPrivate
+ Qt::QmlPrivate
+ Qt::QuickPrivate
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Gui
+ Qt::Quick
+)
+
+qt_internal_extend_target(QuickTemplates2 CONDITION TARGET Qt::QmlModels
+ LIBRARIES
+ Qt::QmlModelsPrivate
+ PUBLIC_LIBRARIES
+ Qt::QmlModels
+ PRIVATE_MODULE_INTERFACE
+ Qt::QmlModelsPrivate
+)
+
+qt_internal_extend_target(QuickTemplates2 CONDITION QT_FEATURE_accessibility
+ SOURCES
+ accessible/qaccessiblequickpage.cpp accessible/qaccessiblequickpage_p.h
+)
+
+qt_internal_extend_target(QuickTemplates2 CONDITION QT_FEATURE_quick_tableview
+ SOURCES
+ qquickheaderview.cpp qquickheaderview_p.h
+ qquickheaderview_p_p.h
+)
+
+qt_internal_extend_target(QuickTemplates2 CONDITION QT_FEATURE_quick_listview AND QT_FEATURE_quick_pathview
+ SOURCES
+ qquicktumbler.cpp qquicktumbler_p.h
+ qquicktumbler_p_p.h
+)
+
+qt_internal_extend_Target(qtquicktemplates2plugin
+ SOURCES
+ qtquicktemplates2plugin.cpp
+ LIBRARIES
+ Qt::Quick
+ Qt::QuickTemplates2Private
+)
diff --git a/src/quicktemplates2/accessible/accessible.pri b/src/quicktemplates2/accessible/accessible.pri
new file mode 100644
index 0000000000..0c855d34c6
--- /dev/null
+++ b/src/quicktemplates2/accessible/accessible.pri
@@ -0,0 +1,4 @@
+HEADERS += \
+ $$PWD/qaccessiblequickpage_p.h \
+SOURCES += \
+ $$PWD/qaccessiblequickpage.cpp \
diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage.cpp b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp
new file mode 100644
index 0000000000..90ac49f9da
--- /dev/null
+++ b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessiblequickpage_p.h"
+#include "qquickpage_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QAccessibleQuickPage::QAccessibleQuickPage(QQuickPage *page)
+ : QAccessibleQuickItem(page)
+{
+}
+
+QAccessibleInterface *QAccessibleQuickPage::child(int index) const
+{
+ const QList<QQuickItem*> kids = orderedChildItems();
+ if (QQuickItem *item = kids.value(index))
+ return QAccessible::queryAccessibleInterface(item);
+ return nullptr;
+}
+
+int QAccessibleQuickPage::indexOfChild(const QAccessibleInterface *iface) const
+{
+ const QList<QQuickItem*> kids = orderedChildItems();
+ return (int)kids.indexOf(static_cast<QQuickItem*>(iface->object()));
+}
+
+QList<QQuickItem *> QAccessibleQuickPage::orderedChildItems() const
+{
+ // Just ensures that the header is first, and footer is last. Other existing order is kept.
+ const QQuickPage *p = page();
+ QList<QQuickItem*> kids = childItems();
+ const qsizetype hidx = kids.indexOf(p->header());
+ if (hidx != -1)
+ kids.move(hidx, 0);
+ const qsizetype fidx = kids.indexOf(p->footer());
+ if (fidx != -1)
+ kids.move(fidx, kids.count() - 1);
+ return kids;
+}
+
+QQuickPage *QAccessibleQuickPage::page() const
+{
+ return static_cast<QQuickPage*>(object());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage_p.h b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h
new file mode 100644
index 0000000000..9b208c1415
--- /dev/null
+++ b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QACCESSIBLEQUICKPAGE_H
+#define QACCESSIBLEQUICKPAGE_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/qaccessiblequickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPage;
+
+class QAccessibleQuickPage : public QAccessibleQuickItem
+{
+public:
+ QAccessibleQuickPage(QQuickPage *page);
+ QAccessibleInterface *child(int index) const override;
+ int indexOfChild(const QAccessibleInterface *iface) const override;
+private:
+ QQuickPage *page() const;
+ QList<QQuickItem *> orderedChildItems() const;
+};
+
+QT_END_NAMESPACE
+
+#endif // QACCESSIBLEQUICKPAGE_H
diff --git a/src/quicktemplates2/configure.cmake b/src/quicktemplates2/configure.cmake
new file mode 100644
index 0000000000..4e09756939
--- /dev/null
+++ b/src/quicktemplates2/configure.cmake
@@ -0,0 +1,30 @@
+
+
+#### Inputs
+
+
+
+#### Libraries
+
+
+
+#### Tests
+
+
+
+#### Features
+
+qt_feature("quicktemplates2-hover" PRIVATE
+ SECTION "Quick Templates 2"
+ LABEL "Hover support"
+ PURPOSE "Provides support for hover effects."
+)
+qt_feature("quicktemplates2-multitouch" PRIVATE
+ SECTION "Quick Templates 2"
+ LABEL "Multi-touch support"
+ PURPOSE "Provides support for multi-touch."
+)
+qt_configure_add_summary_section(NAME "Qt Quick Templates 2")
+qt_configure_add_summary_entry(ARGS "quicktemplates2-hover")
+qt_configure_add_summary_entry(ARGS "quicktemplates2-multitouch")
+qt_configure_end_summary_section() # end of "Qt Quick Templates 2" section
diff --git a/src/quicktemplates2/doc/src/qtquicktemplates2-index.qdoc b/src/quicktemplates2/doc/src/qtquicktemplates2-index.qdoc
new file mode 100644
index 0000000000..c7e2554821
--- /dev/null
+++ b/src/quicktemplates2/doc/src/qtquicktemplates2-index.qdoc
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtquicktemplates2-index.html
+ \title Qt Quick Templates 2
+ \brief A set of templates to create user interface controls in Qt Quick
+
+ Qt Quick Templates are the foundations of \l {Qt Quick Controls}. Templates
+ are non-visual implementations of controls' logic and behavior. They offer
+ an interface to visualize the controls in QML using \l {Qt Quick}.
+
+ Even though the templates aim to be as style-agnostic as possible, in some
+ cases they have to make certain assumptions about the visual structure of
+ a control. For example, a spinbox has buttons that increment and decrement
+ the value of the spinbox. In order to implement the behavior of a spinbox,
+ the spinbox template needs to know if the user is interacting with the up
+ or down button. A visual implementation of the spinbox template merely needs
+ to position the up and down buttons and visualize them in normal, pressed,
+ and disabled states. Any input event handling and state processing is taken
+ care of by the underlying template.
+
+ \section1 Module Evolution
+ \l{Changes to Qt Quick Controls} lists important changes in the
+ module API and functionality that were done for the Qt 6 series of Qt.
+
+ \section1 Related Information
+
+ \list
+ \li \l{Qt Quick}
+ \li \l{Qt Quick Controls}
+ \li \l{Qt Quick Templates 2 QML Types}
+ \endlist
+*/
diff --git a/src/quicktemplates2/doc/src/qtquicktemplates2-qmltypes.qdoc b/src/quicktemplates2/doc/src/qtquicktemplates2-qmltypes.qdoc
new file mode 100644
index 0000000000..feb770bb54
--- /dev/null
+++ b/src/quicktemplates2/doc/src/qtquicktemplates2-qmltypes.qdoc
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule QtQuick.Templates
+ \title Qt Quick Templates 2 QML Types
+ \ingroup qmlmodules
+ \brief Provides QML types for templates (Qt Quick Templates).
+
+ The \l {Qt Quick Templates 2} module provides a set of non-visual templates
+ that can be used to build user interface controls in QML using \l {Qt Quick}.
+
+ The QML types can be imported using the following import statement in your
+ \c .qml file:
+
+ \qml
+ import QtQuick.Templates as T
+ \endqml
+
+ For the sake of clarity, there is a one-to-one mapping between the types
+ provided by the \c QtQuick.Templates and \c QtQuick.Controls imports. For
+ every type available in the \c QtQuick.Controls import, a non-visual template
+ type by the same name exists in the \c QtQuick.Templates import.
+
+ \note It is recommended to use a namespace for the templates import to avoid
+ overlap with the types provided by the \c QtQuick.Controls import.
+
+ \section1 QML Types
+
+ \generatelist {qmltypesbymodule QtQuick.Controls}
+
+ \section1 Related Information
+
+ \list
+ \li \l {Qt Quick Controls QML Types}
+ \li \l {Using Qt Quick Controls types in property declarations}
+ \endlist
+
+ \noautolist
+*/
diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp
new file mode 100644
index 0000000000..ffda109dfa
--- /dev/null
+++ b/src/quicktemplates2/qquickabstractbutton.cpp
@@ -0,0 +1,1220 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickabstractbutton_p.h"
+#include "qquickabstractbutton_p_p.h"
+#include "qquickbuttongroup_p.h"
+#include "qquickaction_p.h"
+#include "qquickaction_p_p.h"
+#include "qquickshortcutcontext_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/qguiapplication.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/private/qshortcutmap_p.h>
+#endif
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype AbstractButton
+ \inherits Control
+//! \instantiates QQuickAbstractButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Abstract base type providing functionality common to buttons.
+
+ AbstractButton provides the interface for controls with button-like
+ behavior; for example, push buttons and checkable controls like
+ radio buttons and check boxes. As an abstract control, it has no delegate
+ implementations, leaving them to the types that derive from it.
+
+ \sa ButtonGroup, {Button Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::pressed()
+
+ This signal is emitted when the button is interactively pressed by the user via touch, mouse, or keyboard.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::released()
+
+ This signal is emitted when the button is interactively released by the user via touch, mouse, or keyboard.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::canceled()
+
+ This signal is emitted when the button loses mouse grab
+ while being pressed, or when it would emit the \l released
+ signal but the mouse cursor is not inside the button.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::clicked()
+
+ This signal is emitted when the button is interactively clicked by the user via touch, mouse, or keyboard.
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal QtQuick.Controls::AbstractButton::toggled()
+
+ This signal is emitted when a checkable button is interactively toggled by the user via touch, mouse, or keyboard.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::pressAndHold()
+
+ This signal is emitted when the button is interactively pressed and held down by the user via touch or mouse.
+ It is not emitted when \l autoRepeat is enabled.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::AbstractButton::doubleClicked()
+
+ This signal is emitted when the button is interactively double clicked by the user via touch or mouse.
+*/
+
+void QQuickAbstractButtonPrivate::setPressPoint(const QPointF &point)
+{
+ pressPoint = point;
+ setMovePoint(point);
+}
+
+void QQuickAbstractButtonPrivate::setMovePoint(const QPointF &point)
+{
+ Q_Q(QQuickAbstractButton);
+ bool xChange = !qFuzzyCompare(point.x(), movePoint.x());
+ bool yChange = !qFuzzyCompare(point.y(), movePoint.y());
+ movePoint = point;
+ if (xChange)
+ emit q->pressXChanged();
+ if (yChange)
+ emit q->pressYChanged();
+}
+
+void QQuickAbstractButtonPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::handlePress(point);
+ setPressPoint(point);
+ q->setPressed(true);
+
+ emit q->pressed();
+
+ if (autoRepeat)
+ startRepeatDelay();
+ else if (touchId != -1 || Qt::LeftButton == (pressButtons & Qt::LeftButton))
+ startPressAndHold();
+ else
+ stopPressAndHold();
+}
+
+void QQuickAbstractButtonPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::handleMove(point);
+ setMovePoint(point);
+ q->setPressed(keepPressed || q->contains(point));
+
+ if (!pressed && autoRepeat)
+ stopPressRepeat();
+ else if (holdTimer > 0 && (!pressed || QLineF(pressPoint, point).length() > QGuiApplication::styleHints()->startDragDistance()))
+ stopPressAndHold();
+}
+
+void QQuickAbstractButtonPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::handleRelease(point);
+ bool wasPressed = pressed;
+ setPressPoint(point);
+ q->setPressed(false);
+ pressButtons = Qt::NoButton;
+
+ if (!wasHeld && (keepPressed || q->contains(point)))
+ q->nextCheckState();
+
+ if (wasPressed) {
+ emit q->released();
+ if (!wasHeld && !wasDoubleClick)
+ trigger();
+ } else {
+ emit q->canceled();
+ }
+
+ if (autoRepeat)
+ stopPressRepeat();
+ else
+ stopPressAndHold();
+
+ wasDoubleClick = false;
+}
+
+void QQuickAbstractButtonPrivate::handleUngrab()
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::handleUngrab();
+ pressButtons = Qt::NoButton;
+ if (!pressed)
+ return;
+
+ q->setPressed(false);
+ stopPressRepeat();
+ stopPressAndHold();
+ wasDoubleClick = false;
+ emit q->canceled();
+}
+
+bool QQuickAbstractButtonPrivate::acceptKeyClick(Qt::Key key) const
+{
+ return key == Qt::Key_Space;
+}
+
+bool QQuickAbstractButtonPrivate::isPressAndHoldConnected()
+{
+ Q_Q(QQuickAbstractButton);
+ static const QMetaMethod method = [&]() {
+ const auto signal = &QQuickAbstractButton::pressAndHold;
+ return QMetaMethod::fromSignal(signal);
+ }();
+ return q->isSignalConnected(method);
+}
+
+bool QQuickAbstractButtonPrivate::isDoubleClickConnected()
+{
+ Q_Q(QQuickAbstractButton);
+ static const QMetaMethod method = [&]() {
+ const auto signal = &QQuickAbstractButton::doubleClicked;
+ return QMetaMethod::fromSignal(signal);
+ }();
+ return q->isSignalConnected(method);
+}
+
+void QQuickAbstractButtonPrivate::startPressAndHold()
+{
+ Q_Q(QQuickAbstractButton);
+ wasHeld = false;
+ stopPressAndHold();
+ if (isPressAndHoldConnected())
+ holdTimer = q->startTimer(QGuiApplication::styleHints()->mousePressAndHoldInterval());
+}
+
+void QQuickAbstractButtonPrivate::stopPressAndHold()
+{
+ Q_Q(QQuickAbstractButton);
+ if (holdTimer > 0) {
+ q->killTimer(holdTimer);
+ holdTimer = 0;
+ }
+}
+
+void QQuickAbstractButtonPrivate::startRepeatDelay()
+{
+ Q_Q(QQuickAbstractButton);
+ stopPressRepeat();
+ delayTimer = q->startTimer(repeatDelay);
+}
+
+void QQuickAbstractButtonPrivate::startPressRepeat()
+{
+ Q_Q(QQuickAbstractButton);
+ stopPressRepeat();
+ repeatTimer = q->startTimer(repeatInterval);
+}
+
+void QQuickAbstractButtonPrivate::stopPressRepeat()
+{
+ Q_Q(QQuickAbstractButton);
+ if (delayTimer > 0) {
+ q->killTimer(delayTimer);
+ delayTimer = 0;
+ }
+ if (repeatTimer > 0) {
+ q->killTimer(repeatTimer);
+ repeatTimer = 0;
+ }
+}
+
+#if QT_CONFIG(shortcut)
+void QQuickAbstractButtonPrivate::grabShortcut()
+{
+ Q_Q(QQuickAbstractButton);
+ if (shortcut.isEmpty())
+ return;
+
+ shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(q, shortcut, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+
+ if (!q->isEnabled())
+ QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(false, shortcutId, q);
+}
+
+void QQuickAbstractButtonPrivate::ungrabShortcut()
+{
+ Q_Q(QQuickAbstractButton);
+ if (!shortcutId)
+ return;
+
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(shortcutId, q);
+ shortcutId = 0;
+}
+#endif
+
+void QQuickAbstractButtonPrivate::actionTextChange()
+{
+ Q_Q(QQuickAbstractButton);
+ if (explicitText)
+ return;
+
+ q->buttonChange(QQuickAbstractButton::ButtonTextChange);
+}
+
+void QQuickAbstractButtonPrivate::setText(const QString &newText, bool isExplicit)
+{
+ Q_Q(QQuickAbstractButton);
+ const QString oldText = q->text();
+ explicitText = isExplicit;
+ text = newText;
+ if (oldText == q->text())
+ return;
+
+ q->buttonChange(QQuickAbstractButton::ButtonTextChange);
+}
+
+void QQuickAbstractButtonPrivate::updateEffectiveIcon()
+{
+ Q_Q(QQuickAbstractButton);
+ // We store effectiveIcon because we need to be able to tell if the icon has actually changed.
+ // If we only stored our icon and the action's icon, and resolved in the getter, we'd have
+ // no way of knowing what the old value was here. As an added benefit, we only resolve when
+ // something has changed, as opposed to doing it unconditionally in the icon() getter.
+ const QQuickIcon newEffectiveIcon = action ? icon.resolve(action->icon()) : icon;
+ if (newEffectiveIcon == effectiveIcon)
+ return;
+
+ effectiveIcon = newEffectiveIcon;
+ emit q->iconChanged();
+}
+
+void QQuickAbstractButtonPrivate::click()
+{
+ Q_Q(QQuickAbstractButton);
+ if (effectiveEnable)
+ emit q->clicked();
+}
+
+void QQuickAbstractButtonPrivate::trigger()
+{
+ Q_Q(QQuickAbstractButton);
+ const bool wasEnabled = effectiveEnable;
+ if (action && action->isEnabled())
+ QQuickActionPrivate::get(action)->trigger(q, false);
+ if (wasEnabled && (!action || !action->isEnabled()))
+ emit q->clicked();
+}
+
+void QQuickAbstractButtonPrivate::toggle(bool value)
+{
+ Q_Q(QQuickAbstractButton);
+ const bool wasChecked = checked;
+ q->setChecked(value);
+ if (wasChecked != checked)
+ emit q->toggled();
+}
+
+static inline QString indicatorName() { return QStringLiteral("indicator"); }
+
+void QQuickAbstractButtonPrivate::cancelIndicator()
+{
+ Q_Q(QQuickAbstractButton);
+ quickCancelDeferred(q, indicatorName());
+}
+
+void QQuickAbstractButtonPrivate::executeIndicator(bool complete)
+{
+ Q_Q(QQuickAbstractButton);
+ if (indicator.wasExecuted())
+ return;
+
+ if (!indicator || complete)
+ quickBeginDeferred(q, indicatorName(), indicator);
+ if (complete)
+ quickCompleteDeferred(q, indicatorName(), indicator);
+}
+
+void QQuickAbstractButtonPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ if (item == indicator)
+ emit q->implicitIndicatorWidthChanged();
+}
+
+void QQuickAbstractButtonPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ if (item == indicator)
+ emit q->implicitIndicatorHeightChanged();
+}
+
+void QQuickAbstractButtonPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickAbstractButton);
+ QQuickControlPrivate::itemDestroyed(item);
+ if (item == indicator) {
+ indicator = nullptr;
+ emit q->implicitIndicatorWidthChanged();
+ emit q->implicitIndicatorHeightChanged();
+ }
+}
+
+QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const
+{
+ Q_Q(const QQuickAbstractButton);
+ if (group)
+ return qobject_cast<QQuickAbstractButton *>(group->checkedButton());
+
+ const QList<QQuickAbstractButton *> buttons = findExclusiveButtons();
+ // TODO: A singular QRadioButton can be unchecked, which seems logical,
+ // because there's nothing to be exclusive with. However, a RadioButton
+ // from QtQuick.Controls 1.x can never be unchecked, which is the behavior
+ // that QQuickRadioButton adopted. Uncommenting the following count check
+ // gives the QRadioButton behavior. Notice that tst_radiobutton.qml needs
+ // to be updated.
+ if (!autoExclusive /*|| buttons.count() == 1*/)
+ return nullptr;
+
+ for (QQuickAbstractButton *button : buttons) {
+ if (button->isChecked() && button != q)
+ return button;
+ }
+ return checked ? const_cast<QQuickAbstractButton *>(q) : nullptr;
+}
+
+QList<QQuickAbstractButton *> QQuickAbstractButtonPrivate::findExclusiveButtons() const
+{
+ QList<QQuickAbstractButton *> buttons;
+ if (group) {
+ QQmlListProperty<QQuickAbstractButton> groupButtons = group->buttons();
+ int count = groupButtons.count(&groupButtons);
+ for (int i = 0; i < count; ++i) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(groupButtons.at(&groupButtons, i));
+ if (button)
+ buttons += button;
+ }
+ } else if (parentItem) {
+ const auto childItems = parentItem->childItems();
+ for (QQuickItem *child : childItems) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(child);
+ if (button && button->autoExclusive() && !QQuickAbstractButtonPrivate::get(button)->group)
+ buttons += button;
+ }
+ }
+ return buttons;
+}
+
+QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent)
+ : QQuickControl(*(new QQuickAbstractButtonPrivate), parent)
+{
+ setActiveFocusOnTab(true);
+#ifdef Q_OS_MACOS
+ setFocusPolicy(Qt::TabFocus);
+#else
+ setFocusPolicy(Qt::StrongFocus);
+#endif
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent)
+ : QQuickControl(dd, parent)
+{
+ setActiveFocusOnTab(true);
+#ifdef Q_OS_MACOS
+ setFocusPolicy(Qt::TabFocus);
+#else
+ setFocusPolicy(Qt::StrongFocus);
+#endif
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickAbstractButton::~QQuickAbstractButton()
+{
+ Q_D(QQuickAbstractButton);
+ d->removeImplicitSizeListener(d->indicator);
+ if (d->group)
+ d->group->removeButton(this);
+#if QT_CONFIG(shortcut)
+ d->ungrabShortcut();
+#endif
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::AbstractButton::text
+
+ This property holds a textual description of the button.
+
+ \note The text is used for accessibility purposes, so it makes sense to
+ set a textual description even if the content item is an image.
+
+ \sa icon, display, {Control::contentItem}{contentItem}
+*/
+QString QQuickAbstractButton::text() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->explicitText || !d->action ? d->text : d->action->text();
+}
+
+void QQuickAbstractButton::setText(const QString &text)
+{
+ Q_D(QQuickAbstractButton);
+ d->setText(text, true);
+}
+
+void QQuickAbstractButton::resetText()
+{
+ Q_D(QQuickAbstractButton);
+ d->setText(QString(), false);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::down
+
+ This property holds whether the button is visually down.
+
+ Unless explicitly set, this property follows the value of \l pressed. To
+ return to the default value, set this property to \c undefined.
+
+ \sa pressed
+*/
+bool QQuickAbstractButton::isDown() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->down;
+}
+
+void QQuickAbstractButton::setDown(bool down)
+{
+ Q_D(QQuickAbstractButton);
+ d->explicitDown = true;
+
+ if (d->down == down)
+ return;
+
+ d->down = down;
+ emit downChanged();
+}
+
+void QQuickAbstractButton::resetDown()
+{
+ Q_D(QQuickAbstractButton);
+ if (!d->explicitDown)
+ return;
+
+ setDown(d->pressed);
+ d->explicitDown = false;
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::pressed
+ \readonly
+
+ This property holds whether the button is physically pressed. A button can
+ be pressed by either touch or key events.
+
+ \sa down
+*/
+bool QQuickAbstractButton::isPressed() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->pressed;
+}
+
+void QQuickAbstractButton::setPressed(bool isPressed)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->pressed == isPressed)
+ return;
+
+ d->pressed = isPressed;
+ setAccessibleProperty("pressed", isPressed);
+ emit pressedChanged();
+ buttonChange(ButtonPressedChanged);
+
+ if (!d->explicitDown) {
+ setDown(d->pressed);
+ d->explicitDown = false;
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::checked
+
+ This property holds whether the button is checked.
+
+ Since Qt 6.2, setting this property no longer affects the
+ \l {AbstractButton::}{checkable} property. Explicitly set the
+ \c checkable property if needed.
+
+ \sa checkable
+*/
+bool QQuickAbstractButton::isChecked() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->checked;
+}
+
+void QQuickAbstractButton::setChecked(bool checked)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->checked == checked)
+ return;
+
+ d->checked = checked;
+ if (d->action)
+ d->action->setChecked(checked);
+ setAccessibleProperty("checked", checked);
+ buttonChange(ButtonCheckedChange);
+ emit checkedChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::checkable
+
+ This property holds whether the button is checkable.
+
+ A checkable button toggles between checked (on) and unchecked (off) when
+ the user clicks on it or presses the space bar while the button has active
+ focus.
+
+ The default value is \c false.
+
+ \sa checked
+*/
+bool QQuickAbstractButton::isCheckable() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->checkable;
+}
+
+void QQuickAbstractButton::setCheckable(bool checkable)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->checkable == checkable)
+ return;
+
+ d->checkable = checkable;
+ if (d->action)
+ d->action->setCheckable(checkable);
+ setAccessibleProperty("checkable", checkable);
+ buttonChange(ButtonCheckableChange);
+ emit checkableChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::autoExclusive
+
+ This property holds whether auto-exclusivity is enabled.
+
+ If auto-exclusivity is enabled, checkable buttons that belong to the same
+ parent item behave as if they were part of the same ButtonGroup. Only
+ one button can be checked at any time; checking another button automatically
+ unchecks the previously checked one.
+
+ \note The property has no effect on buttons that belong to a ButtonGroup.
+
+ RadioButton and TabButton are auto-exclusive by default.
+*/
+bool QQuickAbstractButton::autoExclusive() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->autoExclusive;
+}
+
+void QQuickAbstractButton::setAutoExclusive(bool exclusive)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->autoExclusive == exclusive)
+ return;
+
+ d->autoExclusive = exclusive;
+ emit autoExclusiveChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::AbstractButton::autoRepeat
+
+ This property holds whether the button repeats \l pressed(), \l released()
+ and \l clicked() signals while the button is pressed and held down.
+
+ If this property is set to \c true, the \l pressAndHold() signal will not
+ be emitted.
+
+ The default value is \c false.
+
+ The initial delay and the repetition interval are defined in milliseconds
+ by \l autoRepeatDelay and \l autoRepeatInterval.
+*/
+bool QQuickAbstractButton::autoRepeat() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->autoRepeat;
+}
+
+void QQuickAbstractButton::setAutoRepeat(bool repeat)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->autoRepeat == repeat)
+ return;
+
+ d->stopPressRepeat();
+ d->autoRepeat = repeat;
+ emit autoRepeatChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::AbstractButton::indicator
+
+ This property holds the indicator item.
+*/
+QQuickItem *QQuickAbstractButton::indicator() const
+{
+ QQuickAbstractButtonPrivate *d = const_cast<QQuickAbstractButtonPrivate *>(d_func());
+ if (!d->indicator)
+ d->executeIndicator();
+ return d->indicator;
+}
+
+void QQuickAbstractButton::setIndicator(QQuickItem *indicator)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->indicator == indicator)
+ return;
+
+ if (!d->indicator.isExecuting())
+ d->cancelIndicator();
+
+ const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
+ const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
+
+ d->removeImplicitSizeListener(d->indicator);
+ QQuickControlPrivate::hideOldItem(d->indicator);
+ d->indicator = indicator;
+
+ if (indicator) {
+ if (!indicator->parentItem())
+ indicator->setParentItem(this);
+ indicator->setAcceptedMouseButtons(Qt::LeftButton);
+ d->addImplicitSizeListener(indicator);
+ }
+
+ if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
+ emit implicitIndicatorWidthChanged();
+ if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
+ emit implicitIndicatorHeightChanged();
+ if (!d->indicator.isExecuting())
+ emit indicatorChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::AbstractButton::icon.name
+ \qmlproperty url QtQuick.Controls::AbstractButton::icon.source
+ \qmlproperty int QtQuick.Controls::AbstractButton::icon.width
+ \qmlproperty int QtQuick.Controls::AbstractButton::icon.height
+ \qmlproperty color QtQuick.Controls::AbstractButton::icon.color
+ \qmlproperty bool QtQuick.Controls::AbstractButton::icon.cache
+
+ This property group was added in QtQuick.Controls 2.3.
+
+ \include qquickicon.qdocinc grouped-properties
+
+ \sa text, display, {Icons in Qt Quick Controls}
+*/
+
+QQuickIcon QQuickAbstractButton::icon() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->effectiveIcon;
+}
+
+void QQuickAbstractButton::setIcon(const QQuickIcon &icon)
+{
+ Q_D(QQuickAbstractButton);
+ d->icon = icon;
+ d->icon.ensureRelativeSourceResolved(this);
+ d->updateEffectiveIcon();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty enumeration QtQuick.Controls::AbstractButton::display
+
+ This property determines how the \l icon and \l text are displayed within
+ the button.
+
+ \table
+ \header \li Display \li Result
+ \row \li \c AbstractButton.IconOnly \li \image qtquickcontrols2-button-icononly.png
+ \row \li \c AbstractButton.TextOnly \li \image qtquickcontrols2-button-textonly.png
+ \row \li \c AbstractButton.TextBesideIcon \li \image qtquickcontrols2-button-textbesideicon.png
+ \row \li \c AbstractButton.TextUnderIcon \li \image qtquickcontrols2-button-textundericon.png
+ \endtable
+
+ \sa {Control::}{spacing}, {Control::}{padding}
+*/
+QQuickAbstractButton::Display QQuickAbstractButton::display() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->display;
+}
+
+void QQuickAbstractButton::setDisplay(Display display)
+{
+ Q_D(QQuickAbstractButton);
+ if (display == d->display)
+ return;
+
+ d->display = display;
+ emit displayChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Action QtQuick.Controls::AbstractButton::action
+
+ This property holds the button action.
+
+ \sa Action
+*/
+QQuickAction *QQuickAbstractButton::action() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->action;
+}
+
+void QQuickAbstractButton::setAction(QQuickAction *action)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->action == action)
+ return;
+
+ const QString oldText = text();
+
+ if (QQuickAction *oldAction = d->action.data()) {
+ QQuickActionPrivate::get(oldAction)->unregisterItem(this);
+ QObjectPrivate::disconnect(oldAction, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click);
+ QObjectPrivate::disconnect(oldAction, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange);
+
+ QObjectPrivate::disconnect(oldAction, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon);
+ disconnect(oldAction, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked);
+ disconnect(oldAction, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable);
+ disconnect(oldAction, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled);
+ }
+
+ if (action) {
+ QQuickActionPrivate::get(action)->registerItem(this);
+ QObjectPrivate::connect(action, &QQuickAction::triggered, d, &QQuickAbstractButtonPrivate::click);
+ QObjectPrivate::connect(action, &QQuickAction::textChanged, d, &QQuickAbstractButtonPrivate::actionTextChange);
+
+ QObjectPrivate::connect(action, &QQuickAction::iconChanged, d, &QQuickAbstractButtonPrivate::updateEffectiveIcon);
+ connect(action, &QQuickAction::checkedChanged, this, &QQuickAbstractButton::setChecked);
+ connect(action, &QQuickAction::checkableChanged, this, &QQuickAbstractButton::setCheckable);
+ connect(action, &QQuickAction::enabledChanged, this, &QQuickItem::setEnabled);
+
+ setChecked(action->isChecked());
+ setCheckable(action->isCheckable());
+ setEnabled(action->isEnabled());
+ }
+
+ d->action = action;
+
+ if (oldText != text())
+ buttonChange(ButtonTextChange);
+
+ d->updateEffectiveIcon();
+
+ emit actionChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatDelay
+
+ This property holds the initial delay of auto-repetition in milliseconds.
+ The default value is \c 300 ms.
+
+ \sa autoRepeat, autoRepeatInterval
+*/
+int QQuickAbstractButton::autoRepeatDelay() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->repeatDelay;
+}
+
+void QQuickAbstractButton::setAutoRepeatDelay(int delay)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->repeatDelay == delay)
+ return;
+
+ d->repeatDelay = delay;
+ emit autoRepeatDelayChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty int QtQuick.Controls::AbstractButton::autoRepeatInterval
+
+ This property holds the interval of auto-repetition in milliseconds.
+ The default value is \c 100 ms.
+
+ \sa autoRepeat, autoRepeatDelay
+*/
+int QQuickAbstractButton::autoRepeatInterval() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->repeatInterval;
+}
+
+void QQuickAbstractButton::setAutoRepeatInterval(int interval)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->repeatInterval == interval)
+ return;
+
+ d->repeatInterval = interval;
+ emit autoRepeatIntervalChanged();
+}
+
+#if QT_CONFIG(shortcut)
+QKeySequence QQuickAbstractButton::shortcut() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->shortcut;
+}
+
+void QQuickAbstractButton::setShortcut(const QKeySequence &shortcut)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->shortcut == shortcut)
+ return;
+
+ d->ungrabShortcut();
+ d->shortcut = shortcut;
+ if (isVisible())
+ d->grabShortcut();
+}
+#endif
+
+/*!
+ \readonly
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::AbstractButton::pressX
+
+ This property holds the x-coordinate of the last press.
+
+ \note The value is updated on touch moves, but left intact after touch release.
+
+ \sa pressY
+*/
+qreal QQuickAbstractButton::pressX() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->movePoint.x();
+}
+
+/*!
+ \readonly
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::AbstractButton::pressY
+
+ This property holds the y-coordinate of the last press.
+
+ \note The value is updated on touch moves, but left intact after touch release.
+
+ \sa pressX
+*/
+qreal QQuickAbstractButton::pressY() const
+{
+ Q_D(const QQuickAbstractButton);
+ return d->movePoint.y();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorWidth
+ \readonly
+
+ This property holds the implicit indicator width.
+
+ The value is equal to \c {indicator ? indicator.implicitWidth : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentWidth} and
+ \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
+
+ \sa implicitIndicatorHeight
+*/
+qreal QQuickAbstractButton::implicitIndicatorWidth() const
+{
+ Q_D(const QQuickAbstractButton);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::AbstractButton::implicitIndicatorHeight
+ \readonly
+
+ This property holds the implicit indicator height.
+
+ The value is equal to \c {indicator ? indicator.implicitHeight : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentHeight} and
+ \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
+
+ \sa implicitIndicatorWidth
+*/
+qreal QQuickAbstractButton::implicitIndicatorHeight() const
+{
+ Q_D(const QQuickAbstractButton);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitHeight();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::AbstractButton::toggle()
+
+ Toggles the checked state of the button.
+*/
+void QQuickAbstractButton::toggle()
+{
+ Q_D(QQuickAbstractButton);
+ setChecked(!d->checked);
+}
+
+void QQuickAbstractButton::componentComplete()
+{
+ Q_D(QQuickAbstractButton);
+ d->executeIndicator(true);
+ QQuickControl::componentComplete();
+}
+
+bool QQuickAbstractButton::event(QEvent *event)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickAbstractButton);
+ if (event->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
+ if (se->shortcutId() == d->shortcutId) {
+ d->trigger();
+ return true;
+ }
+ }
+#endif
+ return QQuickControl::event(event);
+}
+
+void QQuickAbstractButton::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ QQuickControl::focusOutEvent(event);
+ if (d->touchId == -1) // don't ungrab on multi-touch if another control gets focused
+ d->handleUngrab();
+}
+
+void QQuickAbstractButton::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ QQuickControl::keyPressEvent(event);
+ if (d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) {
+ d->setPressPoint(QPoint(qRound(width() / 2), qRound(height() / 2)));
+ setPressed(true);
+
+ if (d->autoRepeat)
+ d->startRepeatDelay();
+
+ emit pressed();
+ event->accept();
+ }
+}
+
+void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ QQuickControl::keyReleaseEvent(event);
+ if (d->pressed && d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) {
+ setPressed(false);
+
+ nextCheckState();
+ emit released();
+ d->trigger();
+
+ if (d->autoRepeat)
+ d->stopPressRepeat();
+ event->accept();
+ }
+}
+
+void QQuickAbstractButton::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ d->pressButtons = event->buttons();
+ QQuickControl::mousePressEvent(event);
+}
+
+void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ if (d->isDoubleClickConnected()) {
+ QQuickControl::mouseDoubleClickEvent(event);
+ emit doubleClicked();
+ d->wasDoubleClick = true;
+ }
+}
+
+void QQuickAbstractButton::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickAbstractButton);
+ QQuickControl::timerEvent(event);
+ if (event->timerId() == d->holdTimer) {
+ d->stopPressAndHold();
+ d->wasHeld = true;
+ emit pressAndHold();
+ } else if (event->timerId() == d->delayTimer) {
+ d->startPressRepeat();
+ } else if (event->timerId() == d->repeatTimer) {
+ emit released();
+ d->trigger();
+ emit pressed();
+ }
+}
+
+void QQuickAbstractButton::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ QQuickControl::itemChange(change, value);
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickAbstractButton);
+ if (change == ItemVisibleHasChanged) {
+ if (value.boolValue)
+ d->grabShortcut();
+ else
+ d->ungrabShortcut();
+ }
+#endif
+}
+
+void QQuickAbstractButton::buttonChange(ButtonChange change)
+{
+ Q_D(QQuickAbstractButton);
+ switch (change) {
+ case ButtonCheckedChange:
+ if (d->checked) {
+ QQuickAbstractButton *button = d->findCheckedButton();
+ if (button && button != this)
+ button->setChecked(false);
+ }
+ break;
+ case ButtonTextChange: {
+ const QString txt = text();
+ maybeSetAccessibleName(txt);
+#if QT_CONFIG(shortcut)
+ setShortcut(QKeySequence::mnemonic(txt));
+#endif
+ emit textChanged();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void QQuickAbstractButton::nextCheckState()
+{
+ Q_D(QQuickAbstractButton);
+ if (d->checkable && (!d->checked || d->findCheckedButton() != this))
+ d->toggle(!d->checked);
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickAbstractButton::accessibilityActiveChanged(bool active)
+{
+ QQuickControl::accessibilityActiveChanged(active);
+
+ Q_D(QQuickAbstractButton);
+ if (active) {
+ maybeSetAccessibleName(text());
+ setAccessibleProperty("pressed", d->pressed);
+ setAccessibleProperty("checked", d->checked);
+ setAccessibleProperty("checkable", d->checkable);
+ }
+}
+
+QAccessible::Role QQuickAbstractButton::accessibleRole() const
+{
+ Q_D(const QQuickAbstractButton);
+ if (d->checkable) {
+ return QAccessible::CheckBox;
+ }
+ return QAccessible::Button;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickabstractbutton_p.cpp"
diff --git a/src/quicktemplates2/qquickabstractbutton_p.h b/src/quicktemplates2/qquickabstractbutton_p.h
new file mode 100644
index 0000000000..a5dbd733d0
--- /dev/null
+++ b/src/quicktemplates2/qquickabstractbutton_p.h
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKABSTRACTBUTTON_P_H
+#define QQUICKABSTRACTBUTTON_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQuickAbstractButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickAbstractButton : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText RESET resetText NOTIFY textChanged FINAL)
+ Q_PROPERTY(bool down READ isDown WRITE setDown NOTIFY downChanged RESET resetDown FINAL)
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL)
+ Q_PROPERTY(bool autoExclusive READ autoExclusive WRITE setAutoExclusive NOTIFY autoExclusiveChanged FINAL)
+ Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL)
+ Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(QQuickIcon icon READ icon WRITE setIcon NOTIFY iconChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(Display display READ display WRITE setDisplay NOTIFY displayChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(QQuickAction *action READ action WRITE setAction NOTIFY actionChanged FINAL REVISION(2, 3))
+ // 2.4 (Qt 5.11)
+ Q_PROPERTY(int autoRepeatDelay READ autoRepeatDelay WRITE setAutoRepeatDelay NOTIFY autoRepeatDelayChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(int autoRepeatInterval READ autoRepeatInterval WRITE setAutoRepeatInterval NOTIFY autoRepeatIntervalChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal pressX READ pressX NOTIFY pressXChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal pressY READ pressY NOTIFY pressYChanged FINAL REVISION(2, 4))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitIndicatorWidth READ implicitIndicatorWidth NOTIFY implicitIndicatorWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitIndicatorHeight READ implicitIndicatorHeight NOTIFY implicitIndicatorHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "background,contentItem,indicator")
+ QML_NAMED_ELEMENT(AbstractButton)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickAbstractButton(QQuickItem *parent = nullptr);
+ ~QQuickAbstractButton();
+
+ QString text() const;
+ void setText(const QString &text);
+ void resetText();
+
+ bool isDown() const;
+ void setDown(bool down);
+ void resetDown();
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ bool isChecked() const;
+ void setChecked(bool checked);
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+
+ bool autoExclusive() const;
+ void setAutoExclusive(bool exclusive);
+
+ bool autoRepeat() const;
+ void setAutoRepeat(bool repeat);
+
+ QQuickItem *indicator() const;
+ void setIndicator(QQuickItem *indicator);
+
+ // 2.3 (Qt 5.10)
+ QQuickIcon icon() const;
+ void setIcon(const QQuickIcon &icon);
+
+ enum Display {
+ IconOnly,
+ TextOnly,
+ TextBesideIcon,
+ TextUnderIcon
+ };
+ Q_ENUM(Display)
+
+ Display display() const;
+ void setDisplay(Display display);
+
+ QQuickAction *action() const;
+ void setAction(QQuickAction *action);
+
+#if QT_CONFIG(shortcut)
+ QKeySequence shortcut() const;
+ void setShortcut(const QKeySequence &shortcut);
+#endif
+
+ // 2.4 (Qt 5.11)
+ int autoRepeatDelay() const;
+ void setAutoRepeatDelay(int delay);
+
+ int autoRepeatInterval() const;
+ void setAutoRepeatInterval(int interval);
+
+ qreal pressX() const;
+ qreal pressY() const;
+
+ // 2.5 (Qt 5.12)
+ qreal implicitIndicatorWidth() const;
+ qreal implicitIndicatorHeight() const;
+
+public Q_SLOTS:
+ void toggle();
+
+Q_SIGNALS:
+ void pressed();
+ void released();
+ void canceled();
+ void clicked();
+ void pressAndHold();
+ void doubleClicked();
+ void textChanged();
+ void downChanged();
+ void pressedChanged();
+ void checkedChanged();
+ void checkableChanged();
+ void autoExclusiveChanged();
+ void autoRepeatChanged();
+ void indicatorChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void toggled();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void iconChanged();
+ Q_REVISION(2, 3) void displayChanged();
+ Q_REVISION(2, 3) void actionChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void autoRepeatDelayChanged();
+ Q_REVISION(2, 4) void autoRepeatIntervalChanged();
+ Q_REVISION(2, 4) void pressXChanged();
+ Q_REVISION(2, 4) void pressYChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void implicitIndicatorWidthChanged();
+ Q_REVISION(2, 5) void implicitIndicatorHeightChanged();
+
+protected:
+ QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQuickItem *parent);
+
+ void componentComplete() override;
+
+ bool event(QEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+
+ enum ButtonChange {
+ ButtonCheckedChange,
+ ButtonCheckableChange,
+ ButtonPressedChanged,
+ ButtonTextChange
+ };
+ virtual void buttonChange(ButtonChange change);
+
+ virtual void nextCheckState();
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickAbstractButton)
+ Q_DECLARE_PRIVATE(QQuickAbstractButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickAbstractButton)
+
+#endif // QQUICKABSTRACTBUTTON_P_H
diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h
new file mode 100644
index 0000000000..907790dcc8
--- /dev/null
+++ b/src/quicktemplates2/qquickabstractbutton_p_p.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKABSTRACTBUTTON_P_P_H
+#define QQUICKABSTRACTBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/qkeysequence.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQuickButtonGroup;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickAbstractButtonPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickAbstractButton)
+
+public:
+ static QQuickAbstractButtonPrivate *get(QQuickAbstractButton *button)
+ {
+ return button->d_func();
+ }
+
+ void setPressPoint(const QPointF &point);
+ void setMovePoint(const QPointF &point);
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ virtual bool acceptKeyClick(Qt::Key key) const;
+
+ bool isPressAndHoldConnected();
+ bool isDoubleClickConnected();
+ void startPressAndHold();
+ void stopPressAndHold();
+
+ void startRepeatDelay();
+ void startPressRepeat();
+ void stopPressRepeat();
+
+#if QT_CONFIG(shortcut)
+ void grabShortcut();
+ void ungrabShortcut();
+#endif
+
+ QQuickAbstractButton *findCheckedButton() const;
+ QList<QQuickAbstractButton *> findExclusiveButtons() const;
+
+ void actionTextChange();
+ void setText(const QString &text, bool isExplicit);
+
+ void updateEffectiveIcon();
+
+ void click();
+ void trigger();
+ void toggle(bool value);
+
+ void cancelIndicator();
+ void executeIndicator(bool complete = false);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ // copied from qabstractbutton.cpp
+ static const int AUTO_REPEAT_DELAY = 300;
+ static const int AUTO_REPEAT_INTERVAL = 100;
+
+ bool explicitText = false;
+ bool down = false;
+ bool explicitDown = false;
+ bool pressed = false;
+ bool keepPressed = false;
+ bool checked = false;
+ bool checkable = false;
+ bool autoExclusive = false;
+ bool autoRepeat = false;
+ bool wasHeld = false;
+ bool wasDoubleClick = false;
+ int holdTimer = 0;
+ int delayTimer = 0;
+ int repeatTimer = 0;
+ int repeatDelay = AUTO_REPEAT_DELAY;
+ int repeatInterval = AUTO_REPEAT_INTERVAL;
+#if QT_CONFIG(shortcut)
+ int shortcutId = 0;
+ QKeySequence shortcut;
+#endif
+ QString text;
+ QQuickIcon icon;
+ QQuickIcon effectiveIcon;
+ QPointF pressPoint;
+ QPointF movePoint;
+ Qt::MouseButtons pressButtons = Qt::NoButton;
+ QQuickAbstractButton::Display display = QQuickAbstractButton::TextBesideIcon;
+ QQuickDeferredPointer<QQuickItem> indicator;
+ QQuickButtonGroup *group = nullptr;
+ QPointer<QQuickAction> action;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKABSTRACTBUTTON_P_P_H
diff --git a/src/quicktemplates2/qquickaction.cpp b/src/quicktemplates2/qquickaction.cpp
new file mode 100644
index 0000000000..193169162d
--- /dev/null
+++ b/src/quicktemplates2/qquickaction.cpp
@@ -0,0 +1,587 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickaction_p.h"
+#include "qquickaction_p_p.h"
+#include "qquickactiongroup_p.h"
+#include "qquickshortcutcontext_p_p.h"
+
+#include <QtGui/qevent.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/private/qshortcutmap_p.h>
+#endif
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Action
+ \inherits QtObject
+//! \instantiates QQuickAction
+ \inqmlmodule QtQuick.Controls
+ \since 5.10
+ \ingroup utilities
+ \brief Abstract user interface action.
+
+ Action represents an abstract user interface action that can have shortcuts
+ and can be assigned to menu items and toolbar buttons.
+
+ Actions may contain \l text, an \l icon, and a \l shortcut. Actions are normally
+ \l triggered by the user via menu items, toolbar buttons, or keyboard shortcuts.
+ A \l checkable Action toggles its \l checked state when triggered.
+
+ \snippet qtquickcontrols2-action.qml action
+
+ Action is commonly used to implement application commands that can be invoked
+ via menu items, toolbar buttons, and keyboard shortcuts. Since the user expects
+ the commands to be performed in the same way, regardless of the user interface
+ used, it is useful to represent the commands as shareable actions.
+
+ Action can be also used to separate the logic and the visual presentation. For
+ example, when declaring buttons and menu items in \c .ui.qml files, actions can
+ be declared elsewhere and assigned from the outside.
+
+ \snippet qtquickcontrols2-action.qml toolbutton
+
+ When an action is paired with buttons and menu items, the \c enabled, \c checkable,
+ and \c checked states are synced automatically. For example, in a word processor,
+ if the user clicks a "Bold" toolbar button, the "Bold" menu item will automatically
+ be checked. Buttons and menu items get their \c text and \c icon from the action by
+ default. An action-specific \c text or \c icon can be overridden for a specific
+ control by specifying \c text or \c icon directly on the control.
+
+ \snippet qtquickcontrols2-action.qml menuitem
+
+ Since Action presents a user interface action, it is intended to be assigned to
+ a \l MenuItem, \l ToolButton, or any other control that inherits \l AbstractButton.
+ For keyboard shortcuts, the simpler \l Shortcut type is more appropriate.
+
+ \sa MenuItem, ToolButton, Shortcut
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Action::toggled(QtObject source)
+
+ This signal is emitted when the action is toggled. The \a source argument
+ identifies the object that toggled the action.
+
+ For example, if the action is assigned to a menu item and a toolbar button, the
+ action is toggled when the control is toggled, the shortcut is activated, or
+ when \l toggle() is called directly.
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Action::triggered(QtObject source)
+
+ This signal is emitted when the action is triggered. The \a source argument
+ identifies the object that triggered the action.
+
+ For example, if the action is assigned to a menu item and a toolbar button, the
+ action is triggered when the control is clicked, the shortcut is activated, or
+ when \l trigger() is called directly.
+*/
+
+#if QT_CONFIG(shortcut)
+static QKeySequence variantToKeySequence(const QVariant &var)
+{
+ if (var.metaType().id() == QMetaType::Int)
+ return QKeySequence(static_cast<QKeySequence::StandardKey>(var.toInt()));
+ return QKeySequence::fromString(var.toString());
+}
+
+QQuickActionPrivate::ShortcutEntry::ShortcutEntry(QObject *target)
+ : m_target(target)
+{
+}
+
+QQuickActionPrivate::ShortcutEntry::~ShortcutEntry()
+{
+ ungrab();
+}
+
+QObject *QQuickActionPrivate::ShortcutEntry::target() const
+{
+ return m_target;
+}
+
+int QQuickActionPrivate::ShortcutEntry::shortcutId() const
+{
+ return m_shortcutId;
+}
+
+void QQuickActionPrivate::ShortcutEntry::grab(const QKeySequence &shortcut, bool enabled)
+{
+ if (shortcut.isEmpty() || m_shortcutId)
+ return;
+
+ Qt::ShortcutContext context = Qt::WindowShortcut; // TODO
+ m_shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(m_target, shortcut, context, QQuickShortcutContext::matcher);
+
+ if (!enabled)
+ QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(false, m_shortcutId, m_target);
+}
+
+void QQuickActionPrivate::ShortcutEntry::ungrab()
+{
+ if (!m_shortcutId)
+ return;
+
+ QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, m_target);
+ m_shortcutId = 0;
+}
+
+void QQuickActionPrivate::ShortcutEntry::setEnabled(bool enabled)
+{
+ if (!m_shortcutId)
+ return;
+
+ QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, m_shortcutId, m_target);
+}
+
+QVariant QQuickActionPrivate::shortcut() const
+{
+ return vshortcut;
+}
+
+void QQuickActionPrivate::setShortcut(const QVariant &var)
+{
+ Q_Q(QQuickAction);
+ if (vshortcut == var)
+ return;
+
+ defaultShortcutEntry->ungrab();
+ for (QQuickActionPrivate::ShortcutEntry *entry : qAsConst(shortcutEntries))
+ entry->ungrab();
+
+ vshortcut = var;
+ keySequence = variantToKeySequence(var);
+
+ defaultShortcutEntry->grab(keySequence, enabled);
+ for (QQuickActionPrivate::ShortcutEntry *entry : qAsConst(shortcutEntries))
+ entry->grab(keySequence, enabled);
+
+ emit q->shortcutChanged(keySequence);
+}
+#endif // QT_CONFIG(shortcut)
+
+void QQuickActionPrivate::setEnabled(bool enable)
+{
+ Q_Q(QQuickAction);
+ if (enabled == enable)
+ return;
+
+ enabled = enable;
+
+#if QT_CONFIG(shortcut)
+ defaultShortcutEntry->setEnabled(enable);
+ for (QQuickActionPrivate::ShortcutEntry *entry : qAsConst(shortcutEntries))
+ entry->setEnabled(enable);
+#endif
+
+ emit q->enabledChanged(enable);
+}
+
+bool QQuickActionPrivate::watchItem(QQuickItem *item)
+{
+ Q_Q(QQuickAction);
+ if (!item)
+ return false;
+
+ item->installEventFilter(q);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed);
+ return true;
+}
+
+bool QQuickActionPrivate::unwatchItem(QQuickItem *item)
+{
+ Q_Q(QQuickAction);
+ if (!item)
+ return false;
+
+ item->removeEventFilter(q);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed);
+ return true;
+}
+
+void QQuickActionPrivate::registerItem(QQuickItem *item)
+{
+ if (!watchItem(item))
+ return;
+
+#if QT_CONFIG(shortcut)
+ QQuickActionPrivate::ShortcutEntry *entry = new QQuickActionPrivate::ShortcutEntry(item);
+ if (item->isVisible())
+ entry->grab(keySequence, enabled);
+ shortcutEntries += entry;
+
+ updateDefaultShortcutEntry();
+#endif
+}
+
+void QQuickActionPrivate::unregisterItem(QQuickItem *item)
+{
+#if QT_CONFIG(shortcut)
+ QQuickActionPrivate::ShortcutEntry *entry = findShortcutEntry(item);
+ if (!entry || !unwatchItem(item))
+ return;
+
+ shortcutEntries.removeOne(entry);
+ delete entry;
+
+ updateDefaultShortcutEntry();
+#else
+ Q_UNUSED(item);
+#endif
+}
+
+void QQuickActionPrivate::itemVisibilityChanged(QQuickItem *item)
+{
+#if QT_CONFIG(shortcut)
+ QQuickActionPrivate::ShortcutEntry *entry = findShortcutEntry(item);
+ if (!entry)
+ return;
+
+ if (item->isVisible())
+ entry->grab(keySequence, enabled);
+ else
+ entry->ungrab();
+
+ updateDefaultShortcutEntry();
+#else
+ Q_UNUSED(item);
+#endif
+}
+
+void QQuickActionPrivate::itemDestroyed(QQuickItem *item)
+{
+ unregisterItem(item);
+}
+
+#if QT_CONFIG(shortcut)
+bool QQuickActionPrivate::handleShortcutEvent(QObject *object, QShortcutEvent *event)
+{
+ Q_Q(QQuickAction);
+ if (event->key() != keySequence)
+ return false;
+
+ QQuickActionPrivate::ShortcutEntry *entry = findShortcutEntry(object);
+ if (!entry || event->shortcutId() != entry->shortcutId())
+ return false;
+
+ q->trigger(entry->target());
+ return true;
+}
+
+QQuickActionPrivate::ShortcutEntry *QQuickActionPrivate::findShortcutEntry(QObject *target) const
+{
+ Q_Q(const QQuickAction);
+ if (target == q)
+ return defaultShortcutEntry;
+ for (QQuickActionPrivate::ShortcutEntry *entry : shortcutEntries) {
+ if (entry->target() == target)
+ return entry;
+ }
+ return nullptr;
+}
+
+void QQuickActionPrivate::updateDefaultShortcutEntry()
+{
+ bool hasActiveShortcutEntries = false;
+ for (QQuickActionPrivate::ShortcutEntry *entry : qAsConst(shortcutEntries)) {
+ if (entry->shortcutId()) {
+ hasActiveShortcutEntries = true;
+ break;
+ }
+ }
+
+ if (hasActiveShortcutEntries)
+ defaultShortcutEntry->ungrab();
+ else if (!defaultShortcutEntry->shortcutId())
+ defaultShortcutEntry->grab(keySequence, enabled);
+}
+#endif // QT_CONFIG(shortcut)
+
+QQuickAction::QQuickAction(QObject *parent)
+ : QObject(*(new QQuickActionPrivate), parent)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickAction);
+ d->defaultShortcutEntry = new QQuickActionPrivate::ShortcutEntry(this);
+#endif
+}
+
+QQuickAction::~QQuickAction()
+{
+ Q_D(QQuickAction);
+ if (d->group)
+ d->group->removeAction(this);
+
+#if QT_CONFIG(shortcut)
+ for (QQuickActionPrivate::ShortcutEntry *entry : qAsConst(d->shortcutEntries))
+ d->unwatchItem(qobject_cast<QQuickItem *>(entry->target()));
+
+ qDeleteAll(d->shortcutEntries);
+ delete d->defaultShortcutEntry;
+#endif
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::Action::text
+
+ This property holds a textual description of the action.
+*/
+QString QQuickAction::text() const
+{
+ Q_D(const QQuickAction);
+ return d->text;
+}
+
+void QQuickAction::setText(const QString &text)
+{
+ Q_D(QQuickAction);
+ if (d->text == text)
+ return;
+
+ d->text = text;
+ emit textChanged(text);
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::Action::icon.name
+ \qmlproperty url QtQuick.Controls::Action::icon.source
+ \qmlproperty int QtQuick.Controls::Action::icon.width
+ \qmlproperty int QtQuick.Controls::Action::icon.height
+ \qmlproperty color QtQuick.Controls::Action::icon.color
+ \qmlproperty bool QtQuick.Controls::Action::icon.cache
+
+ \include qquickicon.qdocinc grouped-properties
+*/
+QQuickIcon QQuickAction::icon() const
+{
+ Q_D(const QQuickAction);
+ return d->icon;
+}
+
+void QQuickAction::setIcon(const QQuickIcon &icon)
+{
+ Q_D(QQuickAction);
+ if (d->icon == icon)
+ return;
+
+ d->icon = icon;
+ d->icon.ensureRelativeSourceResolved(this);
+ emit iconChanged(icon);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Action::enabled
+
+ This property holds whether the action is enabled. The default value is \c true.
+*/
+bool QQuickAction::isEnabled() const
+{
+ Q_D(const QQuickAction);
+ return d->enabled && (!d->group || d->group->isEnabled());
+}
+
+void QQuickAction::setEnabled(bool enabled)
+{
+ Q_D(QQuickAction);
+ d->explicitEnabled = true;
+ d->setEnabled(enabled);
+}
+
+void QQuickAction::resetEnabled()
+{
+ Q_D(QQuickAction);
+ if (!d->explicitEnabled)
+ return;
+
+ d->explicitEnabled = false;
+ d->setEnabled(true);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Action::checked
+
+ This property holds whether the action is checked.
+
+ \sa checkable
+*/
+bool QQuickAction::isChecked() const
+{
+ Q_D(const QQuickAction);
+ return d->checked;
+}
+
+void QQuickAction::setChecked(bool checked)
+{
+ Q_D(QQuickAction);
+ if (d->checked == checked)
+ return;
+
+ d->checked = checked;
+ emit checkedChanged(checked);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Action::checkable
+
+ This property holds whether the action is checkable. The default value is \c false.
+
+ A checkable action toggles between checked (on) and unchecked (off) when triggered.
+
+ \sa checked
+*/
+bool QQuickAction::isCheckable() const
+{
+ Q_D(const QQuickAction);
+ return d->checkable;
+}
+
+void QQuickAction::setCheckable(bool checkable)
+{
+ Q_D(QQuickAction);
+ if (d->checkable == checkable)
+ return;
+
+ d->checkable = checkable;
+ emit checkableChanged(checkable);
+}
+
+#if QT_CONFIG(shortcut)
+/*!
+ \qmlproperty keysequence QtQuick.Controls::Action::shortcut
+
+ This property holds the action's shortcut. The key sequence can be set
+ to one of the \l{QKeySequence::StandardKey}{standard keyboard shortcuts},
+ or it can be described with a string containing a sequence of up to four
+ key presses that are needed to trigger the shortcut.
+
+ \code
+ Action {
+ shortcut: "Ctrl+E,Ctrl+W"
+ onTriggered: edit.wrapMode = TextEdit.Wrap
+ }
+ \endcode
+*/
+QKeySequence QQuickAction::shortcut() const
+{
+ Q_D(const QQuickAction);
+ return d->keySequence;
+}
+
+void QQuickAction::setShortcut(const QKeySequence &shortcut)
+{
+ Q_D(QQuickAction);
+ d->setShortcut(shortcut.toString());
+}
+#endif // QT_CONFIG(shortcut)
+
+/*!
+ \qmlmethod void QtQuick.Controls::Action::toggle(QtObject source)
+
+ Toggles the action and emits \l toggled() if enabled, with an optional \a source object defined.
+*/
+void QQuickAction::toggle(QObject *source)
+{
+ Q_D(QQuickAction);
+ if (!d->enabled)
+ return;
+
+ if (d->checkable)
+ setChecked(!d->checked);
+
+ emit toggled(source);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Action::trigger(QtObject source)
+
+ Triggers the action and emits \l triggered() if enabled, with an optional \a source object defined.
+*/
+void QQuickAction::trigger(QObject *source)
+{
+ Q_D(QQuickAction);
+ d->trigger(source, true);
+}
+
+void QQuickActionPrivate::trigger(QObject* source, bool doToggle)
+{
+ Q_Q(QQuickAction);
+ if (!enabled)
+ return;
+
+ QPointer<QObject> guard = q;
+ // the checked action of an exclusive group cannot be unchecked
+ if (checkable && (!checked || !group || !group->isExclusive() || group->checkedAction() != q)) {
+ if (doToggle)
+ q->toggle(source);
+ else
+ emit q->toggled(source);
+ }
+
+ if (!guard.isNull())
+ emit q->triggered(source);
+}
+
+bool QQuickAction::event(QEvent *event)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickAction);
+ if (event->type() == QEvent::Shortcut)
+ return d->handleShortcutEvent(this, static_cast<QShortcutEvent *>(event));
+#endif
+ return QObject::event(event);
+}
+
+bool QQuickAction::eventFilter(QObject *object, QEvent *event)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickAction);
+ if (event->type() == QEvent::Shortcut)
+ return d->handleShortcutEvent(object, static_cast<QShortcutEvent *>(event));
+#else
+ Q_UNUSED(object);
+ Q_UNUSED(event);
+#endif
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickaction_p.cpp"
diff --git a/src/quicktemplates2/qquickaction_p.h b/src/quicktemplates2/qquickaction_p.h
new file mode 100644
index 0000000000..f600d89ed7
--- /dev/null
+++ b/src/quicktemplates2/qquickaction_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKACTION_P_H
+#define QQUICKACTION_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 <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtQuickTemplates2/private/qquickicon_p.h>
+#include <QtCore/qobject.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIcon;
+class QQuickActionPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickAction : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(QQuickIcon icon READ icon WRITE setIcon NOTIFY iconChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged RESET resetEnabled FINAL)
+ Q_PROPERTY(bool checked READ isChecked WRITE setChecked NOTIFY checkedChanged FINAL)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY checkableChanged FINAL)
+#if QT_CONFIG(shortcut)
+ Q_PRIVATE_PROPERTY(QQuickAction::d_func(), QVariant shortcut READ shortcut WRITE setShortcut NOTIFY shortcutChanged FINAL)
+#endif
+ QML_NAMED_ELEMENT(Action)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickAction(QObject *parent = nullptr);
+ ~QQuickAction();
+
+ QString text() const;
+ void setText(const QString &text);
+
+ QQuickIcon icon() const;
+ void setIcon(const QQuickIcon &icon);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+ void resetEnabled();
+
+ bool isChecked() const;
+ void setChecked(bool checked);
+
+ bool isCheckable() const;
+ void setCheckable(bool checkable);
+
+#if QT_CONFIG(shortcut)
+ QKeySequence shortcut() const;
+ void setShortcut(const QKeySequence &shortcut);
+#endif
+
+public Q_SLOTS:
+ void toggle(QObject *source = nullptr);
+ void trigger(QObject *source = nullptr);
+
+Q_SIGNALS:
+ void textChanged(const QString &text);
+ void iconChanged(const QQuickIcon &icon);
+ void enabledChanged(bool enabled);
+ void checkedChanged(bool checked);
+ void checkableChanged(bool checkable);
+#if QT_CONFIG(shortcut)
+ void shortcutChanged(const QKeySequence &shortcut);
+#endif
+
+ void toggled(QObject *source = nullptr);
+ void triggered(QObject *source = nullptr);
+
+protected:
+ bool event(QEvent *event) override;
+ bool eventFilter(QObject *object, QEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickAction)
+ Q_DECLARE_PRIVATE(QQuickAction)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickAction)
+
+#endif // QQUICKACTION_P_H
diff --git a/src/quicktemplates2/qquickaction_p_p.h b/src/quicktemplates2/qquickaction_p_p.h
new file mode 100644
index 0000000000..d9b83548c9
--- /dev/null
+++ b/src/quicktemplates2/qquickaction_p_p.h
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKACTION_P_P_H
+#define QQUICKACTION_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 <QtCore/private/qobject_p.h>
+#include <QtCore/qvariant.h>
+#include <QtCore/qstring.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/qkeysequence.h>
+#endif
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QShortcutEvent;
+class QQuickActionGroup;
+
+class QQuickActionPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickAction)
+
+public:
+ static QQuickActionPrivate *get(QQuickAction *action)
+ {
+ return action->d_func();
+ }
+
+#if QT_CONFIG(shortcut)
+ QVariant shortcut() const;
+ void setShortcut(const QVariant &shortcut);
+#endif
+
+ void setEnabled(bool enable);
+
+ bool watchItem(QQuickItem *item);
+ bool unwatchItem(QQuickItem *item);
+
+ void registerItem(QQuickItem *item);
+ void unregisterItem(QQuickItem *item);
+
+ void itemVisibilityChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ bool handleShortcutEvent(QObject *object, QShortcutEvent *event);
+
+ void trigger(QObject*, bool doToggle);
+
+#if QT_CONFIG(shortcut)
+ class ShortcutEntry
+ {
+ public:
+ explicit ShortcutEntry(QObject *target);
+ ~ShortcutEntry();
+
+ QObject *target() const;
+ int shortcutId() const;
+
+ void grab(const QKeySequence &vshortcut, bool enabled);
+ void ungrab();
+
+ void setEnabled(bool enabled);
+
+ private:
+ int m_shortcutId = 0;
+ QObject *m_target = nullptr;
+ };
+
+ ShortcutEntry *findShortcutEntry(QObject *target) const;
+ void updateDefaultShortcutEntry();
+#endif // QT_CONFIG(shortcut)
+
+ bool explicitEnabled = false;
+ bool enabled = true;
+ bool checked = false;
+ bool checkable = false;
+ QString text;
+ QQuickIcon icon;
+#if QT_CONFIG(shortcut)
+ QKeySequence keySequence;
+ QVariant vshortcut;
+ ShortcutEntry *defaultShortcutEntry = nullptr;
+ QList<ShortcutEntry *> shortcutEntries;
+#endif
+ QQuickActionGroup *group = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKACTION_P_P_H
diff --git a/src/quicktemplates2/qquickactiongroup.cpp b/src/quicktemplates2/qquickactiongroup.cpp
new file mode 100644
index 0000000000..1656ecf51e
--- /dev/null
+++ b/src/quicktemplates2/qquickactiongroup.cpp
@@ -0,0 +1,471 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickactiongroup_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvariant.h>
+#include <QtQml/qqmlinfo.h>
+
+#include "qquickaction_p.h"
+#include "qquickaction_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ActionGroup
+ \inherits QtObject
+//! \instantiates QQuickActionGroup
+ \inqmlmodule QtQuick.Controls
+ \since 5.10
+ \ingroup utilities
+ \brief Groups actions together.
+
+ ActionGroup is a non-visual group of actions. A mutually \l exclusive
+ action group is used with actions where only one of the options can be
+ selected at a time.
+
+ The most straight-forward way to use ActionGroup is to declare actions
+ as children of the group.
+
+ \code
+ ActionGroup {
+ id: alignmentGroup
+
+ Action {
+ checked: true
+ checkable: true
+ text: qsTr("Left")
+ }
+
+ Action {
+ checkable: true
+ text: qsTr("Center")
+ }
+
+ Action {
+ checkable: true
+ text: qsTr("Right")
+ }
+ }
+ \endcode
+
+ Alternatively, the \l group attached property allows declaring the actions
+ elsewhere and assigning them to a specific group.
+
+ \code
+ ActionGroup { id: alignmentGroup }
+
+ Action {
+ checked: true
+ checkable: true
+ text: qsTr("Left")
+ ActionGroup.group: alignmentGroup
+ }
+
+ Action {
+ checkable: true
+ text: qsTr("Center")
+ ActionGroup.group: alignmentGroup
+ }
+
+ Action {
+ checkable: true
+ text: qsTr("Right")
+ ActionGroup.group: alignmentGroup
+ }
+ \endcode
+
+ More advanced use cases can be handled using the \c addAction() and
+ \c removeAction() methods.
+
+ \sa Action, ButtonGroup
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::ActionGroup::triggered(Action action)
+
+ This signal is emitted when an \a action in the group has been triggered.
+
+ This signal is convenient for implementing a common signal handler for
+ all actions in the same group.
+
+ \code
+ ActionGroup {
+ onTriggered: console.log("triggered:", action.text)
+
+ Action { text: "First" }
+ Action { text: "Second" }
+ Action { text: "Third" }
+ }
+ \endcode
+
+ \sa Action::triggered()
+*/
+
+class QQuickActionGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickActionGroup)
+
+public:
+ void clear();
+ void actionTriggered();
+ void _q_updateCurrent();
+
+ static bool changeEnabled(QQuickAction *action, bool enabled);
+
+ static void actions_append(QQmlListProperty<QQuickAction> *prop, QQuickAction *obj);
+ static qsizetype actions_count(QQmlListProperty<QQuickAction> *prop);
+ static QQuickAction *actions_at(QQmlListProperty<QQuickAction> *prop, qsizetype index);
+ static void actions_clear(QQmlListProperty<QQuickAction> *prop);
+
+ bool enabled = true;
+ bool exclusive = true;
+ QPointer<QQuickAction> checkedAction;
+ QList<QQuickAction*> actions;
+};
+
+void QQuickActionGroupPrivate::clear()
+{
+ for (QQuickAction *action : qAsConst(actions)) {
+ QQuickActionPrivate::get(action)->group = nullptr;
+ QObjectPrivate::disconnect(action, &QQuickAction::triggered, this, &QQuickActionGroupPrivate::actionTriggered);
+ QObjectPrivate::disconnect(action, &QQuickAction::checkedChanged, this, &QQuickActionGroupPrivate::_q_updateCurrent);
+ }
+ actions.clear();
+}
+
+void QQuickActionGroupPrivate::actionTriggered()
+{
+ Q_Q(QQuickActionGroup);
+ QQuickAction *action = qobject_cast<QQuickAction*>(q->sender());
+ if (action)
+ emit q->triggered(action);
+}
+
+void QQuickActionGroupPrivate::_q_updateCurrent()
+{
+ Q_Q(QQuickActionGroup);
+ if (!exclusive)
+ return;
+ QQuickAction *action = qobject_cast<QQuickAction*>(q->sender());
+ if (action && action->isChecked())
+ q->setCheckedAction(action);
+ else if (!actions.contains(checkedAction))
+ q->setCheckedAction(nullptr);
+}
+
+bool QQuickActionGroupPrivate::changeEnabled(QQuickAction *action, bool enabled)
+{
+ return action->isEnabled() != enabled && (!enabled || !QQuickActionPrivate::get(action)->explicitEnabled);
+}
+
+void QQuickActionGroupPrivate::actions_append(QQmlListProperty<QQuickAction> *prop, QQuickAction *obj)
+{
+ QQuickActionGroup *q = static_cast<QQuickActionGroup *>(prop->object);
+ q->addAction(obj);
+}
+
+qsizetype QQuickActionGroupPrivate::actions_count(QQmlListProperty<QQuickAction> *prop)
+{
+ QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
+ return p->actions.count();
+}
+
+QQuickAction *QQuickActionGroupPrivate::actions_at(QQmlListProperty<QQuickAction> *prop, qsizetype index)
+{
+ QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
+ return p->actions.value(index);
+}
+
+void QQuickActionGroupPrivate::actions_clear(QQmlListProperty<QQuickAction> *prop)
+{
+ QQuickActionGroupPrivate *p = static_cast<QQuickActionGroupPrivate *>(prop->data);
+ if (!p->actions.isEmpty()) {
+ p->clear();
+ QQuickActionGroup *q = static_cast<QQuickActionGroup *>(prop->object);
+ // QTBUG-52358: don't clear the checked action immediately
+ QMetaObject::invokeMethod(q, "_q_updateCurrent", Qt::QueuedConnection);
+ emit q->actionsChanged();
+ }
+}
+
+QQuickActionGroup::QQuickActionGroup(QObject *parent)
+ : QObject(*(new QQuickActionGroupPrivate), parent)
+{
+}
+
+QQuickActionGroup::~QQuickActionGroup()
+{
+ Q_D(QQuickActionGroup);
+ d->clear();
+}
+
+QQuickActionGroupAttached *QQuickActionGroup::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickActionGroupAttached(object);
+}
+
+/*!
+ \qmlproperty Action QtQuick.Controls::ActionGroup::checkedAction
+
+ This property holds the currently selected action in an exclusive group,
+ or \c null if there is none or the group is non-exclusive.
+
+ By default, it is the first checked action added to an exclusive action group.
+
+ \sa exclusive
+*/
+QQuickAction *QQuickActionGroup::checkedAction() const
+{
+ Q_D(const QQuickActionGroup);
+ return d->checkedAction;
+}
+
+void QQuickActionGroup::setCheckedAction(QQuickAction *checkedAction)
+{
+ Q_D(QQuickActionGroup);
+ if (d->checkedAction == checkedAction)
+ return;
+
+ if (d->checkedAction)
+ d->checkedAction->setChecked(false);
+ d->checkedAction = checkedAction;
+ if (checkedAction)
+ checkedAction->setChecked(true);
+ emit checkedActionChanged();
+}
+
+/*!
+ \qmlproperty list<Action> QtQuick.Controls::ActionGroup::actions
+ \qmldefault
+
+ This property holds the list of actions in the group.
+
+ \sa group
+*/
+QQmlListProperty<QQuickAction> QQuickActionGroup::actions()
+{
+ Q_D(QQuickActionGroup);
+ return QQmlListProperty<QQuickAction>(this, d,
+ QQuickActionGroupPrivate::actions_append,
+ QQuickActionGroupPrivate::actions_count,
+ QQuickActionGroupPrivate::actions_at,
+ QQuickActionGroupPrivate::actions_clear);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ActionGroup::exclusive
+
+ This property holds whether the action group is exclusive. The default value is \c true.
+
+ If this property is \c true, then only one action in the group can be checked at any given time.
+ The user can trigger any action to check it, and that action will replace the existing one as
+ the checked action in the group.
+
+ In an exclusive group, the user cannot uncheck the currently checked action by triggering it;
+ instead, another action in the group must be triggered to set the new checked action for that
+ group.
+
+ In a non-exclusive group, checking and unchecking actions does not affect the other actions in
+ the group. Furthermore, the value of the \l checkedAction property is \c null.
+*/
+bool QQuickActionGroup::isExclusive() const
+{
+ Q_D(const QQuickActionGroup);
+ return d->exclusive;
+}
+
+void QQuickActionGroup::setExclusive(bool exclusive)
+{
+ Q_D(QQuickActionGroup);
+ if (d->exclusive == exclusive)
+ return;
+
+ d->exclusive = exclusive;
+ emit exclusiveChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ActionGroup::enabled
+
+ This property holds whether the action group is enabled. The default value is \c true.
+
+ If this property is \c false, then all actions in the group are disabled. If this property
+ is \c true, all actions in the group are enabled, unless explicitly disabled.
+*/
+bool QQuickActionGroup::isEnabled() const
+{
+ Q_D(const QQuickActionGroup);
+ return d->enabled;
+}
+
+void QQuickActionGroup::setEnabled(bool enabled)
+{
+ Q_D(QQuickActionGroup);
+ if (d->enabled == enabled)
+ return;
+
+ for (QQuickAction *action : qAsConst(d->actions)) {
+ if (d->changeEnabled(action, enabled))
+ emit action->enabledChanged(enabled);
+ }
+
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ActionGroup::addAction(Action action)
+
+ Adds an \a action to the action group.
+
+ \note Manually adding objects to a action group is typically unnecessary.
+ The \l actions property and the \l group attached property provide a
+ convenient and declarative syntax.
+
+ \sa actions, group
+*/
+void QQuickActionGroup::addAction(QQuickAction *action)
+{
+ Q_D(QQuickActionGroup);
+ if (!action || d->actions.contains(action))
+ return;
+
+ const bool enabledChange = d->changeEnabled(action, d->enabled);
+
+ QQuickActionPrivate::get(action)->group = this;
+ QObjectPrivate::connect(action, &QQuickAction::triggered, d, &QQuickActionGroupPrivate::actionTriggered);
+ QObjectPrivate::connect(action, &QQuickAction::checkedChanged, d, &QQuickActionGroupPrivate::_q_updateCurrent);
+
+ if (d->exclusive && action->isChecked())
+ setCheckedAction(action);
+ if (enabledChange)
+ emit action->enabledChanged(action->isEnabled());
+
+ d->actions.append(action);
+ emit actionsChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ActionGroup::removeAction(Action action)
+
+ Removes an \a action from the action group.
+
+ \note Manually removing objects from a action group is typically unnecessary.
+ The \l actions property and the \l group attached property provide a
+ convenient and declarative syntax.
+
+ \sa actions, group
+*/
+void QQuickActionGroup::removeAction(QQuickAction *action)
+{
+ Q_D(QQuickActionGroup);
+ if (!action || !d->actions.contains(action))
+ return;
+
+ const bool enabledChange = d->changeEnabled(action, d->enabled);
+
+ QQuickActionPrivate::get(action)->group = nullptr;
+ QObjectPrivate::disconnect(action, &QQuickAction::triggered, d, &QQuickActionGroupPrivate::actionTriggered);
+ QObjectPrivate::disconnect(action, &QQuickAction::checkedChanged, d, &QQuickActionGroupPrivate::_q_updateCurrent);
+
+ if (d->checkedAction == action)
+ setCheckedAction(nullptr);
+ if (enabledChange)
+ emit action->enabledChanged(action->isEnabled());
+
+ d->actions.removeOne(action);
+ emit actionsChanged();
+}
+
+class QQuickActionGroupAttachedPrivate : public QObjectPrivate
+{
+public:
+ QQuickActionGroup *group = nullptr;
+};
+
+QQuickActionGroupAttached::QQuickActionGroupAttached(QObject *parent)
+ : QObject(*(new QQuickActionGroupAttachedPrivate), parent)
+{
+}
+
+/*!
+ \qmlattachedproperty ActionGroup QtQuick.Controls::ActionGroup::group
+
+ This property attaches an action to an action group.
+
+ \code
+ ActionGroup { id: group }
+
+ Action {
+ checked: true
+ text: qsTr("Option A")
+ ActionGroup.group: group
+ }
+
+ Action {
+ text: qsTr("Option B")
+ ActionGroup.group: group
+ }
+ \endcode
+
+ \sa actions
+*/
+QQuickActionGroup *QQuickActionGroupAttached::group() const
+{
+ Q_D(const QQuickActionGroupAttached);
+ return d->group;
+}
+
+void QQuickActionGroupAttached::setGroup(QQuickActionGroup *group)
+{
+ Q_D(QQuickActionGroupAttached);
+ if (d->group == group)
+ return;
+
+ if (d->group)
+ d->group->removeAction(qobject_cast<QQuickAction*>(parent()));
+ d->group = group;
+ if (group)
+ group->addAction(qobject_cast<QQuickAction*>(parent()));
+ emit groupChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickactiongroup_p.cpp"
diff --git a/src/quicktemplates2/qquickactiongroup_p.h b/src/quicktemplates2/qquickactiongroup_p.h
new file mode 100644
index 0000000000..d905f59598
--- /dev/null
+++ b/src/quicktemplates2/qquickactiongroup_p.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKACTIONGROUP_P_H
+#define QQUICKACTIONGROUP_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 <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQuickActionGroupPrivate;
+class QQuickActionGroupAttached;
+class QQuickActionGroupAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickActionGroup : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickAction *checkedAction READ checkedAction WRITE setCheckedAction NOTIFY checkedActionChanged FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickAction> actions READ actions NOTIFY actionsChanged FINAL)
+ Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive NOTIFY exclusiveChanged FINAL)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "actions")
+ QML_NAMED_ELEMENT(ActionGroup)
+ QML_ATTACHED(QQuickActionGroupAttached)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickActionGroup(QObject *parent = nullptr);
+ ~QQuickActionGroup();
+
+ static QQuickActionGroupAttached *qmlAttachedProperties(QObject *object);
+
+ QQuickAction *checkedAction() const;
+ void setCheckedAction(QQuickAction *checkedAction);
+
+ QQmlListProperty<QQuickAction> actions();
+
+ bool isExclusive() const;
+ void setExclusive(bool exclusive);
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+public Q_SLOTS:
+ void addAction(QQuickAction *action);
+ void removeAction(QQuickAction *action);
+
+Q_SIGNALS:
+ void checkedActionChanged();
+ void actionsChanged();
+ void exclusiveChanged();
+ void enabledChanged();
+ void triggered(QQuickAction *action);
+
+private:
+ Q_DISABLE_COPY(QQuickActionGroup)
+ Q_DECLARE_PRIVATE(QQuickActionGroup)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCurrent())
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickActionGroupAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickActionGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL)
+
+public:
+ explicit QQuickActionGroupAttached(QObject *parent = nullptr);
+
+ QQuickActionGroup *group() const;
+ void setGroup(QQuickActionGroup *group);
+
+Q_SIGNALS:
+ void groupChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickActionGroupAttached)
+ Q_DECLARE_PRIVATE(QQuickActionGroupAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickActionGroup)
+QML_DECLARE_TYPEINFO(QQuickActionGroup, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKACTIONGROUP_P_H
diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp
new file mode 100644
index 0000000000..eb1d12c930
--- /dev/null
+++ b/src/quicktemplates2/qquickapplicationwindow.cpp
@@ -0,0 +1,955 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickapplicationwindow_p.h"
+#include "qquickcontentitem_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquicktextarea_p.h"
+#include "qquicktextfield_p.h"
+#include "qquicktoolbar_p.h"
+#include "qquicktabbar_p.h"
+#include "qquickdialogbuttonbox_p.h"
+#include "qquickdeferredexecute_p_p.h"
+#include "qquickdeferredpointer_p_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuick/private/qquickwindowmodule_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ApplicationWindow
+ \inherits Window
+//! \instantiates QQuickApplicationWindow
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Styled top-level window with support for a header and footer.
+
+ ApplicationWindow is a \l Window which makes it convenient to add
+ a \l {menuBar}{menu bar}, \l header and \l footer item to the window.
+
+ You can declare ApplicationWindow as the root item of your application,
+ and run it by using \l QQmlApplicationEngine. In this way you can control
+ the window's properties, appearance and layout from QML.
+
+ \image qtquickcontrols2-applicationwindow-wireframe.png
+
+ \qml
+ import QtQuick.Controls 2.12
+
+ ApplicationWindow {
+ visible: true
+
+ menuBar: MenuBar {
+ // ...
+ }
+
+ header: ToolBar {
+ // ...
+ }
+
+ footer: TabBar {
+ // ...
+ }
+
+ StackView {
+ anchors.fill: parent
+ }
+ }
+ \endqml
+
+ \note By default, an ApplicationWindow is not visible.
+
+ \section2 Attached ApplicationWindow Properties
+
+ Due to how \l {Scope and Naming Resolution} works in QML, it is possible
+ to reference the \c id of the application root element anywhere in its
+ child QML objects. Even though this approach is fine for many applications
+ and use cases, for a generic QML component it may not be acceptable as it
+ creates a dependency to the surrounding environment.
+
+ ApplicationWindow provides a set of attached properties that can be used
+ to access the window and its building blocks from places where no direct
+ access to the window is available, without creating a dependency to a
+ certain window \c id. A QML component that uses the ApplicationWindow
+ attached properties works in any window regardless of its \c id.
+
+ \sa {Customizing ApplicationWindow}, Overlay, Page, {Container Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+static const QQuickItemPrivate::ChangeTypes ItemChanges = QQuickItemPrivate::Visibility
+ | QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickApplicationWindowPrivate
+ : public QQuickWindowQmlImplPrivate
+ , public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickApplicationWindow)
+
+public:
+ QQuickApplicationWindowPrivate()
+ {
+ complete = true;
+ }
+
+ static QQuickApplicationWindowPrivate *get(QQuickApplicationWindow *window)
+ {
+ return window->d_func();
+ }
+
+ QQmlListProperty<QObject> contentData();
+
+ void relayout();
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemVisibilityChanged(QQuickItem *item) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void updateFont(const QFont &f);
+ inline void setFont_helper(const QFont &f) {
+ if (font.resolveMask() == f.resolveMask() && font == f)
+ return;
+ updateFont(f);
+ }
+ void resolveFont();
+
+ void _q_updateActiveFocus();
+ void setActiveFocusControl(QQuickItem *item);
+
+ static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+
+ void cancelBackground();
+ void executeBackground(bool complete = false);
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::System); }
+ void updateChildrenPalettes(const QPalette &parentPalette) override
+ {
+ // Update regular children
+ QQuickWindowPrivate::updateChildrenPalettes(parentPalette);
+
+ // And cover one special case
+ for (auto &&popup : q_func()->findChildren<QQuickPopup *>())
+ QQuickPopupPrivate::get(popup)->inheritPalette(parentPalette);
+ }
+
+ QQuickDeferredPointer<QQuickItem> background;
+ QQuickItem *appWindowContentItem = nullptr;
+ QQuickItem *menuBar = nullptr;
+ QQuickItem *header = nullptr;
+ QQuickItem *footer = nullptr;
+ QFont font;
+ QLocale locale;
+ QQuickItem *activeFocusControl = nullptr;
+ bool insideRelayout = false;
+};
+
+static void layoutItem(QQuickItem *item, qreal y, qreal width)
+{
+ if (!item)
+ return;
+
+ item->setY(y);
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid()) {
+ item->setWidth(width);
+ p->widthValidFlag = false;
+ }
+}
+
+void QQuickApplicationWindowPrivate::relayout()
+{
+ Q_Q(QQuickApplicationWindow);
+ if (!complete || insideRelayout)
+ return;
+
+ QScopedValueRollback<bool> guard(insideRelayout, true);
+ QQuickItem *content = q->contentItem();
+ qreal hh = header && header->isVisible() ? header->height() : 0;
+ qreal fh = footer && footer->isVisible() ? footer->height() : 0;
+ qreal mbh = menuBar && menuBar->isVisible() ? menuBar->height() : 0;
+
+ content->setY(mbh + hh);
+ content->setWidth(q->width());
+ content->setHeight(q->height() - mbh - hh - fh);
+
+ layoutItem(menuBar, -mbh - hh, q->width());
+ layoutItem(header, -hh, q->width());
+ layoutItem(footer, content->height(), q->width());
+
+ if (background) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (!p->widthValid() && qFuzzyIsNull(background->x())) {
+ background->setWidth(q->width());
+ p->widthValidFlag = false;
+ }
+ if (!p->heightValid() && qFuzzyIsNull(background->y())) {
+ background->setHeight(q->height());
+ p->heightValidFlag = false;
+ }
+ }
+}
+
+void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(change);
+ Q_UNUSED(diff);
+ relayout();
+}
+
+void QQuickApplicationWindowPrivate::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ relayout();
+}
+
+void QQuickApplicationWindowPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ relayout();
+}
+
+void QQuickApplicationWindowPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ relayout();
+}
+
+void QQuickApplicationWindowPrivate::updateFont(const QFont &f)
+{
+ Q_Q(QQuickApplicationWindow);
+ const bool changed = font != f;
+ font = f;
+
+ QQuickControlPrivate::updateFontRecur(q->QQuickWindow::contentItem(), f);
+
+ const QList<QQuickPopup *> popups = q->findChildren<QQuickPopup *>();
+ for (QQuickPopup *popup : popups)
+ QQuickControlPrivate::get(static_cast<QQuickControl *>(popup->popupItem()))->inheritFont(f);
+
+ if (changed)
+ emit q->fontChanged();
+}
+
+void QQuickApplicationWindowPrivate::resolveFont()
+{
+ QFont resolvedFont = font.resolve(QQuickTheme::font(QQuickTheme::System));
+ setFont_helper(resolvedFont);
+}
+
+static QQuickItem *findActiveFocusControl(QQuickWindow *window)
+{
+ QQuickItem *item = window->activeFocusItem();
+ while (item) {
+ if (qobject_cast<QQuickControl *>(item) || qobject_cast<QQuickTextField *>(item) || qobject_cast<QQuickTextArea *>(item))
+ return item;
+ item = item->parentItem();
+ }
+ return item;
+}
+
+void QQuickApplicationWindowPrivate::_q_updateActiveFocus()
+{
+ Q_Q(QQuickApplicationWindow);
+ setActiveFocusControl(findActiveFocusControl(q));
+}
+
+void QQuickApplicationWindowPrivate::setActiveFocusControl(QQuickItem *control)
+{
+ Q_Q(QQuickApplicationWindow);
+ if (activeFocusControl != control) {
+ activeFocusControl = control;
+ emit q->activeFocusControlChanged();
+ }
+}
+
+void QQuickApplicationWindowPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
+{
+ QQuickItemPrivate::data_append(prop, obj);
+
+ // associate "top-level" popups with the window as soon as they are added to the default property
+ if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(obj))
+ QQuickPopupPrivate::get(popup)->setWindow(static_cast<QQuickApplicationWindow *>(prop->data));
+}
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickApplicationWindowPrivate::cancelBackground()
+{
+ Q_Q(QQuickApplicationWindow);
+ quickCancelDeferred(q, backgroundName());
+}
+
+void QQuickApplicationWindowPrivate::executeBackground(bool complete)
+{
+ Q_Q(QQuickApplicationWindow);
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
+}
+
+QQuickApplicationWindow::QQuickApplicationWindow(QWindow *parent)
+ : QQuickWindowQmlImpl(*(new QQuickApplicationWindowPrivate), parent)
+{
+ connect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus()));
+}
+
+QQuickApplicationWindow::~QQuickApplicationWindow()
+{
+ Q_D(QQuickApplicationWindow);
+ d->setActiveFocusControl(nullptr);
+ disconnect(this, SIGNAL(activeFocusItemChanged()), this, SLOT(_q_updateActiveFocus()));
+ if (d->menuBar)
+ QQuickItemPrivate::get(d->menuBar)->removeItemChangeListener(d, ItemChanges);
+ if (d->header)
+ QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, ItemChanges);
+ if (d->footer)
+ QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, ItemChanges);
+}
+
+QQuickApplicationWindowAttached *QQuickApplicationWindow::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickApplicationWindowAttached(object);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::ApplicationWindow::background
+
+ This property holds the background item.
+
+ The background item is stacked under the \l {contentItem}{content item},
+ but above the \l {Window::color}{background color} of the window.
+
+ The background item is useful for images and gradients, for example,
+ but the \l {Window::}{color} property is preferable for solid colors,
+ as it doesn't need to create an item.
+
+ \note If the background item has no explicit size specified, it automatically
+ follows the control's size. In most cases, there is no need to specify
+ width or height for a background item.
+
+ \sa {Customizing ApplicationWindow}, contentItem, header, footer
+*/
+QQuickItem *QQuickApplicationWindow::background() const
+{
+ QQuickApplicationWindowPrivate *d = const_cast<QQuickApplicationWindowPrivate *>(d_func());
+ if (!d->background)
+ d->executeBackground();
+ return d->background;
+}
+
+void QQuickApplicationWindow::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->background == background)
+ return;
+
+ if (!d->background.isExecuting())
+ d->cancelBackground();
+
+ QQuickControlPrivate::hideOldItem(d->background);
+ d->background = background;
+ if (background) {
+ background->setParentItem(QQuickWindow::contentItem());
+ if (qFuzzyIsNull(background->z()))
+ background->setZ(-1);
+ if (isComponentComplete())
+ d->relayout();
+ }
+ if (!d->background.isExecuting())
+ emit backgroundChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::ApplicationWindow::header
+
+ This property holds the window header item. The header item is positioned at the
+ top of the window, below the menu bar, and resized to the width of the window.
+ The default value is \c null.
+
+ \code
+ ApplicationWindow {
+ header: TabBar {
+ // ...
+ }
+ }
+ \endcode
+
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window header
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Header.
+
+ \sa menuBar, footer, Page::header
+*/
+QQuickItem *QQuickApplicationWindow::header() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->header;
+}
+
+void QQuickApplicationWindow::setHeader(QQuickItem *header)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->header == header)
+ return;
+
+ if (d->header) {
+ QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, ItemChanges);
+ d->header->setParentItem(nullptr);
+ }
+ d->header = header;
+ if (header) {
+ header->setParentItem(contentItem());
+ QQuickItemPrivate *p = QQuickItemPrivate::get(header);
+ p->addItemChangeListener(d, ItemChanges);
+ if (qFuzzyIsNull(header->z()))
+ header->setZ(1);
+ if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(header))
+ toolBar->setPosition(QQuickToolBar::Header);
+ else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(header))
+ tabBar->setPosition(QQuickTabBar::Header);
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(header))
+ buttonBox->setPosition(QQuickDialogButtonBox::Header);
+ }
+ if (isComponentComplete())
+ d->relayout();
+ emit headerChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::ApplicationWindow::footer
+
+ This property holds the window footer item. The footer item is positioned to
+ the bottom, and resized to the width of the window. The default value is \c null.
+
+ \code
+ ApplicationWindow {
+ footer: ToolBar {
+ // ...
+ }
+ }
+ \endcode
+
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window footer
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Footer.
+
+ \sa menuBar, header, Page::footer
+*/
+QQuickItem *QQuickApplicationWindow::footer() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->footer;
+}
+
+void QQuickApplicationWindow::setFooter(QQuickItem *footer)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->footer == footer)
+ return;
+
+ if (d->footer) {
+ QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, ItemChanges);
+ d->footer->setParentItem(nullptr);
+ }
+ d->footer = footer;
+ if (footer) {
+ footer->setParentItem(contentItem());
+ QQuickItemPrivate *p = QQuickItemPrivate::get(footer);
+ p->addItemChangeListener(d, ItemChanges);
+ if (qFuzzyIsNull(footer->z()))
+ footer->setZ(1);
+ if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(footer))
+ toolBar->setPosition(QQuickToolBar::Footer);
+ else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(footer))
+ tabBar->setPosition(QQuickTabBar::Footer);
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(footer))
+ buttonBox->setPosition(QQuickDialogButtonBox::Footer);
+ }
+ if (isComponentComplete())
+ d->relayout();
+ emit footerChanged();
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::ApplicationWindow::contentData
+ \qmldefault
+
+ This default property holds the list of all objects declared as children of
+ the window.
+
+ The data property allows you to freely mix visual children, resources and
+ other windows in an ApplicationWindow.
+
+ If you assign an Item to the contentData list, it becomes a child of the
+ window's contentItem, so that it appears inside the window. The item's
+ parent will be the window's \l contentItem.
+
+ It should not generally be necessary to refer to the contentData property,
+ as it is the default property for ApplicationWindow and thus all child
+ items are automatically assigned to this property.
+
+ \sa contentItem
+*/
+QQmlListProperty<QObject> QQuickApplicationWindowPrivate::contentData()
+{
+ Q_Q(QQuickApplicationWindow);
+ return QQmlListProperty<QObject>(q->contentItem(), q,
+ QQuickApplicationWindowPrivate::contentData_append,
+ QQuickItemPrivate::data_count,
+ QQuickItemPrivate::data_at,
+ QQuickItemPrivate::data_clear);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::ApplicationWindow::contentItem
+ \readonly
+
+ This property holds the window content item.
+
+ The content item is stacked above the \l background item, and under the
+ \l menuBar, \l header, and \l footer items.
+
+ \sa background, menuBar, header, footer
+*/
+QQuickItem *QQuickApplicationWindow::contentItem() const
+{
+ QQuickApplicationWindowPrivate *d = const_cast<QQuickApplicationWindowPrivate *>(d_func());
+ if (!d->appWindowContentItem) {
+ d->appWindowContentItem = new QQuickContentItem(this, QQuickWindow::contentItem());
+ d->appWindowContentItem->setFlag(QQuickItem::ItemIsFocusScope);
+ d->appWindowContentItem->setFocus(true);
+ d->relayout();
+ }
+ return d->appWindowContentItem;
+}
+
+/*!
+ \qmlproperty Control QtQuick.Controls::ApplicationWindow::activeFocusControl
+ \readonly
+
+ This property holds the control that currently has active focus, or \c null if there is
+ no control with active focus.
+
+ The difference between \l Window::activeFocusItem and ApplicationWindow::activeFocusControl
+ is that the former may point to a building block of a control, whereas the latter points
+ to the enclosing control. For example, when SpinBox has focus, activeFocusItem points to
+ the editor and activeFocusControl to the SpinBox itself.
+
+ \sa Window::activeFocusItem
+*/
+QQuickItem *QQuickApplicationWindow::activeFocusControl() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->activeFocusControl;
+}
+
+/*!
+ \qmlproperty font QtQuick.Controls::ApplicationWindow::font
+
+ This property holds the font currently set for the window.
+
+ The default font depends on the system environment. QGuiApplication maintains a system/theme
+ font which serves as a default for all application windows. You can also set the default font
+ for windows by passing a custom font to QGuiApplication::setFont(), before loading any QML.
+ Finally, the font is matched against Qt's font database to find the best match.
+
+ ApplicationWindow propagates explicit font properties to child controls. If you change a specific
+ property on the window's font, that property propagates to all child controls in the window,
+ overriding any system defaults for that property.
+
+ \sa Control::font
+*/
+QFont QQuickApplicationWindow::font() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->font;
+}
+
+void QQuickApplicationWindow::setFont(const QFont &font)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->font.resolveMask() == font.resolveMask() && d->font == font)
+ return;
+
+ QFont resolvedFont = font.resolve(QQuickTheme::font(QQuickTheme::System));
+ d->setFont_helper(resolvedFont);
+}
+
+void QQuickApplicationWindow::resetFont()
+{
+ setFont(QFont());
+}
+
+/*!
+ \qmlproperty Locale QtQuick.Controls::ApplicationWindow::locale
+
+ This property holds the locale of the window.
+
+ The default locale depends on the system environment. You can set the
+ default locale by calling QLocale::setDefault(), before loading any QML.
+
+ ApplicationWindow propagates the locale to child controls. If you change
+ the window's locale, that locale propagates to all child controls in the
+ window, overriding the system default locale.
+
+ \sa Control::locale
+*/
+QLocale QQuickApplicationWindow::locale() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->locale;
+}
+
+void QQuickApplicationWindow::setLocale(const QLocale &locale)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->locale == locale)
+ return;
+
+ d->locale = locale;
+ QQuickControlPrivate::updateLocaleRecur(QQuickWindow::contentItem(), locale);
+
+ // TODO: internal QQuickPopupManager that provides reliable access to all QQuickPopup instances
+ const QList<QQuickPopup *> popups = QQuickWindow::contentItem()->findChildren<QQuickPopup *>();
+ for (QQuickPopup *popup : popups)
+ QQuickControlPrivate::get(static_cast<QQuickControl *>(popup->popupItem()))->updateLocale(locale, false); // explicit=false
+
+ emit localeChanged();
+}
+
+void QQuickApplicationWindow::resetLocale()
+{
+ setLocale(QLocale());
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Item QtQuick.Controls::ApplicationWindow::menuBar
+
+ This property holds the window menu bar. The menu bar is positioned at the
+ top of the window, above the header, and resized to the width of the window.
+ The default value is \c null.
+
+ \code
+ ApplicationWindow {
+ menuBar: MenuBar {
+ // ...
+ }
+ }
+ \endcode
+
+ \sa header, footer, MenuBar
+*/
+QQuickItem *QQuickApplicationWindow::menuBar() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->menuBar;
+}
+
+void QQuickApplicationWindow::setMenuBar(QQuickItem *menuBar)
+{
+ Q_D(QQuickApplicationWindow);
+ if (d->menuBar == menuBar)
+ return;
+
+ if (d->menuBar) {
+ QQuickItemPrivate::get(d->menuBar)->removeItemChangeListener(d, ItemChanges);
+ d->menuBar->setParentItem(nullptr);
+ }
+ d->menuBar = menuBar;
+ if (menuBar) {
+ menuBar->setParentItem(contentItem());
+ QQuickItemPrivate *p = QQuickItemPrivate::get(menuBar);
+ p->addItemChangeListener(d, ItemChanges);
+ if (qFuzzyIsNull(menuBar->z()))
+ menuBar->setZ(2);
+ }
+ if (isComponentComplete())
+ d->relayout();
+ emit menuBarChanged();
+}
+
+bool QQuickApplicationWindow::isComponentComplete() const
+{
+ Q_D(const QQuickApplicationWindow);
+ return d->complete;
+}
+
+void QQuickApplicationWindow::classBegin()
+{
+ Q_D(QQuickApplicationWindow);
+ d->complete = false;
+ QQuickWindowQmlImpl::classBegin();
+ d->resolveFont();
+}
+
+void QQuickApplicationWindow::componentComplete()
+{
+ Q_D(QQuickApplicationWindow);
+ d->complete = true;
+ d->executeBackground(true);
+ QQuickWindowQmlImpl::componentComplete();
+ d->relayout();
+}
+
+void QQuickApplicationWindow::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QQuickApplicationWindow);
+ QQuickWindowQmlImpl::resizeEvent(event);
+ d->relayout();
+}
+
+class QQuickApplicationWindowAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickApplicationWindowAttached)
+
+public:
+ void windowChange(QQuickWindow *wnd);
+ void activeFocusChange();
+
+ QQuickWindow *window = nullptr;
+ QQuickItem *activeFocusControl = nullptr;
+};
+
+void QQuickApplicationWindowAttachedPrivate::windowChange(QQuickWindow *wnd)
+{
+ Q_Q(QQuickApplicationWindowAttached);
+ if (window == wnd)
+ return;
+
+ QQuickApplicationWindow *oldWindow = qobject_cast<QQuickApplicationWindow *>(window);
+ if (oldWindow && !QQuickApplicationWindowPrivate::get(oldWindow))
+ oldWindow = nullptr; // being deleted (QTBUG-52731)
+
+ if (oldWindow) {
+ disconnect(oldWindow, &QQuickApplicationWindow::activeFocusControlChanged,
+ this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
+ QObject::disconnect(oldWindow, &QQuickApplicationWindow::menuBarChanged,
+ q, &QQuickApplicationWindowAttached::menuBarChanged);
+ QObject::disconnect(oldWindow, &QQuickApplicationWindow::headerChanged,
+ q, &QQuickApplicationWindowAttached::headerChanged);
+ QObject::disconnect(oldWindow, &QQuickApplicationWindow::footerChanged,
+ q, &QQuickApplicationWindowAttached::footerChanged);
+ } else if (window) {
+ disconnect(window, &QQuickWindow::activeFocusItemChanged,
+ this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
+ }
+
+ QQuickApplicationWindow *newWindow = qobject_cast<QQuickApplicationWindow *>(wnd);
+ if (newWindow) {
+ connect(newWindow, &QQuickApplicationWindow::activeFocusControlChanged,
+ this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
+ QObject::connect(newWindow, &QQuickApplicationWindow::menuBarChanged,
+ q, &QQuickApplicationWindowAttached::menuBarChanged);
+ QObject::connect(newWindow, &QQuickApplicationWindow::headerChanged,
+ q, &QQuickApplicationWindowAttached::headerChanged);
+ QObject::connect(newWindow, &QQuickApplicationWindow::footerChanged,
+ q, &QQuickApplicationWindowAttached::footerChanged);
+ } else if (wnd) {
+ connect(wnd, &QQuickWindow::activeFocusItemChanged,
+ this, &QQuickApplicationWindowAttachedPrivate::activeFocusChange);
+ }
+
+ window = wnd;
+ emit q->windowChanged();
+ emit q->contentItemChanged();
+
+ activeFocusChange();
+ if ((oldWindow && oldWindow->menuBar()) || (newWindow && newWindow->menuBar()))
+ emit q->menuBarChanged();
+ if ((oldWindow && oldWindow->header()) || (newWindow && newWindow->header()))
+ emit q->headerChanged();
+ if ((oldWindow && oldWindow->footer()) || (newWindow && newWindow->footer()))
+ emit q->footerChanged();
+}
+
+void QQuickApplicationWindowAttachedPrivate::activeFocusChange()
+{
+ Q_Q(QQuickApplicationWindowAttached);
+ QQuickItem *control = nullptr;
+ if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(window))
+ control = appWindow->activeFocusControl();
+ else if (window)
+ control = findActiveFocusControl(window);
+ if (activeFocusControl == control)
+ return;
+
+ activeFocusControl = control;
+ emit q->activeFocusControlChanged();
+}
+
+QQuickApplicationWindowAttached::QQuickApplicationWindowAttached(QObject *parent)
+ : QObject(*(new QQuickApplicationWindowAttachedPrivate), parent)
+{
+ Q_D(QQuickApplicationWindowAttached);
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
+ d->windowChange(item->window());
+ QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
+ if (!d->window) {
+ QQuickItem *p = item;
+ while (p) {
+ if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(p->parent())) {
+ d->windowChange(popup->window());
+ QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
+ }
+ p = p->parentItem();
+ }
+ }
+ } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
+ d->windowChange(popup->window());
+ QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickApplicationWindowAttachedPrivate::windowChange);
+ }
+}
+
+/*!
+ \qmlattachedproperty ApplicationWindow QtQuick.Controls::ApplicationWindow::window
+ \readonly
+
+ This attached property holds the application window. The property can be attached
+ to any item. The value is \c null if the item is not in an ApplicationWindow.
+
+ \sa {Attached ApplicationWindow Properties}
+*/
+QQuickApplicationWindow *QQuickApplicationWindowAttached::window() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ return qobject_cast<QQuickApplicationWindow *>(d->window);
+}
+
+/*!
+ \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::contentItem
+ \readonly
+
+ This attached property holds the window content item. The property can be attached
+ to any item. The value is \c null if the item is not in an ApplicationWindow.
+
+ \sa {Attached ApplicationWindow Properties}
+*/
+QQuickItem *QQuickApplicationWindowAttached::contentItem() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
+ return window->contentItem();
+ return nullptr;
+}
+
+/*!
+ \qmlattachedproperty Control QtQuick.Controls::ApplicationWindow::activeFocusControl
+ \readonly
+
+ This attached property holds the control that currently has active focus, or \c null
+ if there is no control with active focus. The property can be attached to any item.
+ The value is \c null if the item is not in a window, or the window has no active focus.
+
+ \sa Window::activeFocusItem, {Attached ApplicationWindow Properties}
+*/
+QQuickItem *QQuickApplicationWindowAttached::activeFocusControl() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ return d->activeFocusControl;
+}
+
+/*!
+ \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::header
+ \readonly
+
+ This attached property holds the window header item. The property can be attached
+ to any item. The value is \c null if the item is not in an ApplicationWindow, or
+ the window has no header item.
+
+ \sa {Attached ApplicationWindow Properties}
+*/
+QQuickItem *QQuickApplicationWindowAttached::header() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
+ return window->header();
+ return nullptr;
+}
+
+/*!
+ \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::footer
+ \readonly
+
+ This attached property holds the window footer item. The property can be attached
+ to any item. The value is \c null if the item is not in an ApplicationWindow, or
+ the window has no footer item.
+
+ \sa {Attached ApplicationWindow Properties}
+*/
+QQuickItem *QQuickApplicationWindowAttached::footer() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
+ return window->footer();
+ return nullptr;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlattachedproperty Item QtQuick.Controls::ApplicationWindow::menuBar
+ \readonly
+
+ This attached property holds the window menu bar. The property can be attached
+ to any item. The value is \c null if the item is not in an ApplicationWindow, or
+ the window has no menu bar.
+
+ \sa {Attached ApplicationWindow Properties}
+*/
+QQuickItem *QQuickApplicationWindowAttached::menuBar() const
+{
+ Q_D(const QQuickApplicationWindowAttached);
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(d->window))
+ return window->menuBar();
+ return nullptr;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickapplicationwindow_p.cpp"
diff --git a/src/quicktemplates2/qquickapplicationwindow_p.h b/src/quicktemplates2/qquickapplicationwindow_p.h
new file mode 100644
index 0000000000..f5aa8b8b1a
--- /dev/null
+++ b/src/quicktemplates2/qquickapplicationwindow_p.h
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKAPPLICATIONWINDOW_P_H
+#define QQUICKAPPLICATIONWINDOW_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>
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+#include <QtCore/qlocale.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickApplicationWindowPrivate;
+class QQuickApplicationWindowAttached;
+class QQuickApplicationWindowAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickApplicationWindow : public QQuickWindowQmlImpl
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QQuickItem *contentItem READ contentItem CONSTANT FINAL)
+ Q_PRIVATE_PROPERTY(QQuickApplicationWindow::d_func(), QQmlListProperty<QObject> contentData READ contentData FINAL)
+ Q_PROPERTY(QQuickItem *activeFocusControl READ activeFocusControl NOTIFY activeFocusControlChanged FINAL)
+ Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL)
+ Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(QQuickItem *menuBar READ menuBar WRITE setMenuBar NOTIFY menuBarChanged FINAL REVISION(2, 3))
+ // 2.14 (Qt 6)
+ Q_PRIVATE_PROPERTY(QQuickApplicationWindow::d_func(), QQuickPalette *palette READ palette WRITE setPalette RESET resetPalette NOTIFY paletteChanged REVISION(2, 3))
+ Q_CLASSINFO("DeferredPropertyNames", "background")
+ Q_CLASSINFO("DefaultProperty", "contentData")
+ QML_NAMED_ELEMENT(ApplicationWindow)
+ QML_ADDED_IN_VERSION(2, 0)
+ QML_ATTACHED(QQuickApplicationWindowAttached)
+
+public:
+ explicit QQuickApplicationWindow(QWindow *parent = nullptr);
+ ~QQuickApplicationWindow();
+
+ static QQuickApplicationWindowAttached *qmlAttachedProperties(QObject *object);
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ QQuickItem *contentItem() const;
+
+ QQuickItem *activeFocusControl() const;
+
+ QQuickItem *header() const;
+ void setHeader(QQuickItem *header);
+
+ QQuickItem *footer() const;
+ void setFooter(QQuickItem *footer);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+ void resetFont();
+
+ QLocale locale() const;
+ void setLocale(const QLocale &locale);
+ void resetLocale();
+
+ QQuickItem *menuBar() const;
+ void setMenuBar(QQuickItem *menuBar);
+
+Q_SIGNALS:
+ void backgroundChanged();
+ void activeFocusControlChanged();
+ void headerChanged();
+ void footerChanged();
+ void fontChanged();
+ void localeChanged();
+ Q_REVISION(2, 3) void menuBarChanged();
+
+protected:
+ bool isComponentComplete() const;
+ void classBegin() override;
+ void componentComplete() override;
+ void resizeEvent(QResizeEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickApplicationWindow)
+ Q_DECLARE_PRIVATE(QQuickApplicationWindow)
+ Q_PRIVATE_SLOT(d_func(), void _q_updateActiveFocus())
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickApplicationWindowAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickApplicationWindow *window READ window NOTIFY windowChanged FINAL)
+ Q_PROPERTY(QQuickItem *contentItem READ contentItem NOTIFY contentItemChanged FINAL)
+ Q_PROPERTY(QQuickItem *activeFocusControl READ activeFocusControl NOTIFY activeFocusControlChanged FINAL)
+ Q_PROPERTY(QQuickItem *header READ header NOTIFY headerChanged FINAL)
+ Q_PROPERTY(QQuickItem *footer READ footer NOTIFY footerChanged FINAL)
+ Q_PROPERTY(QQuickItem *menuBar READ menuBar NOTIFY menuBarChanged FINAL) // REVISION(2, 3)
+
+public:
+ explicit QQuickApplicationWindowAttached(QObject *parent = nullptr);
+
+ QQuickApplicationWindow *window() const;
+ QQuickItem *contentItem() const;
+ QQuickItem *activeFocusControl() const;
+ QQuickItem *header() const;
+ QQuickItem *footer() const;
+ QQuickItem *menuBar() const;
+
+Q_SIGNALS:
+ void windowChanged();
+ void contentItemChanged();
+ void activeFocusControlChanged();
+ void headerChanged();
+ void footerChanged();
+ // 2.3 (Qt 5.10)
+ /*Q_REVISION(2, 3)*/ void menuBarChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickApplicationWindowAttached)
+ Q_DECLARE_PRIVATE(QQuickApplicationWindowAttached)
+};
+
+struct QWindowForeign2
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QWindow)
+ QML_ADDED_IN_VERSION(2, 0)
+};
+
+struct QQuickWindowForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickWindow)
+ QML_ADDED_IN_VERSION(2, 0)
+};
+
+struct QQuickWindowQmlImplForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickWindowQmlImpl)
+ QML_ADDED_IN_VERSION(2, 2)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickApplicationWindow)
+QML_DECLARE_TYPEINFO(QQuickApplicationWindow, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKAPPLICATIONWINDOW_P_H
diff --git a/src/quicktemplates2/qquickbusyindicator.cpp b/src/quicktemplates2/qquickbusyindicator.cpp
new file mode 100644
index 0000000000..1b4f590f63
--- /dev/null
+++ b/src/quicktemplates2/qquickbusyindicator.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbusyindicator_p.h"
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype BusyIndicator
+ \inherits Control
+//! \instantiates QQuickBusyIndicator
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-indicators
+ \brief Indicates background activity, for example, while content is being loaded.
+
+ \image qtquickcontrols2-busyindicator.gif
+
+ The busy indicator should be used to indicate activity while content is
+ being loaded or the UI is blocked waiting for a resource to become available.
+
+ The following snippet shows how to use the BusyIndicator:
+
+ \qml
+ BusyIndicator {
+ running: image.status === Image.Loading
+ }
+ \endqml
+
+ BusyIndicator is similar to an indeterminate \l ProgressBar. Both can be
+ used to indicate background activity. The main difference is visual, and
+ that ProgressBar can also present a concrete amount of progress (when it
+ can be determined). Due to the visual difference, busy indicators and
+ indeterminate progress bars fit different places in user interfaces.
+ Typical places for a busy indicator:
+ \list
+ \li in the corner of a \l ToolBar
+ \li as an overlay on top of a \l Page
+ \li on the side of an \l ItemDelegate
+ \endlist
+
+ \sa {Customizing BusyIndicator}, {Indicator Controls}, ProgressBar
+*/
+
+class QQuickBusyIndicatorPrivate : public QQuickControlPrivate
+{
+public:
+ bool running = true;
+};
+
+QQuickBusyIndicator::QQuickBusyIndicator(QQuickItem *parent)
+ : QQuickControl(*(new QQuickBusyIndicatorPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::BusyIndicator::running
+
+ This property holds whether the busy indicator is currently indicating
+ activity.
+
+ \note The indicator is only visible when this property is set to \c true.
+
+ The default value is \c true.
+*/
+bool QQuickBusyIndicator::isRunning() const
+{
+ Q_D(const QQuickBusyIndicator);
+ return d->running;
+}
+
+void QQuickBusyIndicator::setRunning(bool running)
+{
+ Q_D(QQuickBusyIndicator);
+ if (d->running == running)
+ return;
+
+ d->running = running;
+ emit runningChanged();
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickBusyIndicator::touchEvent(QTouchEvent *event)
+{
+ event->ignore(); // QTBUG-61785
+}
+#endif
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickBusyIndicator::accessibleRole() const
+{
+ return QAccessible::Indicator;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbusyindicator_p.cpp"
diff --git a/src/quicktemplates2/qquickbusyindicator_p.h b/src/quicktemplates2/qquickbusyindicator_p.h
new file mode 100644
index 0000000000..bdb2eb240b
--- /dev/null
+++ b/src/quicktemplates2/qquickbusyindicator_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBUSYINDICATOR_P_H
+#define QQUICKBUSYINDICATOR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickBusyIndicatorPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickBusyIndicator : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged FINAL)
+ QML_NAMED_ELEMENT(BusyIndicator)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickBusyIndicator(QQuickItem *parent = nullptr);
+
+ bool isRunning() const;
+ void setRunning(bool running);
+
+Q_SIGNALS:
+ void runningChanged();
+
+protected:
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickBusyIndicator)
+ Q_DECLARE_PRIVATE(QQuickBusyIndicator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickBusyIndicator)
+
+#endif // QQUICKBUSYINDICATOR_P_H
diff --git a/src/quicktemplates2/qquickbutton.cpp b/src/quicktemplates2/qquickbutton.cpp
new file mode 100644
index 0000000000..beae5287a4
--- /dev/null
+++ b/src/quicktemplates2/qquickbutton.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbutton_p.h"
+#include "qquickbutton_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Button
+ \inherits AbstractButton
+//! \instantiates QQuickButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Push-button that can be clicked to perform a command or answer a question.
+
+ \image qtquickcontrols2-button.gif
+
+ Button presents a push-button control that can be pushed or clicked by
+ the user. Buttons are normally used to perform an action, or to answer
+ a question. Typical buttons are \e OK, \e Apply, \e Cancel, \e Close,
+ \e Yes, \e No, and \e Help.
+
+ Button inherits its API from AbstractButton. For instance, you can set
+ \l {AbstractButton::text}{text}, display an \l {Icons in Qt Quick Controls}{icon},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton API.
+
+ A button emits the signal \l {AbstractButton::}{clicked()} when it is activated by the user.
+ Connect to this signal to perform the button's action. Buttons also
+ provide the signals \l {AbstractButton::}{canceled()}, \l {AbstractButton::}{doubleClicked()}, \l {AbstractButton::}{pressed()},
+ \l {AbstractButton::}{released()} and \l {AbstractButton::}{pressAndHold()} for long presses.
+
+ See the snippet below on how to connect to the button's signals.
+
+ \code
+ RowLayout {
+ Button {
+ text: "Ok"
+ onClicked: model.submit()
+ }
+ Button {
+ text: "Cancel"
+ onClicked: model.revert()
+ }
+ }
+ \endcode
+
+ \sa {Customizing Button}, {Button Controls}
+*/
+
+QQuickButton::QQuickButton(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickButtonPrivate), parent)
+{
+}
+
+QQuickButton::QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent)
+ : QQuickAbstractButton(dd, parent)
+{
+}
+
+QFont QQuickButton::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Button);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Button::highlighted
+
+ This property holds whether the button is highlighted.
+
+ \image qtquickcontrols2-button-highlighted.gif
+
+ A button can be highlighted in order to draw the user's attention towards
+ it. It has no effect on keyboard interaction.
+
+ The default value is \c false.
+*/
+bool QQuickButton::isHighlighted() const
+{
+ Q_D(const QQuickButton);
+ return d->highlighted;
+}
+
+void QQuickButton::setHighlighted(bool highlighted)
+{
+ Q_D(QQuickButton);
+ if (highlighted == d->highlighted)
+ return;
+
+ d->highlighted = highlighted;
+ emit highlightedChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Button::flat
+
+ This property holds whether the button is flat.
+
+ \image qtquickcontrols2-button-flat.gif
+
+ A flat button typically does not draw a background unless it is pressed or checked.
+
+ The default value is \c false.
+*/
+bool QQuickButton::isFlat() const
+{
+ Q_D(const QQuickButton);
+ return d->flat;
+}
+
+void QQuickButton::setFlat(bool flat)
+{
+ Q_D(QQuickButton);
+ if (flat == d->flat)
+ return;
+
+ d->flat = flat;
+ emit flatChanged();
+}
+
+QPalette QQuickButtonPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::Button);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbutton_p.cpp"
diff --git a/src/quicktemplates2/qquickbutton_p.h b/src/quicktemplates2/qquickbutton_p.h
new file mode 100644
index 0000000000..bfac5663b7
--- /dev/null
+++ b/src/quicktemplates2/qquickbutton_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBUTTON_P_H
+#define QQUICKBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickButton : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat NOTIFY flatChanged FINAL)
+ QML_NAMED_ELEMENT(Button)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickButton(QQuickItem *parent = nullptr);
+
+ bool isHighlighted() const;
+ void setHighlighted(bool highlighted);
+
+ bool isFlat() const;
+ void setFlat(bool flat);
+
+Q_SIGNALS:
+ void highlightedChanged();
+ void flatChanged();
+
+protected:
+ QQuickButton(QQuickButtonPrivate &dd, QQuickItem *parent);
+
+ QFont defaultFont() const override;
+
+private:
+ Q_DISABLE_COPY(QQuickButton)
+ Q_DECLARE_PRIVATE(QQuickButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickButton)
+
+#endif // QQUICKBUTTON_P_H
diff --git a/src/quicktemplates2/qquickbutton_p_p.h b/src/quicktemplates2/qquickbutton_p_p.h
new file mode 100644
index 0000000000..e83e320934
--- /dev/null
+++ b/src/quicktemplates2/qquickbutton_p_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBUTTON_P_P_H
+#define QQUICKBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickButtonPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickButton)
+
+public:
+ QPalette defaultPalette() const override;
+
+ bool flat = false;
+ bool highlighted = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKBUTTON_P_P_H
diff --git a/src/quicktemplates2/qquickbuttongroup.cpp b/src/quicktemplates2/qquickbuttongroup.cpp
new file mode 100644
index 0000000000..fd8e822c5f
--- /dev/null
+++ b/src/quicktemplates2/qquickbuttongroup.cpp
@@ -0,0 +1,546 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickbuttongroup_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qvariant.h>
+#include <QtQml/qqmlinfo.h>
+
+#include "qquickabstractbutton_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ButtonGroup
+ \inherits QtObject
+//! \instantiates QQuickButtonGroup
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup utilities
+ \brief Mutually-exclusive group of checkable buttons.
+
+ ButtonGroup is a non-visual, mutually exclusive group of buttons.
+ It is used with controls such as RadioButton, where only one of the options
+ can be selected at a time.
+
+ The most straight-forward way to use ButtonGroup is to assign
+ a list of buttons. For example, the list of children of a
+ \l{Item Positioners}{positioner} or a \l{Qt Quick Layouts}{layout}
+ that manages a group of mutually exclusive buttons.
+
+ \code
+ ButtonGroup {
+ buttons: column.children
+ }
+
+ Column {
+ id: column
+
+ RadioButton {
+ checked: true
+ text: qsTr("DAB")
+ }
+
+ RadioButton {
+ text: qsTr("FM")
+ }
+
+ RadioButton {
+ text: qsTr("AM")
+ }
+ }
+ \endcode
+
+ Mutually exclusive buttons do not always share the same parent item,
+ or the parent layout may sometimes contain items that should not be
+ included in the button group. Such cases are best handled using
+ the \l group attached property.
+
+ \code
+ ButtonGroup { id: radioGroup }
+
+ Column {
+ Label {
+ text: qsTr("Radio:")
+ }
+
+ RadioButton {
+ checked: true
+ text: qsTr("DAB")
+ ButtonGroup.group: radioGroup
+ }
+
+ RadioButton {
+ text: qsTr("FM")
+ ButtonGroup.group: radioGroup
+ }
+
+ RadioButton {
+ text: qsTr("AM")
+ ButtonGroup.group: radioGroup
+ }
+ }
+ \endcode
+
+ More advanced use cases can be handled using the \c addButton() and
+ \c removeButton() methods.
+
+ \sa RadioButton, {Button Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::ButtonGroup::clicked(AbstractButton button)
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This signal is emitted when a \a button in the group has been clicked.
+
+ This signal is convenient for implementing a common signal handler for
+ all buttons in the same group.
+
+ \code
+ ButtonGroup {
+ buttons: column.children
+ onClicked: console.log("clicked:", button.text)
+ }
+
+ Column {
+ id: column
+ Button { text: "First" }
+ Button { text: "Second" }
+ Button { text: "Third" }
+ }
+ \endcode
+
+ \sa AbstractButton::clicked()
+*/
+
+class QQuickButtonGroupPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickButtonGroup)
+
+public:
+ void clear();
+ void buttonClicked();
+ void _q_updateCurrent();
+ void updateCheckState();
+ void setCheckState(Qt::CheckState state);
+
+ static void buttons_append(QQmlListProperty<QQuickAbstractButton> *prop, QQuickAbstractButton *obj);
+ static qsizetype buttons_count(QQmlListProperty<QQuickAbstractButton> *prop);
+ static QQuickAbstractButton *buttons_at(QQmlListProperty<QQuickAbstractButton> *prop, qsizetype index);
+ static void buttons_clear(QQmlListProperty<QQuickAbstractButton> *prop);
+
+ bool complete = true;
+ bool exclusive = true;
+ bool settingCheckState = false;
+ Qt::CheckState checkState = Qt::Unchecked;
+ QPointer<QQuickAbstractButton> checkedButton;
+ QList<QQuickAbstractButton*> buttons;
+};
+
+void QQuickButtonGroupPrivate::clear()
+{
+ for (QQuickAbstractButton *button : qAsConst(buttons)) {
+ QQuickAbstractButtonPrivate::get(button)->group = nullptr;
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, this, &QQuickButtonGroupPrivate::buttonClicked);
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, this, &QQuickButtonGroupPrivate::_q_updateCurrent);
+ }
+ buttons.clear();
+}
+
+void QQuickButtonGroupPrivate::buttonClicked()
+{
+ Q_Q(QQuickButtonGroup);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
+ if (button)
+ emit q->clicked(button);
+}
+
+void QQuickButtonGroupPrivate::_q_updateCurrent()
+{
+ Q_Q(QQuickButtonGroup);
+ if (exclusive) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
+ if (button && button->isChecked())
+ q->setCheckedButton(button);
+ else if (!buttons.contains(checkedButton))
+ q->setCheckedButton(nullptr);
+ }
+ updateCheckState();
+}
+
+void QQuickButtonGroupPrivate::updateCheckState()
+{
+ if (!complete || settingCheckState)
+ return;
+
+ bool anyChecked = false;
+ bool allChecked = !buttons.isEmpty();
+ for (QQuickAbstractButton *button : qAsConst(buttons)) {
+ const bool isChecked = button->isChecked();
+ anyChecked |= isChecked;
+ allChecked &= isChecked;
+ }
+ setCheckState(Qt::CheckState(anyChecked + allChecked));
+}
+
+void QQuickButtonGroupPrivate::setCheckState(Qt::CheckState state)
+{
+ Q_Q(QQuickButtonGroup);
+ if (checkState == state)
+ return;
+
+ checkState = state;
+ emit q->checkStateChanged();
+}
+
+void QQuickButtonGroupPrivate::buttons_append(QQmlListProperty<QQuickAbstractButton> *prop, QQuickAbstractButton *obj)
+{
+ QQuickButtonGroup *q = static_cast<QQuickButtonGroup *>(prop->object);
+ q->addButton(obj);
+}
+
+qsizetype QQuickButtonGroupPrivate::buttons_count(QQmlListProperty<QQuickAbstractButton> *prop)
+{
+ QQuickButtonGroupPrivate *p = static_cast<QQuickButtonGroupPrivate *>(prop->data);
+ return p->buttons.count();
+}
+
+QQuickAbstractButton *QQuickButtonGroupPrivate::buttons_at(QQmlListProperty<QQuickAbstractButton> *prop, qsizetype index)
+{
+ QQuickButtonGroupPrivate *p = static_cast<QQuickButtonGroupPrivate *>(prop->data);
+ return p->buttons.value(index);
+}
+
+void QQuickButtonGroupPrivate::buttons_clear(QQmlListProperty<QQuickAbstractButton> *prop)
+{
+ QQuickButtonGroupPrivate *p = static_cast<QQuickButtonGroupPrivate *>(prop->data);
+ if (!p->buttons.isEmpty()) {
+ p->clear();
+ QQuickButtonGroup *q = static_cast<QQuickButtonGroup *>(prop->object);
+ // QTBUG-52358: don't clear the checked button immediately
+ QMetaObject::invokeMethod(q, "_q_updateCurrent", Qt::QueuedConnection);
+ emit q->buttonsChanged();
+ }
+}
+
+QQuickButtonGroup::QQuickButtonGroup(QObject *parent)
+ : QObject(*(new QQuickButtonGroupPrivate), parent)
+{
+}
+
+QQuickButtonGroup::~QQuickButtonGroup()
+{
+ Q_D(QQuickButtonGroup);
+ d->clear();
+}
+
+QQuickButtonGroupAttached *QQuickButtonGroup::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickButtonGroupAttached(object);
+}
+
+/*!
+ \qmlproperty AbstractButton QtQuick.Controls::ButtonGroup::checkedButton
+
+ This property holds the currently selected button in an exclusive group,
+ or \c null if there is none or the group is non-exclusive.
+
+ By default, it is the first checked button added to an exclusive button group.
+
+ \sa exclusive
+*/
+QQuickAbstractButton *QQuickButtonGroup::checkedButton() const
+{
+ Q_D(const QQuickButtonGroup);
+ return d->checkedButton;
+}
+
+void QQuickButtonGroup::setCheckedButton(QQuickAbstractButton *checkedButton)
+{
+ Q_D(QQuickButtonGroup);
+ if (d->checkedButton == checkedButton)
+ return;
+
+ if (d->checkedButton)
+ d->checkedButton->setChecked(false);
+ d->checkedButton = checkedButton;
+ if (checkedButton)
+ checkedButton->setChecked(true);
+ emit checkedButtonChanged();
+}
+
+/*!
+ \qmlproperty list<AbstractButton> QtQuick.Controls::ButtonGroup::buttons
+
+ This property holds the list of buttons.
+
+ \code
+ ButtonGroup {
+ buttons: column.children
+ }
+
+ Column {
+ id: column
+
+ RadioButton {
+ checked: true
+ text: qsTr("Option A")
+ }
+
+ RadioButton {
+ text: qsTr("Option B")
+ }
+ }
+ \endcode
+
+ \sa group
+*/
+QQmlListProperty<QQuickAbstractButton> QQuickButtonGroup::buttons()
+{
+ Q_D(QQuickButtonGroup);
+ return QQmlListProperty<QQuickAbstractButton>(this, d,
+ QQuickButtonGroupPrivate::buttons_append,
+ QQuickButtonGroupPrivate::buttons_count,
+ QQuickButtonGroupPrivate::buttons_at,
+ QQuickButtonGroupPrivate::buttons_clear);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::ButtonGroup::exclusive
+
+ This property holds whether the button group is exclusive. The default value is \c true.
+
+ If this property is \c true, then only one button in the group can be checked at any given time.
+ The user can click on any button to check it, and that button will replace the existing one as
+ the checked button in the group.
+
+ In an exclusive group, the user cannot uncheck the currently checked button by clicking on it;
+ instead, another button in the group must be clicked to set the new checked button for that group.
+
+ In a non-exclusive group, checking and unchecking buttons does not affect the other buttons in
+ the group. Furthermore, the value of the \l checkedButton property is \c null.
+*/
+bool QQuickButtonGroup::isExclusive() const
+{
+ Q_D(const QQuickButtonGroup);
+ return d->exclusive;
+}
+
+void QQuickButtonGroup::setExclusive(bool exclusive)
+{
+ Q_D(QQuickButtonGroup);
+ if (d->exclusive == exclusive)
+ return;
+
+ d->exclusive = exclusive;
+ emit exclusiveChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty enumeration QtQuick.Controls::ButtonGroup::checkState
+
+ This property holds the combined check state of the button group.
+
+ Available states:
+ \value Qt.Unchecked None of the buttons are checked.
+ \value Qt.PartiallyChecked Some of the buttons are checked.
+ \value Qt.Checked All of the buttons are checked.
+
+ Setting the check state of a non-exclusive button group to \c Qt.Unchecked
+ or \c Qt.Checked unchecks or checks all buttons in the group, respectively.
+ \c Qt.PartiallyChecked is ignored.
+
+ Setting the check state of an exclusive button group to \c Qt.Unchecked
+ unchecks the \l checkedButton. \c Qt.Checked and \c Qt.PartiallyChecked
+ are ignored.
+*/
+Qt::CheckState QQuickButtonGroup::checkState() const
+{
+ Q_D(const QQuickButtonGroup);
+ return d->checkState;
+}
+
+void QQuickButtonGroup::setCheckState(Qt::CheckState state)
+{
+ Q_D(QQuickButtonGroup);
+ if (d->checkState == state || state == Qt::PartiallyChecked)
+ return;
+
+ d->settingCheckState = true;
+ if (d->exclusive) {
+ if (d->checkedButton && state == Qt::Unchecked)
+ setCheckedButton(nullptr);
+ } else {
+ for (QQuickAbstractButton *button : qAsConst(d->buttons))
+ button->setChecked(state == Qt::Checked);
+ }
+ d->settingCheckState = false;
+ d->setCheckState(state);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ButtonGroup::addButton(AbstractButton button)
+
+ Adds a \a button to the button group.
+
+ \note Manually adding objects to a button group is typically unnecessary.
+ The \l buttons property and the \l group attached property provide a
+ convenient and declarative syntax.
+
+ \sa buttons, group
+*/
+void QQuickButtonGroup::addButton(QQuickAbstractButton *button)
+{
+ Q_D(QQuickButtonGroup);
+ if (!button || d->buttons.contains(button))
+ return;
+
+ QQuickAbstractButtonPrivate::get(button)->group = this;
+ QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
+ QObjectPrivate::connect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
+
+ if (d->exclusive && button->isChecked())
+ setCheckedButton(button);
+
+ d->buttons.append(button);
+ d->updateCheckState();
+ emit buttonsChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ButtonGroup::removeButton(AbstractButton button)
+
+ Removes a \a button from the button group.
+
+ \note Manually removing objects from a button group is typically unnecessary.
+ The \l buttons property and the \l group attached property provide a
+ convenient and declarative syntax.
+
+ \sa buttons, group
+*/
+void QQuickButtonGroup::removeButton(QQuickAbstractButton *button)
+{
+ Q_D(QQuickButtonGroup);
+ if (!button || !d->buttons.contains(button))
+ return;
+
+ QQuickAbstractButtonPrivate::get(button)->group = nullptr;
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
+
+ if (d->checkedButton == button)
+ setCheckedButton(nullptr);
+
+ d->buttons.removeOne(button);
+ d->updateCheckState();
+ emit buttonsChanged();
+}
+
+void QQuickButtonGroup::classBegin()
+{
+ Q_D(QQuickButtonGroup);
+ d->complete = false;
+}
+
+void QQuickButtonGroup::componentComplete()
+{
+ Q_D(QQuickButtonGroup);
+ d->complete = true;
+ if (!d->buttons.isEmpty())
+ d->updateCheckState();
+}
+
+class QQuickButtonGroupAttachedPrivate : public QObjectPrivate
+{
+public:
+ QQuickButtonGroup *group = nullptr;
+};
+
+QQuickButtonGroupAttached::QQuickButtonGroupAttached(QObject *parent)
+ : QObject(*(new QQuickButtonGroupAttachedPrivate), parent)
+{
+}
+
+/*!
+ \qmlattachedproperty ButtonGroup QtQuick.Controls::ButtonGroup::group
+
+ This property attaches a button to a button group.
+
+ \code
+ ButtonGroup { id: group }
+
+ RadioButton {
+ checked: true
+ text: qsTr("Option A")
+ ButtonGroup.group: group
+ }
+
+ RadioButton {
+ text: qsTr("Option B")
+ ButtonGroup.group: group
+ }
+ \endcode
+
+ \sa buttons
+*/
+QQuickButtonGroup *QQuickButtonGroupAttached::group() const
+{
+ Q_D(const QQuickButtonGroupAttached);
+ return d->group;
+}
+
+void QQuickButtonGroupAttached::setGroup(QQuickButtonGroup *group)
+{
+ Q_D(QQuickButtonGroupAttached);
+ if (d->group == group)
+ return;
+
+ if (d->group)
+ d->group->removeButton(qobject_cast<QQuickAbstractButton*>(parent()));
+ d->group = group;
+ if (group)
+ group->addButton(qobject_cast<QQuickAbstractButton*>(parent()));
+ emit groupChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickbuttongroup_p.cpp"
diff --git a/src/quicktemplates2/qquickbuttongroup_p.h b/src/quicktemplates2/qquickbuttongroup_p.h
new file mode 100644
index 0000000000..daff84f2a0
--- /dev/null
+++ b/src/quicktemplates2/qquickbuttongroup_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKBUTTONGROUP_P_H
+#define QQUICKBUTTONGROUP_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 <QtQml/qqml.h>
+#include <QtQml/qqmlparserstatus.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAbstractButton;
+class QQuickButtonGroupPrivate;
+class QQuickButtonGroupAttached;
+class QQuickButtonGroupAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickButtonGroup : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickAbstractButton *checkedButton READ checkedButton WRITE setCheckedButton NOTIFY checkedButtonChanged FINAL)
+ Q_PROPERTY(QQmlListProperty<QQuickAbstractButton> buttons READ buttons NOTIFY buttonsChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool exclusive READ isExclusive WRITE setExclusive NOTIFY exclusiveChanged FINAL REVISION(2, 3))
+ // 2.4 (Qt 5.11)
+ Q_PROPERTY(Qt::CheckState checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL REVISION(2, 4))
+ Q_INTERFACES(QQmlParserStatus)
+ QML_NAMED_ELEMENT(ButtonGroup)
+ QML_ATTACHED(QQuickButtonGroupAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickButtonGroup(QObject *parent = nullptr);
+ ~QQuickButtonGroup();
+
+ static QQuickButtonGroupAttached *qmlAttachedProperties(QObject *object);
+
+ QQuickAbstractButton *checkedButton() const;
+ void setCheckedButton(QQuickAbstractButton *checkedButton);
+
+ QQmlListProperty<QQuickAbstractButton> buttons();
+
+ bool isExclusive() const;
+ void setExclusive(bool exclusive);
+
+ // 2.4 (Qt 5.11)
+ Qt::CheckState checkState() const;
+ void setCheckState(Qt::CheckState state);
+
+public Q_SLOTS:
+ void addButton(QQuickAbstractButton *button);
+ void removeButton(QQuickAbstractButton *button);
+
+Q_SIGNALS:
+ void checkedButtonChanged();
+ void buttonsChanged();
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void clicked(QQuickAbstractButton *button);
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void exclusiveChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void checkStateChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+private:
+ Q_DISABLE_COPY(QQuickButtonGroup)
+ Q_DECLARE_PRIVATE(QQuickButtonGroup)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_updateCurrent())
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickButtonGroupAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickButtonGroup *group READ group WRITE setGroup NOTIFY groupChanged FINAL)
+
+public:
+ explicit QQuickButtonGroupAttached(QObject *parent = nullptr);
+
+ QQuickButtonGroup *group() const;
+ void setGroup(QQuickButtonGroup *group);
+
+Q_SIGNALS:
+ void groupChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickButtonGroupAttached)
+ Q_DECLARE_PRIVATE(QQuickButtonGroupAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickButtonGroup)
+QML_DECLARE_TYPEINFO(QQuickButtonGroup, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKBUTTONGROUP_P_H
diff --git a/src/quicktemplates2/qquickcheckbox.cpp b/src/quicktemplates2/qquickcheckbox.cpp
new file mode 100644
index 0000000000..e3184ceb52
--- /dev/null
+++ b/src/quicktemplates2/qquickcheckbox.cpp
@@ -0,0 +1,245 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcheckbox_p.h"
+#include "qquickabstractbutton_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype CheckBox
+ \inherits AbstractButton
+//! \instantiates QQuickCheckBox
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Check button that can be toggled on or off.
+
+ \image qtquickcontrols2-checkbox.gif
+
+ CheckBox presents an option button that can be toggled on (checked) or
+ off (unchecked). Check boxes are typically used to select one or more
+ options from a set of options. For larger sets of options, such as those
+ in a list, consider using \l CheckDelegate instead.
+
+ CheckBox inherits its API from \l AbstractButton. For instance, the
+ state of the checkbox can be set with the \l {AbstractButton::}{checked} property.
+
+ In addition to the checked and unchecked states, there is a third state:
+ partially checked. The partially checked state can be enabled using the
+ \l tristate property. This state indicates that the regular checked/unchecked
+ state can not be determined; generally because of other states that affect
+ the checkbox. This state is useful when several child nodes are selected
+ in a treeview, for example.
+
+ \code
+ ColumnLayout {
+ CheckBox {
+ checked: true
+ text: qsTr("First")
+ }
+ CheckBox {
+ text: qsTr("Second")
+ }
+ CheckBox {
+ checked: true
+ text: qsTr("Third")
+ }
+ }
+ \endcode
+
+ Hierarchical checkbox groups can be managed with a non-exclusive
+ \l ButtonGroup.
+
+ \image qtquickcontrols2-checkbox-group.png
+
+ The following example illustrates how the combined check state of
+ children can be bound to the check state of the parent checkbox:
+
+ \snippet qtquickcontrols2-checkbox-group.qml 1
+
+ \sa {Customizing CheckBox}, ButtonGroup, {Button Controls}
+*/
+
+class QQuickCheckBoxPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickCheckBox)
+
+public:
+ void setNextCheckState(const QJSValue &callback);
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::CheckBox); }
+
+ bool tristate = false;
+ Qt::CheckState checkState = Qt::Unchecked;
+ QJSValue nextCheckState;
+};
+
+void QQuickCheckBoxPrivate::setNextCheckState(const QJSValue &callback)
+{
+ Q_Q(QQuickCheckBox);
+ nextCheckState = callback;
+ emit q->nextCheckStateChanged();
+}
+
+QQuickCheckBox::QQuickCheckBox(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickCheckBoxPrivate), parent)
+{
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::CheckBox::tristate
+
+ This property holds whether the checkbox is a tri-state checkbox.
+
+ In the animation below, the first checkbox is tri-state:
+
+ \image qtquickcontrols2-checkbox-tristate.gif
+
+ The default is \c false, i.e., the checkbox has only two states.
+*/
+bool QQuickCheckBox::isTristate() const
+{
+ Q_D(const QQuickCheckBox);
+ return d->tristate;
+}
+
+void QQuickCheckBox::setTristate(bool tristate)
+{
+ Q_D(QQuickCheckBox);
+ if (d->tristate == tristate)
+ return;
+
+ d->tristate = tristate;
+ emit tristateChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::CheckBox::checkState
+
+ This property holds the check state of the checkbox.
+
+ Available states:
+ \value Qt.Unchecked The checkbox is unchecked.
+ \value Qt.PartiallyChecked The checkbox is partially checked. This state is only used when \l tristate is enabled.
+ \value Qt.Checked The checkbox is checked.
+
+ \sa tristate, {AbstractButton::checked}{checked}
+*/
+Qt::CheckState QQuickCheckBox::checkState() const
+{
+ Q_D(const QQuickCheckBox);
+ return d->checkState;
+}
+
+void QQuickCheckBox::setCheckState(Qt::CheckState state)
+{
+ Q_D(QQuickCheckBox);
+ if (d->checkState == state)
+ return;
+
+ bool wasChecked = isChecked();
+ d->checked = state == Qt::Checked;
+ d->checkState = state;
+ emit checkStateChanged();
+ if (d->checked != wasChecked)
+ emit checkedChanged();
+}
+
+QFont QQuickCheckBox::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::CheckBox);
+}
+
+void QQuickCheckBox::buttonChange(ButtonChange change)
+{
+ if (change == ButtonCheckedChange)
+ setCheckState(isChecked() ? Qt::Checked : Qt::Unchecked);
+ else
+ QQuickAbstractButton::buttonChange(change);
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty function QtQuick.Controls::CheckBox::nextCheckState
+
+ This property holds a callback function that is called to determine
+ the next check state whenever the checkbox is interactively toggled
+ by the user via touch, mouse, or keyboard.
+
+ By default, a normal checkbox cycles between \c Qt.Unchecked and
+ \c Qt.Checked states, and a tri-state checkbox cycles between
+ \c Qt.Unchecked, \c Qt.PartiallyChecked, and \c Qt.Checked states.
+
+ The \c nextCheckState callback function can override the default behavior.
+ The following example implements a tri-state checkbox that can present
+ a partially checked state depending on external conditions, but never
+ cycles to the partially checked state when interactively toggled by
+ the user.
+
+ \code
+ CheckBox {
+ tristate: true
+ checkState: allChildrenChecked ? Qt.Checked :
+ anyChildChecked ? Qt.PartiallyChecked : Qt.Unchecked
+
+ nextCheckState: function() {
+ if (checkState === Qt.Checked)
+ return Qt.Unchecked
+ else
+ return Qt.Checked
+ }
+ }
+ \endcode
+*/
+void QQuickCheckBox::nextCheckState()
+{
+ Q_D(QQuickCheckBox);
+ if (d->nextCheckState.isCallable())
+ setCheckState(static_cast<Qt::CheckState>(d->nextCheckState.call().toInt()));
+ else if (d->tristate)
+ setCheckState(static_cast<Qt::CheckState>((d->checkState + 1) % 3));
+ else
+ QQuickAbstractButton::nextCheckState();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcheckbox_p.cpp"
diff --git a/src/quicktemplates2/qquickcheckbox_p.h b/src/quicktemplates2/qquickcheckbox_p.h
new file mode 100644
index 0000000000..8e53b41dd7
--- /dev/null
+++ b/src/quicktemplates2/qquickcheckbox_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCHECKBOX_P_H
+#define QQUICKCHECKBOX_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickCheckBoxPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickCheckBox : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool tristate READ isTristate WRITE setTristate NOTIFY tristateChanged FINAL)
+ Q_PROPERTY(Qt::CheckState checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL)
+ // 2.4 (Qt 5.11)
+ Q_PRIVATE_PROPERTY(QQuickCheckBox::d_func(), QJSValue nextCheckState MEMBER nextCheckState WRITE setNextCheckState NOTIFY nextCheckStateChanged FINAL REVISION(2, 4))
+ QML_NAMED_ELEMENT(CheckBox)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickCheckBox(QQuickItem *parent = nullptr);
+
+ bool isTristate() const;
+ void setTristate(bool tristate);
+
+ Qt::CheckState checkState() const;
+ void setCheckState(Qt::CheckState state);
+
+Q_SIGNALS:
+ void tristateChanged();
+ void checkStateChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void nextCheckStateChanged();
+
+protected:
+ QFont defaultFont() const override;
+
+ void buttonChange(ButtonChange change) override;
+ void nextCheckState() override;
+
+private:
+ Q_DISABLE_COPY(QQuickCheckBox)
+ Q_DECLARE_PRIVATE(QQuickCheckBox)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickCheckBox)
+
+#endif // QQUICKCHECKBOX_P_H
diff --git a/src/quicktemplates2/qquickcheckdelegate.cpp b/src/quicktemplates2/qquickcheckdelegate.cpp
new file mode 100644
index 0000000000..7596e104b9
--- /dev/null
+++ b/src/quicktemplates2/qquickcheckdelegate.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcheckdelegate_p.h"
+#include "qquickitemdelegate_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype CheckDelegate
+ \inherits ItemDelegate
+//! \instantiates QQuickCheckDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-delegates
+ \brief Item delegate with a check indicator that can be toggled on or off.
+
+ \image qtquickcontrols2-checkdelegate.gif
+
+ CheckDelegate presents an item delegate that can be toggled on (checked) or
+ off (unchecked). Check delegates are typically used to select one or more
+ options from a set of options in a list. For smaller sets of options, or
+ for options that need to be uniquely identifiable, consider using
+ \l CheckBox instead.
+
+ CheckDelegate inherits its API from \l ItemDelegate, which is inherited
+ from AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton
+ API. The state of the check delegate can be set with the
+ \l {AbstractButton::}{checked} property.
+
+ In addition to the checked and unchecked states, there is a third state:
+ partially checked. The partially checked state can be enabled using the
+ \l tristate property. This state indicates that the regular checked/unchecked
+ state can not be determined; generally because of other states that affect
+ the check delegate. This state is useful when several child nodes are selected
+ in a treeview, for example.
+
+ \code
+ ListView {
+ model: ["Option 1", "Option 2", "Option 3"]
+ delegate: CheckDelegate {
+ text: modelData
+ }
+ }
+ \endcode
+
+ \sa {Customizing CheckDelegate}, {Delegate Controls}, CheckBox
+*/
+
+class QQuickCheckDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickCheckDelegate)
+
+public:
+ void setNextCheckState(const QJSValue &callback);
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ListView); }
+
+ bool tristate = false;
+ Qt::CheckState checkState = Qt::Unchecked;
+ QJSValue nextCheckState;
+};
+
+void QQuickCheckDelegatePrivate::setNextCheckState(const QJSValue &callback)
+{
+ Q_Q(QQuickCheckDelegate);
+ nextCheckState = callback;
+ emit q->nextCheckStateChanged();
+}
+
+QQuickCheckDelegate::QQuickCheckDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickCheckDelegatePrivate), parent)
+{
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::CheckDelegate::tristate
+
+ This property determines whether the check delegate has three states.
+
+ In the animation below, the first checkdelegate is tri-state:
+
+ \image qtquickcontrols2-checkdelegate-tristate.gif
+
+ The default is \c false, i.e., the delegate has only two states.
+*/
+bool QQuickCheckDelegate::isTristate() const
+{
+ Q_D(const QQuickCheckDelegate);
+ return d->tristate;
+}
+
+void QQuickCheckDelegate::setTristate(bool tristate)
+{
+ Q_D(QQuickCheckDelegate);
+ if (d->tristate == tristate)
+ return;
+
+ d->tristate = tristate;
+ emit tristateChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::CheckDelegate::checkState
+
+ This property determines the check state of the check delegate.
+
+ Available states:
+ \value Qt.Unchecked The delegate is unchecked.
+ \value Qt.PartiallyChecked The delegate is partially checked. This state is only used when \l tristate is enabled.
+ \value Qt.Checked The delegate is checked.
+
+ \sa tristate, {AbstractButton::checked}{checked}
+*/
+Qt::CheckState QQuickCheckDelegate::checkState() const
+{
+ Q_D(const QQuickCheckDelegate);
+ return d->checkState;
+}
+
+void QQuickCheckDelegate::setCheckState(Qt::CheckState state)
+{
+ Q_D(QQuickCheckDelegate);
+ if (d->checkState == state)
+ return;
+
+ bool wasChecked = isChecked();
+ d->checked = state == Qt::Checked;
+ d->checkState = state;
+ emit checkStateChanged();
+ if (d->checked != wasChecked)
+ emit checkedChanged();
+}
+
+QFont QQuickCheckDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ListView);
+}
+
+void QQuickCheckDelegate::buttonChange(ButtonChange change)
+{
+ if (change == ButtonCheckedChange)
+ setCheckState(isChecked() ? Qt::Checked : Qt::Unchecked);
+ else
+ QQuickAbstractButton::buttonChange(change);
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty function QtQuick.Controls::CheckDelegate::nextCheckState
+
+ This property holds a callback function that is called to determine
+ the next check state whenever the check delegate is interactively toggled
+ by the user via touch, mouse, or keyboard.
+
+ By default, a normal check delegate cycles between \c Qt.Unchecked and
+ \c Qt.Checked states, and a tri-state check delegate cycles between
+ \c Qt.Unchecked, \c Qt.PartiallyChecked, and \c Qt.Checked states.
+
+ The \c nextCheckState callback function can override the default behavior.
+ The following example implements a tri-state check delegate that can present
+ a partially checked state depending on external conditions, but never
+ cycles to the partially checked state when interactively toggled by
+ the user.
+
+ \code
+ CheckDelegate {
+ tristate: true
+ checkState: allChildrenChecked ? Qt.Checked :
+ anyChildChecked ? Qt.PartiallyChecked : Qt.Unchecked
+
+ nextCheckState: function() {
+ if (checkState === Qt.Checked)
+ return Qt.Unchecked
+ else
+ return Qt.Checked
+ }
+ }
+ \endcode
+*/
+void QQuickCheckDelegate::nextCheckState()
+{
+ Q_D(QQuickCheckDelegate);
+ if (d->nextCheckState.isCallable())
+ setCheckState(static_cast<Qt::CheckState>(d->nextCheckState.call().toInt()));
+ else if (d->tristate)
+ setCheckState(static_cast<Qt::CheckState>((d->checkState + 1) % 3));
+ else
+ QQuickItemDelegate::nextCheckState();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickCheckDelegate::accessibleRole() const
+{
+ return QAccessible::CheckBox;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcheckdelegate_p.cpp"
diff --git a/src/quicktemplates2/qquickcheckdelegate_p.h b/src/quicktemplates2/qquickcheckdelegate_p.h
new file mode 100644
index 0000000000..9b69943fd6
--- /dev/null
+++ b/src/quicktemplates2/qquickcheckdelegate_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCHECKDELEGATE_P_H
+#define QQUICKCHECKDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickCheckDelegatePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickCheckDelegate : public QQuickItemDelegate
+{
+ Q_OBJECT
+ Q_PROPERTY(bool tristate READ isTristate WRITE setTristate NOTIFY tristateChanged FINAL)
+ Q_PROPERTY(Qt::CheckState checkState READ checkState WRITE setCheckState NOTIFY checkStateChanged FINAL)
+ // 2.4 (Qt 5.11)
+ Q_PRIVATE_PROPERTY(QQuickCheckDelegate::d_func(), QJSValue nextCheckState MEMBER nextCheckState WRITE setNextCheckState NOTIFY nextCheckStateChanged FINAL REVISION(2, 4))
+ QML_NAMED_ELEMENT(CheckDelegate)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickCheckDelegate(QQuickItem *parent = nullptr);
+
+ bool isTristate() const;
+ void setTristate(bool tristate);
+
+ Qt::CheckState checkState() const;
+ void setCheckState(Qt::CheckState state);
+
+Q_SIGNALS:
+ void tristateChanged();
+ void checkStateChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void nextCheckStateChanged();
+
+protected:
+ QFont defaultFont() const override;
+
+ void buttonChange(ButtonChange change) override;
+ void nextCheckState() override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickCheckDelegate)
+ Q_DECLARE_PRIVATE(QQuickCheckDelegate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickCheckDelegate)
+
+#endif // QQUICKCHECKDELEGATE_P_H
diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp
new file mode 100644
index 0000000000..5e2f2383fb
--- /dev/null
+++ b/src/quicktemplates2/qquickcombobox.cpp
@@ -0,0 +1,2221 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcombobox_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickabstractbutton_p.h"
+#include "qquickabstractbutton_p_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtCore/qregularexpression.h>
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qglobal.h>
+#include <QtGui/qinputmethod.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/private/qlazilyallocated_p.h>
+#include <private/qqmldelegatemodel_p.h>
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquicktextinput_p_p.h>
+#include <QtQuick/private/qquickitemview_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcCalculateWidestTextWidth, "qt.quick.controls.combobox.calculatewidesttextwidth")
+
+/*!
+ \qmltype ComboBox
+ \inherits Control
+//! \instantiates QQuickComboBox
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Combined button and popup list for selecting options.
+
+ \image qtquickcontrols2-combobox.gif
+
+ ComboBox is a combined button and popup list. It provides a means of
+ presenting a list of options to the user in a way that takes up the
+ minimum amount of screen space.
+
+ ComboBox is populated with a data model. The data model is commonly
+ a JavaScript array, a \l ListModel or an integer, but other types
+ of \l {qml-data-models}{data models} are also supported.
+
+ \code
+ ComboBox {
+ model: ["First", "Second", "Third"]
+ }
+ \endcode
+
+ \section1 Editable ComboBox
+
+ ComboBox can be made \l editable. An editable combo box auto-completes
+ its text based on what is available in the model.
+
+ The following example demonstrates appending content to an editable
+ combo box by reacting to the \l accepted signal.
+
+ \snippet qtquickcontrols2-combobox-accepted.qml combobox
+
+ \section1 ComboBox's Popup
+
+ By default, clicking outside of ComboBox's popup will close it, and the
+ event is propagated to items lower in the stacking order. To prevent the
+ popup from closing, set its \l {Popup::}{closePolicy}:
+
+ \snippet qtquickcontrols2-combobox-popup.qml closePolicy
+
+ To prevent event propagation, set its \l {Popup::}{modal} property to
+ \c true:
+
+ \snippet qtquickcontrols2-combobox-popup.qml modal
+
+ \section1 ComboBox Model Roles
+
+ ComboBox is able to visualize standard \l {qml-data-models}{data models}
+ that provide the \c modelData role:
+ \list
+ \li models that have only one role
+ \li models that do not have named roles (JavaScript array, integer)
+ \endlist
+
+ When using models that have multiple named roles, ComboBox must be configured
+ to use a specific \l {textRole}{text role} for its \l {displayText}{display text}
+ and \l delegate instances. If you want to use a role of the model item
+ that corresponds to the text role, set \l valueRole. The \l currentValue
+ property and \l indexOfValue() method can then be used to get information
+ about those values.
+
+ For example:
+
+ \snippet qtquickcontrols2-combobox-valuerole.qml file
+
+ \note If ComboBox is assigned a data model that has multiple named roles, but
+ \l textRole is not defined, ComboBox is unable to visualize it and throws a
+ \c {ReferenceError: modelData is not defined}.
+
+ \sa {Customizing ComboBox}, {Input Controls}, {Focus Management in Qt Quick Controls}
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::ComboBox::activated(int index)
+
+ This signal is emitted when the item at \a index is activated by the user.
+
+ An item is activated when it is selected while the popup is open,
+ causing the popup to close (and \l currentIndex to change),
+ or while the popup is closed and the combo box is navigated via
+ keyboard, causing the \l currentIndex to change.
+ The \l currentIndex property is set to \a index.
+
+ \sa currentIndex
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::ComboBox::highlighted(int index)
+
+ This signal is emitted when the item at \a index in the popup list is highlighted by the user.
+
+ The highlighted signal is only emitted when the popup is open and an item
+ is highlighted, but not necessarily \l activated.
+
+ \sa highlightedIndex
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal void QtQuick.Controls::ComboBox::accepted()
+
+ This signal is emitted when the \uicontrol Return or \uicontrol Enter key is pressed
+ on an \l editable combo box.
+
+ You can handle this signal in order to add the newly entered
+ item to the model, for example:
+
+ \snippet qtquickcontrols2-combobox-accepted.qml combobox
+
+ Before the signal is emitted, a check is done to see if the string
+ exists in the model. If it does, \l currentIndex will be set to its index,
+ and \l currentText to the string itself.
+
+ After the signal has been emitted, and if the first check failed (that is,
+ the item did not exist), another check will be done to see if the item was
+ added by the signal handler. If it was, the \l currentIndex and
+ \l currentText are updated accordingly. Otherwise, they will be set to
+ \c -1 and \c "", respectively.
+
+ \note If there is a \l validator set on the combo box, the signal will only be
+ emitted if the input is in an acceptable state.
+*/
+
+namespace {
+ enum Activation { NoActivate, Activate };
+ enum Highlighting { NoHighlight, Highlight };
+}
+
+class QQuickComboBoxDelegateModel : public QQmlDelegateModel
+{
+public:
+ explicit QQuickComboBoxDelegateModel(QQuickComboBox *combo);
+ QVariant variantValue(int index, const QString &role) override;
+
+private:
+ QQuickComboBox *combo = nullptr;
+};
+
+QQuickComboBoxDelegateModel::QQuickComboBoxDelegateModel(QQuickComboBox *combo)
+ : QQmlDelegateModel(qmlContext(combo), combo),
+ combo(combo)
+{
+}
+
+QVariant QQuickComboBoxDelegateModel::variantValue(int index, const QString &role)
+{
+ const QVariant model = combo->model();
+ if (model.userType() == QMetaType::QVariantList) {
+ QVariant object = model.toList().value(index);
+ if (object.userType() == QMetaType::QVariantMap) {
+ const QVariantMap data = object.toMap();
+ if (data.count() == 1 && role == QLatin1String("modelData"))
+ return data.first();
+ return data.value(role);
+ } else if (object.userType() == QMetaType::QObjectStar) {
+ const QObject *data = object.value<QObject *>();
+ if (data && role != QLatin1String("modelData"))
+ return data->property(role.toUtf8());
+ }
+ }
+ return QQmlDelegateModel::variantValue(index, role);
+}
+
+class QQuickComboBoxPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickComboBox)
+
+public:
+ bool isPopupVisible() const;
+ void showPopup();
+ void hidePopup(bool accept);
+ void togglePopup(bool accept);
+ void popupVisibleChanged();
+
+ void itemClicked();
+ void itemHovered();
+
+ void createdItem(int index, QObject *object);
+ void modelUpdated();
+ void countChanged();
+
+ QString effectiveTextRole() const;
+ void updateEditText();
+ void updateCurrentText();
+ void updateCurrentValue();
+ void updateCurrentTextAndValue();
+ void updateAcceptableInput();
+
+ bool isValidIndex(int index) const;
+
+ void acceptInput();
+ QString tryComplete(const QString &inputText);
+
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+ void setCurrentIndex(int index, Activation activate);
+ void updateHighlightedIndex();
+ void setHighlightedIndex(int index, Highlighting highlight);
+
+ void keySearch(const QString &text);
+ int match(int start, const QString &text, Qt::MatchFlags flags) const;
+
+ void createDelegateModel();
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void cancelIndicator();
+ void executeIndicator(bool complete = false);
+
+ void cancelPopup();
+ void executePopup(bool complete = false);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void setInputMethodHints(Qt::InputMethodHints hints, bool force = false);
+
+ virtual qreal getContentWidth() const override;
+ qreal calculateWidestTextWidth() const;
+ void maybeUpdateImplicitContentWidth();
+
+ static void hideOldPopup(QQuickPopup *popup);
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ComboBox); }
+
+ bool flat = false;
+ bool down = false;
+ bool hasDown = false;
+ bool pressed = false;
+ bool ownModel = false;
+ bool keyNavigating = false;
+ bool hasDisplayText = false;
+ bool hasCurrentIndex = false;
+ bool hasCalculatedWidestText = false;
+ int highlightedIndex = -1;
+ int currentIndex = -1;
+ QQuickComboBox::ImplicitContentWidthPolicy implicitContentWidthPolicy = QQuickComboBox::ContentItemImplicitWidth;
+ QVariant model;
+ QString textRole;
+ QString currentText;
+ QString displayText;
+ QString valueRole;
+ QVariant currentValue;
+ QQuickItem *pressedItem = nullptr;
+ QQmlInstanceModel *delegateModel = nullptr;
+ QQmlComponent *delegate = nullptr;
+ QQuickDeferredPointer<QQuickItem> indicator;
+ QQuickDeferredPointer<QQuickPopup> popup;
+ bool m_acceptableInput = true;
+
+ struct ExtraData {
+ bool editable = false;
+ bool accepting = false;
+ bool allowComplete = false;
+ bool selectTextByMouse = false;
+ Qt::InputMethodHints inputMethodHints = Qt::ImhNone;
+ QString editText;
+ QValidator *validator = nullptr;
+ };
+ QLazilyAllocated<ExtraData> extra;
+};
+
+bool QQuickComboBoxPrivate::isPopupVisible() const
+{
+ return popup && popup->isVisible();
+}
+
+void QQuickComboBoxPrivate::showPopup()
+{
+ if (!popup)
+ executePopup(true);
+
+ if (popup && !popup->isVisible())
+ popup->open();
+}
+
+void QQuickComboBoxPrivate::hidePopup(bool accept)
+{
+ Q_Q(QQuickComboBox);
+ if (accept) {
+ q->setCurrentIndex(highlightedIndex);
+ emit q->activated(currentIndex);
+ }
+ if (popup && popup->isVisible())
+ popup->close();
+}
+
+void QQuickComboBoxPrivate::togglePopup(bool accept)
+{
+ if (!popup || !popup->isVisible())
+ showPopup();
+ else
+ hidePopup(accept);
+}
+
+void QQuickComboBoxPrivate::popupVisibleChanged()
+{
+ Q_Q(QQuickComboBox);
+ if (isPopupVisible())
+ QGuiApplication::inputMethod()->reset();
+
+ QQuickItemView *itemView = popup->findChild<QQuickItemView *>();
+ if (itemView)
+ itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
+
+ updateHighlightedIndex();
+
+ if (itemView)
+ itemView->positionViewAtIndex(highlightedIndex, QQuickItemView::Beginning);
+
+ if (!hasDown) {
+ q->setDown(pressed || isPopupVisible());
+ hasDown = false;
+ }
+}
+
+void QQuickComboBoxPrivate::itemClicked()
+{
+ Q_Q(QQuickComboBox);
+ int index = delegateModel->indexOf(q->sender(), nullptr);
+ if (index != -1) {
+ setHighlightedIndex(index, Highlight);
+ hidePopup(true);
+ }
+}
+
+void QQuickComboBoxPrivate::itemHovered()
+{
+ Q_Q(QQuickComboBox);
+ if (keyNavigating)
+ return;
+
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
+ if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
+ return;
+
+ int index = delegateModel->indexOf(button, nullptr);
+ if (index != -1) {
+ setHighlightedIndex(index, Highlight);
+
+ if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
+ itemView->positionViewAtIndex(index, QQuickItemView::Contain);
+ }
+}
+
+void QQuickComboBoxPrivate::createdItem(int index, QObject *object)
+{
+ Q_Q(QQuickComboBox);
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (item && !item->parentItem()) {
+ if (popup)
+ item->setParentItem(popup->contentItem());
+ else
+ item->setParentItem(q);
+ QQuickItemPrivate::get(item)->setCulled(true);
+ }
+
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(object);
+ if (button) {
+ button->setFocusPolicy(Qt::NoFocus);
+ connect(button, &QQuickAbstractButton::clicked, this, &QQuickComboBoxPrivate::itemClicked);
+ connect(button, &QQuickAbstractButton::hoveredChanged, this, &QQuickComboBoxPrivate::itemHovered);
+ }
+
+ if (index == currentIndex && !q->isEditable())
+ updateCurrentTextAndValue();
+}
+
+void QQuickComboBoxPrivate::modelUpdated()
+{
+ if (componentComplete && (!extra.isAllocated() || !extra->accepting)) {
+ updateCurrentTextAndValue();
+
+ if (implicitContentWidthPolicy == QQuickComboBox::WidestText)
+ updateImplicitContentSize();
+ }
+}
+
+void QQuickComboBoxPrivate::countChanged()
+{
+ Q_Q(QQuickComboBox);
+ if (q->count() == 0)
+ q->setCurrentIndex(-1);
+ emit q->countChanged();
+}
+
+QString QQuickComboBoxPrivate::effectiveTextRole() const
+{
+ return textRole.isEmpty() ? QStringLiteral("modelData") : textRole;
+}
+
+void QQuickComboBoxPrivate::updateEditText()
+{
+ Q_Q(QQuickComboBox);
+ QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
+ if (!input)
+ return;
+
+ const QString text = input->text();
+
+ if (extra.isAllocated() && extra->allowComplete && !text.isEmpty()) {
+ const QString completed = tryComplete(text);
+ if (completed.length() > text.length()) {
+ input->setText(completed);
+ // This will select the text backwards.
+ input->select(completed.length(), text.length());
+ return;
+ }
+ }
+ q->setEditText(text);
+}
+
+void QQuickComboBoxPrivate::updateCurrentText()
+{
+ Q_Q(QQuickComboBox);
+ const QString text = q->textAt(currentIndex);
+ if (currentText != text) {
+ currentText = text;
+ if (!hasDisplayText)
+ q->maybeSetAccessibleName(text);
+ emit q->currentTextChanged();
+ }
+ if (!hasDisplayText && displayText != text) {
+ displayText = text;
+ emit q->displayTextChanged();
+ }
+ if (!extra.isAllocated() || !extra->accepting)
+ q->setEditText(currentText);
+}
+
+void QQuickComboBoxPrivate::updateCurrentValue()
+{
+ Q_Q(QQuickComboBox);
+ const QVariant value = q->valueAt(currentIndex);
+ if (currentValue == value)
+ return;
+
+ currentValue = value;
+ emit q->currentValueChanged();
+}
+
+void QQuickComboBoxPrivate::updateCurrentTextAndValue()
+{
+ updateCurrentText();
+ updateCurrentValue();
+}
+
+void QQuickComboBoxPrivate::updateAcceptableInput()
+{
+ Q_Q(QQuickComboBox);
+
+ if (!contentItem)
+ return;
+
+ const QQuickTextInput *textInputContentItem = qobject_cast<QQuickTextInput *>(contentItem);
+
+ if (!textInputContentItem)
+ return;
+
+ const bool newValue = textInputContentItem->hasAcceptableInput();
+
+ if (m_acceptableInput != newValue) {
+ m_acceptableInput = newValue;
+ emit q->acceptableInputChanged();
+ }
+}
+
+bool QQuickComboBoxPrivate::isValidIndex(int index) const
+{
+ return delegateModel && index >= 0 && index < delegateModel->count();
+}
+
+void QQuickComboBoxPrivate::acceptInput()
+{
+ Q_Q(QQuickComboBox);
+ int idx = q->find(extra.value().editText, Qt::MatchFixedString);
+ if (idx > -1) {
+ // The item that was accepted already exists, so make it the current item.
+ q->setCurrentIndex(idx);
+ // After accepting text that matches an existing entry, the selection should be cleared.
+ QQuickTextInput *input = qobject_cast<QQuickTextInput *>(contentItem);
+ if (input) {
+ const auto text = input->text();
+ input->select(text.size(), text.size());
+ }
+ }
+
+ extra.value().accepting = true;
+ emit q->accepted();
+
+ // The user might have added the item since it didn't exist, so check again
+ // to see if we can select that new item.
+ if (idx == -1)
+ q->setCurrentIndex(q->find(extra.value().editText, Qt::MatchFixedString));
+ extra.value().accepting = false;
+}
+
+QString QQuickComboBoxPrivate::tryComplete(const QString &input)
+{
+ Q_Q(QQuickComboBox);
+ QString match;
+
+ const int itemCount = q->count();
+ for (int idx = 0; idx < itemCount; ++idx) {
+ const QString text = q->textAt(idx);
+ if (!text.startsWith(input, Qt::CaseInsensitive))
+ continue;
+
+ // either the first or the shortest match
+ if (match.isEmpty() || text.length() < match.length())
+ match = text;
+ }
+
+ if (match.isEmpty())
+ return input;
+
+ return input + match.mid(input.length());
+}
+
+void QQuickComboBoxPrivate::setCurrentIndex(int index, Activation activate)
+{
+ Q_Q(QQuickComboBox);
+ if (currentIndex == index)
+ return;
+
+ currentIndex = index;
+ emit q->currentIndexChanged();
+
+ if (componentComplete)
+ updateCurrentTextAndValue();
+
+ if (activate)
+ emit q->activated(index);
+}
+
+void QQuickComboBoxPrivate::incrementCurrentIndex()
+{
+ Q_Q(QQuickComboBox);
+ if (extra.isAllocated())
+ extra->allowComplete = false;
+ if (isPopupVisible()) {
+ if (highlightedIndex < q->count() - 1)
+ setHighlightedIndex(highlightedIndex + 1, Highlight);
+ } else {
+ if (currentIndex < q->count() - 1)
+ setCurrentIndex(currentIndex + 1, Activate);
+ }
+ if (extra.isAllocated())
+ extra->allowComplete = true;
+}
+
+void QQuickComboBoxPrivate::decrementCurrentIndex()
+{
+ if (extra.isAllocated())
+ extra->allowComplete = false;
+ if (isPopupVisible()) {
+ if (highlightedIndex > 0)
+ setHighlightedIndex(highlightedIndex - 1, Highlight);
+ } else {
+ if (currentIndex > 0)
+ setCurrentIndex(currentIndex - 1, Activate);
+ }
+ if (extra.isAllocated())
+ extra->allowComplete = true;
+}
+
+void QQuickComboBoxPrivate::updateHighlightedIndex()
+{
+ setHighlightedIndex(popup->isVisible() ? currentIndex : -1, NoHighlight);
+}
+
+void QQuickComboBoxPrivate::setHighlightedIndex(int index, Highlighting highlight)
+{
+ Q_Q(QQuickComboBox);
+ if (highlightedIndex == index)
+ return;
+
+ highlightedIndex = index;
+ emit q->highlightedIndexChanged();
+
+ if (highlight)
+ emit q->highlighted(index);
+}
+
+void QQuickComboBoxPrivate::keySearch(const QString &text)
+{
+ const int startIndex = isPopupVisible() ? highlightedIndex : currentIndex;
+ const int index = match(startIndex + 1, text, Qt::MatchStartsWith | Qt::MatchWrap);
+ if (index != -1) {
+ if (isPopupVisible())
+ setHighlightedIndex(index, Highlight);
+ else
+ setCurrentIndex(index, Activate);
+ }
+}
+
+int QQuickComboBoxPrivate::match(int start, const QString &text, Qt::MatchFlags flags) const
+{
+ Q_Q(const QQuickComboBox);
+ uint matchType = flags & 0x0F;
+ bool wrap = flags & Qt::MatchWrap;
+ Qt::CaseSensitivity cs = flags & Qt::MatchCaseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ QRegularExpression::PatternOptions options = flags & Qt::MatchCaseSensitive ? QRegularExpression::NoPatternOption
+ : QRegularExpression::CaseInsensitiveOption;
+ int from = start;
+ int to = q->count();
+
+ // iterates twice if wrapping
+ for (int i = 0; (wrap && i < 2) || (!wrap && i < 1); ++i) {
+ for (int idx = from; idx < to; ++idx) {
+ QString t = q->textAt(idx);
+ switch (matchType) {
+ case Qt::MatchExactly:
+ if (t == text)
+ return idx;
+ break;
+ case Qt::MatchRegularExpression: {
+ QRegularExpression rx(QRegularExpression::anchoredPattern(text), options);
+ if (rx.match(t).hasMatch())
+ return idx;
+ break;
+ }
+ case Qt::MatchWildcard: {
+ QRegularExpression rx(QRegularExpression::wildcardToRegularExpression(text),
+ options);
+ if (rx.match(t).hasMatch())
+ return idx;
+ break;
+ }
+ case Qt::MatchStartsWith:
+ if (t.startsWith(text, cs))
+ return idx;
+ break;
+ case Qt::MatchEndsWith:
+ if (t.endsWith(text, cs))
+ return idx;
+ break;
+ case Qt::MatchFixedString:
+ if (t.compare(text, cs) == 0)
+ return idx;
+ break;
+ case Qt::MatchContains:
+ default:
+ if (t.contains(text, cs))
+ return idx;
+ break;
+ }
+ }
+ // prepare for the next iteration
+ from = 0;
+ to = start;
+ }
+ return -1;
+}
+
+void QQuickComboBoxPrivate::createDelegateModel()
+{
+ Q_Q(QQuickComboBox);
+ bool ownedOldModel = ownModel;
+ QQmlInstanceModel* oldModel = delegateModel;
+ if (oldModel) {
+ disconnect(delegateModel, &QQmlInstanceModel::countChanged, this, &QQuickComboBoxPrivate::countChanged);
+ disconnect(delegateModel, &QQmlInstanceModel::modelUpdated, this, &QQuickComboBoxPrivate::modelUpdated);
+ disconnect(delegateModel, &QQmlInstanceModel::createdItem, this, &QQuickComboBoxPrivate::createdItem);
+ }
+
+ ownModel = false;
+ delegateModel = model.value<QQmlInstanceModel *>();
+
+ if (!delegateModel && model.isValid()) {
+ QQmlDelegateModel *dataModel = new QQuickComboBoxDelegateModel(q);
+ dataModel->setModel(model);
+ dataModel->setDelegate(delegate);
+ if (q->isComponentComplete())
+ dataModel->componentComplete();
+
+ ownModel = true;
+ delegateModel = dataModel;
+ }
+
+ if (delegateModel) {
+ connect(delegateModel, &QQmlInstanceModel::countChanged, this, &QQuickComboBoxPrivate::countChanged);
+ connect(delegateModel, &QQmlInstanceModel::modelUpdated, this, &QQuickComboBoxPrivate::modelUpdated);
+ connect(delegateModel, &QQmlInstanceModel::createdItem, this, &QQuickComboBoxPrivate::createdItem);
+ }
+
+ emit q->delegateModelChanged();
+
+ if (ownedOldModel)
+ delete oldModel;
+}
+
+void QQuickComboBoxPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::handlePress(point);
+ q->setPressed(true);
+}
+
+void QQuickComboBoxPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::handleMove(point);
+ q->setPressed(q->contains(point));
+}
+
+void QQuickComboBoxPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::handleRelease(point);
+ if (pressed) {
+ q->setPressed(false);
+ togglePopup(false);
+ }
+}
+
+void QQuickComboBoxPrivate::handleUngrab()
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::handleUngrab();
+ q->setPressed(false);
+}
+
+static inline QString indicatorName() { return QStringLiteral("indicator"); }
+
+void QQuickComboBoxPrivate::cancelIndicator()
+{
+ Q_Q(QQuickComboBox);
+ quickCancelDeferred(q, indicatorName());
+}
+
+void QQuickComboBoxPrivate::executeIndicator(bool complete)
+{
+ Q_Q(QQuickComboBox);
+ if (indicator.wasExecuted())
+ return;
+
+ if (!indicator || complete)
+ quickBeginDeferred(q, indicatorName(), indicator);
+ if (complete)
+ quickCompleteDeferred(q, indicatorName(), indicator);
+}
+
+static inline QString popupName() { return QStringLiteral("popup"); }
+
+void QQuickComboBoxPrivate::cancelPopup()
+{
+ Q_Q(QQuickComboBox);
+ quickCancelDeferred(q, popupName());
+}
+
+void QQuickComboBoxPrivate::executePopup(bool complete)
+{
+ Q_Q(QQuickComboBox);
+ if (popup.wasExecuted())
+ return;
+
+ if (!popup || complete)
+ quickBeginDeferred(q, popupName(), popup);
+ if (complete)
+ quickCompleteDeferred(q, popupName(), popup);
+}
+
+void QQuickComboBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ if (item == indicator)
+ emit q->implicitIndicatorWidthChanged();
+}
+
+void QQuickComboBoxPrivate::setInputMethodHints(Qt::InputMethodHints hints, bool force)
+{
+ Q_Q(QQuickComboBox);
+ if (!force && hints == q->inputMethodHints())
+ return;
+
+ extra.value().inputMethodHints = hints;
+ emit q->inputMethodHintsChanged();
+}
+
+void QQuickComboBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickComboBox);
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ if (item == indicator)
+ emit q->implicitIndicatorHeightChanged();
+}
+
+qreal QQuickComboBoxPrivate::getContentWidth() const
+{
+ if (componentComplete) {
+ switch (implicitContentWidthPolicy) {
+ case QQuickComboBox::WidestText:
+ return calculateWidestTextWidth();
+ case QQuickComboBox::WidestTextWhenCompleted:
+ if (!hasCalculatedWidestText)
+ return calculateWidestTextWidth();
+ break;
+ default:
+ break;
+ }
+ }
+
+ return QQuickControlPrivate::getContentWidth();
+}
+
+qreal QQuickComboBoxPrivate::calculateWidestTextWidth() const
+{
+ Q_Q(const QQuickComboBox);
+ if (!componentComplete)
+ return 0;
+
+ const int count = q->count();
+ if (count == 0)
+ return 0;
+
+ auto textInput = qobject_cast<QQuickTextInput*>(contentItem);
+ if (!textInput)
+ return 0;
+
+ qCDebug(lcCalculateWidestTextWidth) << "calculating widest text from" << count << "items...";
+
+ // Avoid the index check and repeated calls to effectiveTextRole()
+ // that would result from calling textAt() in a loop.
+ const QString textRole = effectiveTextRole();
+ auto textInputPrivate = QQuickTextInputPrivate::get(textInput);
+ qreal widest = 0;
+ for (int i = 0; i < count; ++i) {
+ const QString text = delegateModel->stringValue(i, textRole);
+ const qreal textImplicitWidth = textInputPrivate->calculateImplicitWidthForText(text);
+ widest = qMax(widest, textImplicitWidth);
+ }
+
+ qCDebug(lcCalculateWidestTextWidth) << "... widest text is" << widest;
+ return widest;
+}
+
+/*!
+ \internal
+
+ If the user requested it (and we haven't already done it, depending on the policy),
+ update the implicit content width to the largest text in the model.
+*/
+void QQuickComboBoxPrivate::maybeUpdateImplicitContentWidth()
+{
+ if (!componentComplete)
+ return;
+
+ if (implicitContentWidthPolicy == QQuickComboBox::ContentItemImplicitWidth
+ || (implicitContentWidthPolicy == QQuickComboBox::WidestTextWhenCompleted && hasCalculatedWidestText))
+ return;
+
+ updateImplicitContentWidth();
+ hasCalculatedWidestText = true;
+}
+
+void QQuickComboBoxPrivate::hideOldPopup(QQuickPopup *popup)
+{
+ if (!popup)
+ return;
+
+ qCDebug(lcItemManagement) << "hiding old popup" << popup;
+
+ popup->setVisible(false);
+ popup->setParentItem(nullptr);
+#if QT_CONFIG(accessibility)
+ // Remove the item from the accessibility tree.
+ QQuickAccessibleAttached *accessible = accessibleAttached(popup);
+ if (accessible)
+ accessible->setIgnored(true);
+#endif
+}
+
+QQuickComboBox::QQuickComboBox(QQuickItem *parent)
+ : QQuickControl(*(new QQuickComboBoxPrivate), parent)
+{
+ setFocusPolicy(Qt::StrongFocus);
+ setFlag(QQuickItem::ItemIsFocusScope);
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+ Q_D(QQuickComboBox);
+ d->setInputMethodHints(Qt::ImhNoPredictiveText, true);
+}
+
+QQuickComboBox::~QQuickComboBox()
+{
+ Q_D(QQuickComboBox);
+ d->removeImplicitSizeListener(d->indicator);
+ if (d->popup) {
+ // Disconnect visibleChanged() to avoid a spurious highlightedIndexChanged() signal
+ // emission during the destruction of the (visible) popup. (QTBUG-57650)
+ QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
+ QQuickComboBoxPrivate::hideOldPopup(d->popup);
+ d->popup = nullptr;
+ }
+}
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick.Controls::ComboBox::count
+
+ This property holds the number of items in the combo box.
+*/
+int QQuickComboBox::count() const
+{
+ Q_D(const QQuickComboBox);
+ return d->delegateModel ? d->delegateModel->count() : 0;
+}
+
+/*!
+ \qmlproperty model QtQuick.Controls::ComboBox::model
+
+ This property holds the model providing data for the combo box.
+
+ \code
+ ComboBox {
+ textRole: "key"
+ model: ListModel {
+ ListElement { key: "First"; value: 123 }
+ ListElement { key: "Second"; value: 456 }
+ ListElement { key: "Third"; value: 789 }
+ }
+ }
+ \endcode
+
+ \sa textRole, {qml-data-models}{Data Models}
+*/
+QVariant QQuickComboBox::model() const
+{
+ Q_D(const QQuickComboBox);
+ return d->model;
+}
+
+void QQuickComboBox::setModel(const QVariant& m)
+{
+ Q_D(QQuickComboBox);
+ QVariant model = m;
+ if (model.userType() == qMetaTypeId<QJSValue>())
+ model = model.value<QJSValue>().toVariant();
+
+ if (d->model == model)
+ return;
+
+ if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(d->model)) {
+ QObjectPrivate::disconnect(aim, &QAbstractItemModel::dataChanged,
+ d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentTextAndValue));
+ }
+ if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(model)) {
+ QObjectPrivate::connect(aim, &QAbstractItemModel::dataChanged,
+ d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentTextAndValue));
+ }
+
+ d->model = model;
+ d->createDelegateModel();
+ emit countChanged();
+ if (isComponentComplete()) {
+ setCurrentIndex(count() > 0 ? 0 : -1);
+ d->updateCurrentTextAndValue();
+ }
+ emit modelChanged();
+
+ d->maybeUpdateImplicitContentWidth();
+}
+
+/*!
+ \internal
+ \qmlproperty model QtQuick.Controls::ComboBox::delegateModel
+
+ This property holds the model providing delegate instances for the combo box.
+*/
+QQmlInstanceModel *QQuickComboBox::delegateModel() const
+{
+ Q_D(const QQuickComboBox);
+ return d->delegateModel;
+}
+
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick.Controls::ComboBox::pressed
+
+ This property holds whether the combo box button is physically pressed.
+ A button can be pressed by either touch or key events.
+
+ \sa down
+*/
+bool QQuickComboBox::isPressed() const
+{
+ Q_D(const QQuickComboBox);
+ return d->pressed;
+}
+
+void QQuickComboBox::setPressed(bool pressed)
+{
+ Q_D(QQuickComboBox);
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ emit pressedChanged();
+
+ if (!d->hasDown) {
+ setDown(d->pressed || d->isPopupVisible());
+ d->hasDown = false;
+ }
+}
+
+/*!
+ \readonly
+ \qmlproperty int QtQuick.Controls::ComboBox::highlightedIndex
+
+ This property holds the index of the highlighted item in the combo box popup list.
+
+ When a highlighted item is activated, the popup is closed, \l currentIndex
+ is set to \c highlightedIndex, and the value of this property is reset to
+ \c -1, as there is no longer a highlighted item.
+
+ \sa highlighted(), currentIndex
+*/
+int QQuickComboBox::highlightedIndex() const
+{
+ Q_D(const QQuickComboBox);
+ return d->highlightedIndex;
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::ComboBox::currentIndex
+
+ This property holds the index of the current item in the combo box.
+
+ The default value is \c -1 when \l count is \c 0, and \c 0 otherwise.
+
+ \sa activated(), currentText, highlightedIndex
+*/
+int QQuickComboBox::currentIndex() const
+{
+ Q_D(const QQuickComboBox);
+ return d->currentIndex;
+}
+
+void QQuickComboBox::setCurrentIndex(int index)
+{
+ Q_D(QQuickComboBox);
+ d->hasCurrentIndex = true;
+ d->setCurrentIndex(index, NoActivate);
+}
+
+/*!
+ \readonly
+ \qmlproperty string QtQuick.Controls::ComboBox::currentText
+
+ This property holds the text of the current item in the combo box.
+
+ \sa currentIndex, displayText, textRole, editText
+*/
+QString QQuickComboBox::currentText() const
+{
+ Q_D(const QQuickComboBox);
+ return d->currentText;
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::ComboBox::displayText
+
+ This property holds the text that is displayed on the combo box button.
+
+ By default, the display text presents the current selection. That is,
+ it follows the text of the current item. However, the default display
+ text can be overridden with a custom value.
+
+ \code
+ ComboBox {
+ currentIndex: 1
+ displayText: "Size: " + currentText
+ model: ["S", "M", "L"]
+ }
+ \endcode
+
+ \sa currentText, textRole
+*/
+QString QQuickComboBox::displayText() const
+{
+ Q_D(const QQuickComboBox);
+ return d->displayText;
+}
+
+void QQuickComboBox::setDisplayText(const QString &text)
+{
+ Q_D(QQuickComboBox);
+ d->hasDisplayText = true;
+ if (d->displayText == text)
+ return;
+
+ d->displayText = text;
+ maybeSetAccessibleName(text);
+ emit displayTextChanged();
+}
+
+void QQuickComboBox::resetDisplayText()
+{
+ Q_D(QQuickComboBox);
+ if (!d->hasDisplayText)
+ return;
+
+ d->hasDisplayText = false;
+ d->updateCurrentText();
+}
+
+
+/*!
+ \qmlproperty string QtQuick.Controls::ComboBox::textRole
+
+ This property holds the model role used for populating the combo box.
+
+ When the model has multiple roles, \c textRole can be set to determine
+ which role should be displayed.
+
+ \sa model, currentText, displayText, {ComboBox Model Roles}
+*/
+QString QQuickComboBox::textRole() const
+{
+ Q_D(const QQuickComboBox);
+ return d->textRole;
+}
+
+void QQuickComboBox::setTextRole(const QString &role)
+{
+ Q_D(QQuickComboBox);
+ if (d->textRole == role)
+ return;
+
+ d->textRole = role;
+ if (isComponentComplete())
+ d->updateCurrentText();
+ emit textRoleChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.14 (Qt 5.14)
+ \qmlproperty string QtQuick.Controls::ComboBox::valueRole
+
+ This property holds the model role used for storing the value associated
+ with each item in the model.
+
+ For an example of how to use this property, see \l {ComboBox Model Roles}.
+
+ \sa model, currentValue
+*/
+QString QQuickComboBox::valueRole() const
+{
+ Q_D(const QQuickComboBox);
+ return d->valueRole;
+}
+
+void QQuickComboBox::setValueRole(const QString &role)
+{
+ Q_D(QQuickComboBox);
+ if (d->valueRole == role)
+ return;
+
+ d->valueRole = role;
+ if (isComponentComplete())
+ d->updateCurrentValue();
+ emit valueRoleChanged();
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::ComboBox::delegate
+
+ This property holds a delegate that presents an item in the combo box popup.
+
+ It is recommended to use \l ItemDelegate (or any other \l AbstractButton
+ derivatives) as the delegate. This ensures that the interaction works as
+ expected, and the popup will automatically close when appropriate. When
+ other types are used as the delegate, the popup must be closed manually.
+ For example, if \l MouseArea is used:
+
+ \code
+ delegate: Rectangle {
+ // ...
+ MouseArea {
+ // ...
+ onClicked: comboBox.popup.close()
+ }
+ }
+ \endcode
+
+ \sa ItemDelegate, {Customizing ComboBox}
+*/
+QQmlComponent *QQuickComboBox::delegate() const
+{
+ Q_D(const QQuickComboBox);
+ return d->delegate;
+}
+
+void QQuickComboBox::setDelegate(QQmlComponent* delegate)
+{
+ Q_D(QQuickComboBox);
+ if (d->delegate == delegate)
+ return;
+
+ delete d->delegate;
+ d->delegate = delegate;
+ QQmlDelegateModel *delegateModel = qobject_cast<QQmlDelegateModel*>(d->delegateModel);
+ if (delegateModel)
+ delegateModel->setDelegate(d->delegate);
+ emit delegateChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::ComboBox::indicator
+
+ This property holds the drop indicator item.
+
+ \sa {Customizing ComboBox}
+*/
+QQuickItem *QQuickComboBox::indicator() const
+{
+ QQuickComboBoxPrivate *d = const_cast<QQuickComboBoxPrivate *>(d_func());
+ if (!d->indicator)
+ d->executeIndicator();
+ return d->indicator;
+}
+
+void QQuickComboBox::setIndicator(QQuickItem *indicator)
+{
+ Q_D(QQuickComboBox);
+ if (d->indicator == indicator)
+ return;
+
+ if (!d->indicator.isExecuting())
+ d->cancelIndicator();
+
+ const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
+ const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
+
+ d->removeImplicitSizeListener(d->indicator);
+ QQuickControlPrivate::hideOldItem(d->indicator);
+ d->indicator = indicator;
+ if (indicator) {
+ if (!indicator->parentItem())
+ indicator->setParentItem(this);
+ d->addImplicitSizeListener(indicator);
+ }
+
+ if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
+ emit implicitIndicatorWidthChanged();
+ if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
+ emit implicitIndicatorHeightChanged();
+ if (!d->indicator.isExecuting())
+ emit indicatorChanged();
+}
+
+/*!
+ \qmlproperty Popup QtQuick.Controls::ComboBox::popup
+
+ This property holds the popup.
+
+ The popup can be opened or closed manually, if necessary:
+
+ \code
+ onSpecialEvent: comboBox.popup.close()
+ \endcode
+
+ \sa {Customizing ComboBox}
+*/
+QQuickPopup *QQuickComboBox::popup() const
+{
+ QQuickComboBoxPrivate *d = const_cast<QQuickComboBoxPrivate *>(d_func());
+ if (!d->popup)
+ d->executePopup(isComponentComplete());
+ return d->popup;
+}
+
+void QQuickComboBox::setPopup(QQuickPopup *popup)
+{
+ Q_D(QQuickComboBox);
+ if (d->popup == popup)
+ return;
+
+ if (!d->popup.isExecuting())
+ d->cancelPopup();
+
+ if (d->popup) {
+ QObjectPrivate::disconnect(d->popup.data(), &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
+ QQuickComboBoxPrivate::hideOldPopup(d->popup);
+ }
+ if (popup) {
+ QQuickPopupPrivate::get(popup)->allowVerticalFlip = true;
+ popup->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent);
+ QObjectPrivate::connect(popup, &QQuickPopup::visibleChanged, d, &QQuickComboBoxPrivate::popupVisibleChanged);
+
+ if (QQuickItemView *itemView = popup->findChild<QQuickItemView *>())
+ itemView->setHighlightRangeMode(QQuickItemView::NoHighlightRange);
+ }
+ d->popup = popup;
+ if (!d->popup.isExecuting())
+ emit popupChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::ComboBox::flat
+
+ This property holds whether the combo box button is flat.
+
+ A flat combo box button does not draw a background unless it is interacted
+ with. In comparison to normal combo boxes, flat combo boxes provide looks
+ that make them stand out less from the rest of the UI. For instance, when
+ placing a combo box into a tool bar, it may be desirable to make the combo
+ box flat so it matches better with the flat looks of tool buttons.
+
+ The default value is \c false.
+*/
+bool QQuickComboBox::isFlat() const
+{
+ Q_D(const QQuickComboBox);
+ return d->flat;
+}
+
+void QQuickComboBox::setFlat(bool flat)
+{
+ Q_D(QQuickComboBox);
+ if (d->flat == flat)
+ return;
+
+ d->flat = flat;
+ emit flatChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::ComboBox::down
+
+ This property holds whether the combo box button is visually down.
+
+ Unless explicitly set, this property is \c true when either \c pressed
+ or \c popup.visible is \c true. To return to the default value, set this
+ property to \c undefined.
+
+ \sa pressed, popup
+*/
+bool QQuickComboBox::isDown() const
+{
+ Q_D(const QQuickComboBox);
+ return d->down;
+}
+
+void QQuickComboBox::setDown(bool down)
+{
+ Q_D(QQuickComboBox);
+ d->hasDown = true;
+
+ if (d->down == down)
+ return;
+
+ d->down = down;
+ emit downChanged();
+}
+
+void QQuickComboBox::resetDown()
+{
+ Q_D(QQuickComboBox);
+ if (!d->hasDown)
+ return;
+
+ setDown(d->pressed || d->isPopupVisible());
+ d->hasDown = false;
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::ComboBox::editable
+
+ This property holds whether the combo box is editable.
+
+ The default value is \c false.
+
+ \sa validator
+*/
+bool QQuickComboBox::isEditable() const
+{
+ Q_D(const QQuickComboBox);
+ return d->extra.isAllocated() && d->extra->editable;
+}
+
+void QQuickComboBox::setEditable(bool editable)
+{
+ Q_D(QQuickComboBox);
+ if (editable == isEditable())
+ return;
+
+ if (d->contentItem) {
+ if (editable) {
+ d->contentItem->installEventFilter(this);
+ if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
+ QObjectPrivate::connect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
+ QObjectPrivate::connect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
+ }
+#if QT_CONFIG(cursor)
+ d->contentItem->setCursor(Qt::IBeamCursor);
+#endif
+ } else {
+ d->contentItem->removeEventFilter(this);
+ if (QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem)) {
+ QObjectPrivate::disconnect(input, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
+ QObjectPrivate::disconnect(input, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
+ }
+#if QT_CONFIG(cursor)
+ d->contentItem->unsetCursor();
+#endif
+ }
+ }
+
+ d->extra.value().editable = editable;
+ setAccessibleProperty("editable", editable);
+ emit editableChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty string QtQuick.Controls::ComboBox::editText
+
+ This property holds the text in the text field of an editable combo box.
+
+ \sa editable, currentText, displayText
+*/
+QString QQuickComboBox::editText() const
+{
+ Q_D(const QQuickComboBox);
+ return d->extra.isAllocated() ? d->extra->editText : QString();
+}
+
+void QQuickComboBox::setEditText(const QString &text)
+{
+ Q_D(QQuickComboBox);
+ if (text == editText())
+ return;
+
+ d->extra.value().editText = text;
+ emit editTextChanged();
+}
+
+void QQuickComboBox::resetEditText()
+{
+ setEditText(QString());
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty Validator QtQuick.Controls::ComboBox::validator
+
+ This property holds an input text validator for an editable combo box.
+
+ When a validator is set, the text field will only accept input which
+ leaves the text property in an intermediate state. The \l accepted signal
+ will only be emitted if the text is in an acceptable state when the
+ \uicontrol Return or \uicontrol Enter key is pressed.
+
+ The currently supported validators are \l[QtQuick]{IntValidator},
+ \l[QtQuick]{DoubleValidator}, and \l[QtQuick]{RegularExpressionValidator}. An
+ example of using validators is shown below, which allows input of
+ integers between \c 0 and \c 10 into the text field:
+
+ \code
+ ComboBox {
+ model: 10
+ editable: true
+ validator: IntValidator {
+ top: 9
+ bottom: 0
+ }
+ }
+ \endcode
+
+ \sa acceptableInput, accepted, editable
+*/
+QValidator *QQuickComboBox::validator() const
+{
+ Q_D(const QQuickComboBox);
+ return d->extra.isAllocated() ? d->extra->validator : nullptr;
+}
+
+void QQuickComboBox::setValidator(QValidator *validator)
+{
+ Q_D(QQuickComboBox);
+ if (validator == QQuickComboBox::validator())
+ return;
+
+ d->extra.value().validator = validator;
+#if QT_CONFIG(validator)
+ if (validator)
+ validator->setLocale(d->locale);
+#endif
+ emit validatorChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty flags QtQuick.Controls::ComboBox::inputMethodHints
+
+ Provides hints to the input method about the expected content of the combo box and how it
+ should operate.
+
+ The default value is \c Qt.ImhNoPredictiveText.
+
+ \include inputmethodhints.qdocinc
+*/
+Qt::InputMethodHints QQuickComboBox::inputMethodHints() const
+{
+ Q_D(const QQuickComboBox);
+ return d->extra.isAllocated() ? d->extra->inputMethodHints : Qt::ImhNoPredictiveText;
+}
+
+void QQuickComboBox::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QQuickComboBox);
+ d->setInputMethodHints(hints);
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::ComboBox::inputMethodComposing
+ \readonly
+
+ This property holds whether an editable combo box has partial text input from an input method.
+
+ While it is composing, an input method may rely on mouse or key events from the combo box to
+ edit or commit the partial text. This property can be used to determine when to disable event
+ handlers that may interfere with the correct operation of an input method.
+*/
+bool QQuickComboBox::isInputMethodComposing() const
+{
+ Q_D(const QQuickComboBox);
+ return d->contentItem && d->contentItem->property("inputMethodComposing").toBool();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::ComboBox::acceptableInput
+ \readonly
+
+ This property holds whether the combo box contains acceptable text in the editable text field.
+
+ If a validator has been set, the value is \c true only if the current text is acceptable
+ to the validator as a final string (not as an intermediate string).
+
+ \sa validator, accepted
+*/
+bool QQuickComboBox::hasAcceptableInput() const
+{
+ Q_D(const QQuickComboBox);
+ return d->m_acceptableInput;
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::ComboBox::implicitIndicatorWidth
+ \readonly
+
+ This property holds the implicit indicator width.
+
+ The value is equal to \c {indicator ? indicator.implicitWidth : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentWidth} and
+ \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
+
+ \sa implicitIndicatorHeight
+*/
+qreal QQuickComboBox::implicitIndicatorWidth() const
+{
+ Q_D(const QQuickComboBox);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::ComboBox::implicitIndicatorHeight
+ \readonly
+
+ This property holds the implicit indicator height.
+
+ The value is equal to \c {indicator ? indicator.implicitHeight : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentHeight} and
+ \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
+
+ \sa implicitIndicatorWidth
+*/
+qreal QQuickComboBox::implicitIndicatorHeight() const
+{
+ Q_D(const QQuickComboBox);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitHeight();
+}
+
+/*!
+ \readonly
+ \since QtQuick.Controls 2.14 (Qt 5.14)
+ \qmlproperty var QtQuick.Controls::ComboBox::currentValue
+
+ This property holds the value of the current item in the combo box.
+
+ For an example of how to use this property, see \l {ComboBox Model Roles}.
+
+ \sa currentIndex, currentText, valueRole
+*/
+QVariant QQuickComboBox::currentValue() const
+{
+ Q_D(const QQuickComboBox);
+ return d->currentValue;
+}
+
+/*!
+ \readonly
+ \since QtQuick.Controls 2.14 (Qt 5.14)
+ \qmlmethod var QtQuick.Controls::ComboBox::valueAt(int index)
+
+ Returns the value at position \a index in the combo box.
+
+ \sa indexOfValue
+*/
+QVariant QQuickComboBox::valueAt(int index) const
+{
+ Q_D(const QQuickComboBox);
+ if (!d->isValidIndex(index))
+ return QVariant();
+
+ const QString effectiveValueRole = d->valueRole.isEmpty() ? QStringLiteral("modelData") : d->valueRole;
+ return d->delegateModel->variantValue(index, effectiveValueRole);
+}
+
+/*!
+ \since QtQuick.Controls 2.14 (Qt 5.14)
+ \qmlmethod int QtQuick.Controls::ComboBox::indexOfValue(object value)
+
+ Returns the index of the specified \a value, or \c -1 if no match is found.
+
+ For an example of how to use this method, see \l {ComboBox Model Roles}.
+
+ \include qquickcombobox.qdocinc functions-after-component-completion
+
+ \sa find(), currentValue, currentIndex, valueRole, valueAt
+*/
+int QQuickComboBox::indexOfValue(const QVariant &value) const
+{
+ for (int i = 0; i < count(); ++i) {
+ const QVariant ourValue = valueAt(i);
+ if (value == ourValue)
+ return i;
+ }
+ return -1;
+}
+
+/*!
+ \since QtQuick.Controls 2.15 (Qt 5.15)
+ \qmlproperty bool QtQuick.Controls::ComboBox::selectTextByMouse
+
+ This property holds whether the text field for an editable ComboBox
+ can be selected with the mouse.
+
+ The default value is \c false.
+*/
+bool QQuickComboBox::selectTextByMouse() const
+{
+ Q_D(const QQuickComboBox);
+ return d->extra.isAllocated() ? d->extra->selectTextByMouse : false;
+}
+
+void QQuickComboBox::setSelectTextByMouse(bool canSelect)
+{
+ Q_D(QQuickComboBox);
+ if (canSelect == selectTextByMouse())
+ return;
+
+ d->extra.value().selectTextByMouse = canSelect;
+ emit selectTextByMouseChanged();
+}
+
+/*!
+ \since QtQuick.Controls 6.0 (Qt 6.0)
+ \qmlproperty enumeration QtQuick.Controls::ComboBox::implicitContentWidthPolicy
+
+ This property controls how the \l{Control::}{implicitContentWidth} of the ComboBox is
+ calculated.
+
+ When the width of a ComboBox is not large enough to display text, that text
+ is elided. Depending on which parts of the text are elided, this can make
+ selecting an item difficult for the end user. An efficient way of ensuring
+ that a ComboBox is wide enough to avoid text being elided is to set a width
+ that is known to be large enough:
+
+ \code
+ width: 300
+ implicitContentWidthPolicy: ComboBox.ContentItemImplicitWidth
+ \endcode
+
+ However, it is often not possible to know whether or not a hard-coded value
+ will be large enough, as the size of text depends on many factors, such as
+ font family, font size, translations, and so on.
+
+ implicitContentWidthPolicy provides an easy way to control how the
+ implicitContentWidth is calculated, which in turn affects the
+ \l{Item::}{implicitWidth} of the ComboBox and ensures that text will not be elided.
+
+ The available values are:
+
+ \value ContentItemImplicitWidth
+ The implicitContentWidth will default to that of the \l{Control::}{contentItem}.
+ This is the most efficient option, as no extra text layout is done.
+ \value WidestText
+ The implicitContentWidth will be set to the implicit width of the
+ the largest text for the given \l textRole every time the model
+ changes.
+ This option should be used with smaller models, as it can be expensive.
+ \value WidestTextWhenCompleted
+ The implicitContentWidth will be set to the implicit width of the
+ the largest text for the given \l textRole once after
+ \l {QQmlParserStatus::componentComplete()}{component completion}.
+ This option should be used with smaller models, as it can be expensive.
+
+ The default value is \c ContentItemImplicitWidth.
+
+ As this property only affects the \c implicitWidth of the ComboBox, setting
+ an explicit \l{Item::}{width} can still result in eliding.
+
+ \note This feature requires the contentItem to be a type derived from
+ \l TextInput.
+
+ \note This feature requires text to be laid out, and can therefore be
+ expensive for large models or models whose contents are updated
+ frequently.
+*/
+QQuickComboBox::ImplicitContentWidthPolicy QQuickComboBox::implicitContentWidthPolicy() const
+{
+ Q_D(const QQuickComboBox);
+ return d->implicitContentWidthPolicy;
+}
+
+void QQuickComboBox::setImplicitContentWidthPolicy(QQuickComboBox::ImplicitContentWidthPolicy policy)
+{
+ Q_D(QQuickComboBox);
+ if (policy == d->implicitContentWidthPolicy)
+ return;
+
+ d->implicitContentWidthPolicy = policy;
+ d->maybeUpdateImplicitContentWidth();
+ emit implicitContentWidthPolicyChanged();
+}
+/*!
+ \qmlmethod string QtQuick.Controls::ComboBox::textAt(int index)
+
+ Returns the text for the specified \a index, or an empty string
+ if the index is out of bounds.
+
+ \include qquickcombobox.qdocinc functions-after-component-completion
+ For example:
+ \snippet qtquickcontrols2-combobox-textat.qml textat
+
+ \sa textRole
+*/
+QString QQuickComboBox::textAt(int index) const
+{
+ Q_D(const QQuickComboBox);
+ if (!d->isValidIndex(index))
+ return QString();
+
+ return d->delegateModel->stringValue(index, d->effectiveTextRole());
+}
+
+/*!
+ \qmlmethod int QtQuick.Controls::ComboBox::find(string text, enumeration flags)
+
+ Returns the index of the specified \a text, or \c -1 if no match is found.
+
+ The way the search is performed is defined by the specified match \a flags. By default,
+ combo box performs case sensitive exact matching (\c Qt.MatchExactly). All other match
+ types are case-insensitive unless the \c Qt.MatchCaseSensitive flag is also specified.
+
+ \value Qt.MatchExactly The search term matches exactly (default).
+ \value Qt.MatchRegularExpression The search term matches as a regular expression.
+ \value Qt.MatchWildcard The search term matches using wildcards.
+ \value Qt.MatchFixedString The search term matches as a fixed string.
+ \value Qt.MatchStartsWith The search term matches the start of the item.
+ \value Qt.MatchEndsWidth The search term matches the end of the item.
+ \value Qt.MatchContains The search term is contained in the item.
+ \value Qt.MatchCaseSensitive The search is case sensitive.
+
+ \include qquickcombobox.qdocinc functions-after-component-completion
+ For example:
+ \snippet qtquickcontrols2-combobox-find.qml find
+
+ \sa textRole
+*/
+int QQuickComboBox::find(const QString &text, Qt::MatchFlags flags) const
+{
+ Q_D(const QQuickComboBox);
+ return d->match(0, text, flags);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ComboBox::incrementCurrentIndex()
+
+ Increments the current index of the combo box, or the highlighted
+ index if the popup list is visible.
+
+ \sa currentIndex, highlightedIndex
+*/
+void QQuickComboBox::incrementCurrentIndex()
+{
+ Q_D(QQuickComboBox);
+ d->incrementCurrentIndex();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ComboBox::decrementCurrentIndex()
+
+ Decrements the current index of the combo box, or the highlighted
+ index if the popup list is visible.
+
+ \sa currentIndex, highlightedIndex
+*/
+void QQuickComboBox::decrementCurrentIndex()
+{
+ Q_D(QQuickComboBox);
+ d->decrementCurrentIndex();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlmethod void QtQuick.Controls::ComboBox::selectAll()
+
+ Selects all the text in the editable text field of the combo box.
+
+ \sa editText
+*/
+void QQuickComboBox::selectAll()
+{
+ Q_D(QQuickComboBox);
+ QQuickTextInput *input = qobject_cast<QQuickTextInput *>(d->contentItem);
+ if (!input)
+ return;
+ input->selectAll();
+}
+
+bool QQuickComboBox::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QQuickComboBox);
+ switch (event->type()) {
+ case QEvent::MouseButtonRelease:
+ if (d->isPopupVisible())
+ d->hidePopup(false);
+ break;
+ case QEvent::KeyPress: {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(event);
+ if (d->filterKeyEvent(ke, false))
+ return true;
+ event->accept();
+ if (d->extra.isAllocated())
+ d->extra->allowComplete = ke->key() != Qt::Key_Backspace && ke->key() != Qt::Key_Delete;
+ break;
+ }
+ case QEvent::FocusOut:
+ if (qGuiApp->focusObject() != this && (!d->popup || !d->popup->hasActiveFocus())) {
+ // Only close the popup if focus was transferred somewhere else
+ // than to the popup or the popup button (which normally means that
+ // the user clicked on the popup button to open it, not close it).
+ d->hidePopup(false);
+ setPressed(false);
+
+ // The focus left the text field, so if the edit text matches an item in the model,
+ // change our currentIndex to that. This matches widgets' behavior.
+ const int indexForEditText = find(d->extra.value().editText, Qt::MatchFixedString);
+ if (indexForEditText > -1)
+ setCurrentIndex(indexForEditText);
+ }
+ break;
+#if QT_CONFIG(im)
+ case QEvent::InputMethod:
+ if (d->extra.isAllocated())
+ d->extra->allowComplete = !static_cast<QInputMethodEvent*>(event)->commitString().isEmpty();
+ break;
+#endif
+ default:
+ break;
+ }
+ return QQuickControl::eventFilter(object, event);
+}
+
+void QQuickComboBox::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::focusInEvent(event);
+ // Setting focus on TextField should not be done when drop down indicator was clicked
+ // That is why, if focus is not set with key reason, it should not be passed to textEdit by default.
+ // Focus on Edit Text should be set only intentionally by user.
+ if ((event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason ||
+ event->reason() == Qt::ShortcutFocusReason) && d->contentItem && isEditable())
+ d->contentItem->forceActiveFocus(event->reason());
+}
+
+void QQuickComboBox::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::focusOutEvent(event);
+
+ if (qGuiApp->focusObject() != d->contentItem && (!d->popup || !d->popup->hasActiveFocus())) {
+ // Only close the popup if focus was transferred
+ // somewhere else than to the popup or the inner line edit (which is
+ // normally done from QQuickComboBox::focusInEvent).
+ d->hidePopup(false);
+ setPressed(false);
+ }
+}
+
+#if QT_CONFIG(im)
+void QQuickComboBox::inputMethodEvent(QInputMethodEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::inputMethodEvent(event);
+ if (!isEditable() && !event->commitString().isEmpty())
+ d->keySearch(event->commitString());
+ else
+ event->ignore();
+}
+#endif
+
+void QQuickComboBox::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::keyPressEvent(event);
+
+ switch (event->key()) {
+ case Qt::Key_Escape:
+ case Qt::Key_Back:
+ if (d->isPopupVisible())
+ event->accept();
+ break;
+ case Qt::Key_Space:
+ if (!event->isAutoRepeat())
+ setPressed(true);
+ event->accept();
+ break;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (d->isPopupVisible())
+ setPressed(true);
+ event->accept();
+ break;
+ case Qt::Key_Up:
+ d->keyNavigating = true;
+ d->decrementCurrentIndex();
+ event->accept();
+ break;
+ case Qt::Key_Down:
+ d->keyNavigating = true;
+ d->incrementCurrentIndex();
+ event->accept();
+ break;
+ case Qt::Key_Home:
+ d->keyNavigating = true;
+ if (d->isPopupVisible())
+ d->setHighlightedIndex(0, Highlight);
+ else
+ d->setCurrentIndex(0, Activate);
+ event->accept();
+ break;
+ case Qt::Key_End:
+ d->keyNavigating = true;
+ if (d->isPopupVisible())
+ d->setHighlightedIndex(count() - 1, Highlight);
+ else
+ d->setCurrentIndex(count() - 1, Activate);
+ event->accept();
+ break;
+ default:
+ if (!isEditable() && !event->text().isEmpty())
+ d->keySearch(event->text());
+ else
+ event->ignore();
+ break;
+ }
+}
+
+void QQuickComboBox::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::keyReleaseEvent(event);
+ d->keyNavigating = false;
+ if (event->isAutoRepeat())
+ return;
+
+ switch (event->key()) {
+ case Qt::Key_Space:
+ if (!isEditable())
+ d->togglePopup(true);
+ setPressed(false);
+ event->accept();
+ break;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ if (!isEditable() || d->isPopupVisible())
+ d->hidePopup(d->isPopupVisible());
+ setPressed(false);
+ event->accept();
+ break;
+ case Qt::Key_Escape:
+ case Qt::Key_Back:
+ if (d->isPopupVisible()) {
+ d->hidePopup(false);
+ setPressed(false);
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+#if QT_CONFIG(wheelevent)
+void QQuickComboBox::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::wheelEvent(event);
+ if (d->wheelEnabled && !d->isPopupVisible()) {
+ if (event->angleDelta().y() > 0)
+ d->decrementCurrentIndex();
+ else
+ d->incrementCurrentIndex();
+ }
+}
+#endif
+
+bool QQuickComboBox::event(QEvent *e)
+{
+ Q_D(QQuickComboBox);
+ if (e->type() == QEvent::LanguageChange)
+ d->updateCurrentTextAndValue();
+ return QQuickControl::event(e);
+}
+
+void QQuickComboBox::componentComplete()
+{
+ Q_D(QQuickComboBox);
+ d->executeIndicator(true);
+ QQuickControl::componentComplete();
+ if (d->popup)
+ d->executePopup(true);
+
+ if (d->delegateModel && d->ownModel)
+ static_cast<QQmlDelegateModel *>(d->delegateModel)->componentComplete();
+
+ if (count() > 0) {
+ if (!d->hasCurrentIndex && d->currentIndex == -1)
+ setCurrentIndex(0);
+ else
+ d->updateCurrentTextAndValue();
+
+ // If the widest text was already calculated in the call to
+ // QQmlDelegateModel::componentComplete() above, then we shouldn't do it here too.
+ if (!d->hasCalculatedWidestText)
+ d->maybeUpdateImplicitContentWidth();
+ }
+}
+
+void QQuickComboBox::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::itemChange(change, value);
+ if (change == ItemVisibleHasChanged && !value.boolValue) {
+ d->hidePopup(false);
+ setPressed(false);
+ }
+}
+
+void QQuickComboBox::fontChange(const QFont &newFont, const QFont &oldFont)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::fontChange(newFont, oldFont);
+ d->maybeUpdateImplicitContentWidth();
+}
+
+void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickComboBox);
+ if (oldItem) {
+ oldItem->removeEventFilter(this);
+ if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem)) {
+ QObjectPrivate::disconnect(oldInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
+ QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
+ disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickComboBox::inputMethodComposingChanged);
+ QObjectPrivate::disconnect(oldInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
+ }
+ }
+ if (newItem && isEditable()) {
+ newItem->installEventFilter(this);
+ if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem)) {
+ QObjectPrivate::connect(newInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput);
+ QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText);
+ connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickComboBox::inputMethodComposingChanged);
+ QObjectPrivate::connect(newInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput);
+ }
+#if QT_CONFIG(cursor)
+ newItem->setCursor(Qt::IBeamCursor);
+#endif
+ }
+
+ d->updateAcceptableInput();
+}
+
+void QQuickComboBox::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
+{
+ QQuickControl::localeChange(newLocale, oldLocale);
+#if QT_CONFIG(validator)
+ if (QValidator *v = validator())
+ v->setLocale(newLocale);
+#endif
+}
+
+QFont QQuickComboBox::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ComboBox);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickComboBox::accessibleRole() const
+{
+ return QAccessible::ComboBox;
+}
+
+void QQuickComboBox::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickComboBox);
+ QQuickControl::accessibilityActiveChanged(active);
+
+ if (active) {
+ maybeSetAccessibleName(d->hasDisplayText ? d->displayText : d->currentText);
+ setAccessibleProperty("editable", isEditable());
+ }
+}
+#endif //
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcombobox_p.cpp"
diff --git a/src/quicktemplates2/qquickcombobox_p.h b/src/quicktemplates2/qquickcombobox_p.h
new file mode 100644
index 0000000000..71dd836603
--- /dev/null
+++ b/src/quicktemplates2/qquickcombobox_p.h
@@ -0,0 +1,272 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCOMBOBOX_P_H
+#define QQUICKCOMBOBOX_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/qloggingcategory.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcItemManagement)
+
+class QValidator;
+class QQuickPopup;
+class QQmlInstanceModel;
+class QQuickComboBoxPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickComboBox : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL)
+ Q_PROPERTY(QQmlInstanceModel *delegateModel READ delegateModel NOTIFY delegateModelChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(int highlightedIndex READ highlightedIndex NOTIFY highlightedIndexChanged FINAL)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
+ Q_PROPERTY(QString currentText READ currentText NOTIFY currentTextChanged FINAL)
+ Q_PROPERTY(QString displayText READ displayText WRITE setDisplayText RESET resetDisplayText NOTIFY displayTextChanged FINAL)
+ Q_PROPERTY(QString textRole READ textRole WRITE setTextRole NOTIFY textRoleChanged FINAL)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
+ Q_PROPERTY(QQuickPopup *popup READ popup WRITE setPopup NOTIFY popupChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat NOTIFY flatChanged FINAL REVISION(2, 1))
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool down READ isDown WRITE setDown RESET resetDown NOTIFY downChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable NOTIFY editableChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(QString editText READ editText WRITE setEditText RESET resetEditText NOTIFY editTextChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(QValidator *validator READ validator WRITE setValidator NOTIFY validatorChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged FINAL REVISION(2, 2))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitIndicatorWidth READ implicitIndicatorWidth NOTIFY implicitIndicatorWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitIndicatorHeight READ implicitIndicatorHeight NOTIFY implicitIndicatorHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "background,contentItem,indicator,popup")
+ // 2.14 (Qt 5.14)
+ Q_PROPERTY(QVariant currentValue READ currentValue NOTIFY currentValueChanged FINAL REVISION(2, 14))
+ Q_PROPERTY(QString valueRole READ valueRole WRITE setValueRole NOTIFY valueRoleChanged FINAL REVISION(2, 14))
+ // 2.15 (Qt 5.15)
+ Q_PROPERTY(bool selectTextByMouse READ selectTextByMouse WRITE setSelectTextByMouse NOTIFY selectTextByMouseChanged FINAL REVISION(2, 15))
+ // 6.0 (Qt 6.0)
+ Q_PROPERTY(ImplicitContentWidthPolicy implicitContentWidthPolicy READ implicitContentWidthPolicy
+ WRITE setImplicitContentWidthPolicy NOTIFY implicitContentWidthPolicyChanged FINAL REVISION(6, 0))
+ QML_NAMED_ELEMENT(ComboBox)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickComboBox(QQuickItem *parent = nullptr);
+ ~QQuickComboBox();
+
+ int count() const;
+
+ QVariant model() const;
+ void setModel(const QVariant &model);
+ QQmlInstanceModel *delegateModel() const;
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ int highlightedIndex() const;
+
+ int currentIndex() const;
+ void setCurrentIndex(int index);
+
+ QString currentText() const;
+
+ QString displayText() const;
+ void setDisplayText(const QString &text);
+ void resetDisplayText();
+
+ QString textRole() const;
+ void setTextRole(const QString &role);
+
+ QString valueRole() const;
+ void setValueRole(const QString &role);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ QQuickItem *indicator() const;
+ void setIndicator(QQuickItem *indicator);
+
+ QQuickPopup *popup() const;
+ void setPopup(QQuickPopup *popup);
+
+ Q_INVOKABLE QString textAt(int index) const;
+ Q_INVOKABLE int find(const QString &text, Qt::MatchFlags flags = Qt::MatchExactly) const;
+
+ // 2.1 (Qt 5.8)
+ bool isFlat() const;
+ void setFlat(bool flat);
+
+ // 2.2 (Qt 5.9)
+ bool isDown() const;
+ void setDown(bool down);
+ void resetDown();
+
+ bool isEditable() const;
+ void setEditable(bool editable);
+
+ QString editText() const;
+ void setEditText(const QString &text);
+ void resetEditText();
+
+ QValidator *validator() const;
+ void setValidator(QValidator *validator);
+
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+
+ bool isInputMethodComposing() const;
+ bool hasAcceptableInput() const;
+
+ // 2.5 (Qt 5.12)
+ qreal implicitIndicatorWidth() const;
+ qreal implicitIndicatorHeight() const;
+
+ // 2.14 (Qt 5.14)
+ QVariant currentValue() const;
+ Q_REVISION(2, 14) Q_INVOKABLE QVariant valueAt(int index) const;
+ Q_REVISION(2, 14) Q_INVOKABLE int indexOfValue(const QVariant &value) const;
+
+ // 2.15 (Qt 5.15)
+ bool selectTextByMouse() const;
+ void setSelectTextByMouse(bool canSelect);
+
+ // 6.0 (Qt 6.0)
+ enum ImplicitContentWidthPolicy {
+ ContentItemImplicitWidth,
+ WidestText,
+ WidestTextWhenCompleted
+ };
+ Q_ENUM(ImplicitContentWidthPolicy)
+
+ ImplicitContentWidthPolicy implicitContentWidthPolicy() const;
+ void setImplicitContentWidthPolicy(ImplicitContentWidthPolicy policy);
+
+public Q_SLOTS:
+ void incrementCurrentIndex();
+ void decrementCurrentIndex();
+ Q_REVISION(2, 2) void selectAll();
+
+Q_SIGNALS:
+ void activated(int index);
+ void highlighted(int index);
+ void countChanged();
+ void modelChanged();
+ void delegateModelChanged();
+ void pressedChanged();
+ void highlightedIndexChanged();
+ void currentIndexChanged();
+ void currentTextChanged();
+ void displayTextChanged();
+ void textRoleChanged();
+ void delegateChanged();
+ void indicatorChanged();
+ void popupChanged();
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void flatChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void accepted();
+ Q_REVISION(2, 2) void downChanged();
+ Q_REVISION(2, 2) void editableChanged();
+ Q_REVISION(2, 2) void editTextChanged();
+ Q_REVISION(2, 2) void validatorChanged();
+ Q_REVISION(2, 2) void inputMethodHintsChanged();
+ Q_REVISION(2, 2) void inputMethodComposingChanged();
+ Q_REVISION(2, 2) void acceptableInputChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void implicitIndicatorWidthChanged();
+ Q_REVISION(2, 5) void implicitIndicatorHeightChanged();
+ // 2.14 (Qt 5.14)
+ Q_REVISION(2, 14) void valueRoleChanged();
+ Q_REVISION(2, 14) void currentValueChanged();
+ // 2.15 (Qt 5.15)
+ Q_REVISION(2, 15) void selectTextByMouseChanged();
+ // 6.0 (Qt 6.0)
+ Q_REVISION(6, 0) void implicitContentWidthPolicyChanged();
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+#if QT_CONFIG(im)
+ void inputMethodEvent(QInputMethodEvent *event) override;
+#endif
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+ bool event(QEvent *e) override;
+
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void fontChange(const QFont &newFont, const QFont &oldFont) override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickComboBox)
+ Q_DECLARE_PRIVATE(QQuickComboBox)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickComboBox)
+
+#endif // QQUICKCOMBOBOX_P_H
diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp
new file mode 100644
index 0000000000..e190c49470
--- /dev/null
+++ b/src/quicktemplates2/qquickcontainer.cpp
@@ -0,0 +1,913 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcontainer_p.h"
+#include "qquickcontainer_p_p.h"
+
+#include <QtQuick/private/qquickflickable_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Container
+ \inherits Control
+//! \instantiates QQuickContainer
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \brief Abstract base type providing functionality common to containers.
+
+ Container is the base type of container-like user interface controls that
+ allow dynamic insertion and removal of items.
+
+ \section2 Using Containers
+
+ Typically, items are statically declared as children of Container, but it
+ is also possible to \l {addItem}{add}, \l {insertItem}{insert},
+ \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The
+ items in a container can be accessed using \l itemAt() or
+ \l contentChildren.
+
+ Most containers have the concept of a "current" item. The current item is
+ specified via the \l currentIndex property, and can be accessed using the
+ read-only \l currentItem property.
+
+ The following example illustrates dynamic insertion of items to a \l TabBar,
+ which is one of the concrete implementations of Container.
+
+ \code
+ Row {
+ TabBar {
+ id: tabBar
+
+ currentIndex: 0
+ width: parent.width - addButton.width
+
+ TabButton { text: "TabButton" }
+ }
+
+ Component {
+ id: tabButton
+ TabButton { text: "TabButton" }
+ }
+
+ Button {
+ id: addButton
+ text: "+"
+ flat: true
+ onClicked: {
+ tabBar.addItem(tabButton.createObject(tabBar))
+ console.log("added:", tabBar.itemAt(tabBar.count - 1))
+ }
+ }
+ }
+ \endcode
+
+ \section2 Managing the Current Index
+
+ When using multiple containers, such as \l TabBar and \l SwipeView, together,
+ their \l currentIndex properties can be bound to each other to keep them in
+ sync. When the user interacts with either container, its current index changes
+ automatically propagate to the other container.
+
+ Notice, however, that assigning a \c currentIndex value in JavaScript removes
+ the respective binding. In order to retain the bindings, use the following
+ methods to alter the current index:
+
+ \list
+ \li \l incrementCurrentIndex()
+ \li \l decrementCurrentIndex()
+ \li \l setCurrentIndex()
+ \endlist
+
+ \code
+ TabBar {
+ id: tabBar
+ currentIndex: swipeView.currentIndex
+ }
+
+ SwipeView {
+ id: swipeView
+ currentIndex: tabBar.currentIndex
+ }
+
+ Button {
+ text: qsTr("Home")
+ onClicked: swipeView.setCurrentIndex(0)
+ enabled: swipeView.currentIndex != 0
+ }
+
+ Button {
+ text: qsTr("Previous")
+ onClicked: swipeView.decrementCurrentIndex()
+ enabled: swipeView.currentIndex > 0
+ }
+
+ Button {
+ text: qsTr("Next")
+ onClicked: swipeView.incrementCurrentIndex()
+ enabled: swipeView.currentIndex < swipeView.count - 1
+ }
+ \endcode
+
+
+ \section2 Implementing Containers
+
+ Container does not provide any default visualization. It is used to implement
+ such containers as \l SwipeView and \l TabBar. When implementing a custom
+ container, the most important part of the API is \l contentModel, which provides
+ the contained items in a way that it can be used as a delegate model for item
+ views and repeaters.
+
+ \code
+ Container {
+ id: container
+
+ contentItem: ListView {
+ model: container.contentModel
+ snapMode: ListView.SnapOneItem
+ orientation: ListView.Horizontal
+ }
+
+ Text {
+ text: "Page 1"
+ width: container.width
+ height: container.height
+ }
+
+ Text {
+ text: "Page 2"
+ width: container.width
+ height: container.height
+ }
+ }
+ \endcode
+
+ Notice how the sizes of the page items are set by hand. This is because the
+ example uses a plain Container, which does not make any assumptions on the
+ visual layout. It is typically not necessary to specify sizes for items in
+ concrete Container implementations, such as \l SwipeView and \l TabBar.
+
+ \sa {Container Controls}
+*/
+
+static QQuickItem *effectiveContentItem(QQuickItem *item)
+{
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(item);
+ if (flickable)
+ return flickable->contentItem();
+ return item;
+}
+
+void QQuickContainerPrivate::init()
+{
+ Q_Q(QQuickContainer);
+ contentModel = new QQmlObjectModel(q);
+ QObject::connect(contentModel, &QQmlObjectModel::countChanged, q, &QQuickContainer::countChanged);
+ QObject::connect(contentModel, &QQmlObjectModel::childrenChanged, q, &QQuickContainer::contentChildrenChanged);
+ connect(q, &QQuickControl::implicitContentWidthChanged, this, &QQuickContainerPrivate::updateContentWidth);
+ connect(q, &QQuickControl::implicitContentHeightChanged, this, &QQuickContainerPrivate::updateContentHeight);
+}
+
+void QQuickContainerPrivate::cleanup()
+{
+ Q_Q(QQuickContainer);
+ // ensure correct destruction order (QTBUG-46798)
+ const int count = contentModel->count();
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = itemAt(i);
+ if (item)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
+ }
+
+ if (contentItem) {
+ QQuickItem *focusItem = QQuickItemPrivate::get(contentItem)->subFocusItem;
+ if (focusItem && window)
+ QQuickWindowPrivate::get(window)->clearFocusInScope(contentItem, focusItem, Qt::OtherFocusReason);
+
+ q->contentItemChange(nullptr, contentItem);
+ QQuickControlPrivate::hideOldItem(contentItem);
+ }
+
+ QObject::disconnect(contentModel, &QQmlObjectModel::countChanged, q, &QQuickContainer::countChanged);
+ QObject::disconnect(contentModel, &QQmlObjectModel::childrenChanged, q, &QQuickContainer::contentChildrenChanged);
+ delete contentModel;
+ contentModel = nullptr;
+}
+
+QQuickItem *QQuickContainerPrivate::itemAt(int index) const
+{
+ return qobject_cast<QQuickItem *>(contentModel->get(index));
+}
+
+void QQuickContainerPrivate::insertItem(int index, QQuickItem *item)
+{
+ Q_Q(QQuickContainer);
+ if (!q->isContent(item))
+ return;
+ contentData.append(item);
+
+ updatingCurrent = true;
+
+ item->setParentItem(effectiveContentItem(q->contentItem()));
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, changeTypes);
+ contentModel->insert(index, item);
+
+ q->itemAdded(index, item);
+
+ int count = contentModel->count();
+ for (int i = index + 1; i < count; ++i)
+ q->itemMoved(i, itemAt(i));
+
+ if (count == 1 && currentIndex == -1)
+ q->setCurrentIndex(index);
+
+ updatingCurrent = false;
+}
+
+void QQuickContainerPrivate::moveItem(int from, int to, QQuickItem *item)
+{
+ Q_Q(QQuickContainer);
+ int oldCurrent = currentIndex;
+ contentModel->move(from, to);
+
+ updatingCurrent = true;
+
+ q->itemMoved(to, item);
+
+ if (from < to) {
+ for (int i = from; i < to; ++i)
+ q->itemMoved(i, itemAt(i));
+ } else {
+ for (int i = from; i > to; --i)
+ q->itemMoved(i, itemAt(i));
+ }
+
+ if (from == oldCurrent)
+ q->setCurrentIndex(to);
+ else if (from < oldCurrent && to >= oldCurrent)
+ q->setCurrentIndex(oldCurrent - 1);
+ else if (from > oldCurrent && to <= oldCurrent)
+ q->setCurrentIndex(oldCurrent + 1);
+
+ updatingCurrent = false;
+}
+
+void QQuickContainerPrivate::removeItem(int index, QQuickItem *item)
+{
+ Q_Q(QQuickContainer);
+ if (!q->isContent(item))
+ return;
+ contentData.removeOne(item);
+
+ updatingCurrent = true;
+
+ int count = contentModel->count();
+ bool currentChanged = false;
+ if (index == currentIndex && (index != 0 || count == 1)) {
+ q->setCurrentIndex(currentIndex - 1);
+ } else if (index < currentIndex) {
+ --currentIndex;
+ currentChanged = true;
+ }
+
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, changeTypes);
+ item->setParentItem(nullptr);
+ contentModel->remove(index);
+ --count;
+
+ q->itemRemoved(index, item);
+
+ for (int i = index; i < count; ++i)
+ q->itemMoved(i, itemAt(i));
+
+ if (currentChanged)
+ emit q->currentIndexChanged();
+
+ updatingCurrent = false;
+}
+
+void QQuickContainerPrivate::reorderItems()
+{
+ Q_Q(QQuickContainer);
+ if (!contentItem)
+ return;
+
+ QList<QQuickItem *> siblings = effectiveContentItem(contentItem)->childItems();
+
+ int to = 0;
+ for (int i = 0; i < siblings.count(); ++i) {
+ QQuickItem* sibling = siblings.at(i);
+ if (QQuickItemPrivate::get(sibling)->isTransparentForPositioner())
+ continue;
+ int index = contentModel->indexOf(sibling, nullptr);
+ q->moveItem(index, to++);
+ }
+}
+
+void QQuickContainerPrivate::_q_currentIndexChanged()
+{
+ Q_Q(QQuickContainer);
+ if (!updatingCurrent)
+ q->setCurrentIndex(contentItem ? contentItem->property("currentIndex").toInt() : -1);
+}
+
+void QQuickContainerPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
+{
+ // add dynamically reparented items (eg. by a Repeater)
+ if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child))
+ insertItem(contentModel->count(), child);
+}
+
+void QQuickContainerPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ // remove dynamically unparented items (eg. by a Repeater)
+ if (!parent)
+ removeItem(contentModel->indexOf(item, nullptr), item);
+}
+
+void QQuickContainerPrivate::itemSiblingOrderChanged(QQuickItem *)
+{
+ if (!componentComplete)
+ return;
+
+ // reorder the restacked items (eg. by a Repeater)
+ reorderItems();
+}
+
+void QQuickContainerPrivate::itemDestroyed(QQuickItem *item)
+{
+ int index = contentModel->indexOf(item, nullptr);
+ if (index != -1)
+ removeItem(index, item);
+ else
+ QQuickControlPrivate::itemDestroyed(item);
+}
+
+void QQuickContainerPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ QQuickContainerPrivate *p = QQuickContainerPrivate::get(q);
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (item) {
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ item->setParentItem(effectiveContentItem(q->contentItem()));
+ else if (p->contentModel->indexOf(item, nullptr) == -1)
+ q->addItem(item);
+ } else {
+ p->contentData.append(obj);
+ }
+}
+
+qsizetype QQuickContainerPrivate::contentData_count(QQmlListProperty<QObject> *prop)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return QQuickContainerPrivate::get(q)->contentData.count();
+}
+
+QObject *QQuickContainerPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return QQuickContainerPrivate::get(q)->contentData.value(index);
+}
+
+void QQuickContainerPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return QQuickContainerPrivate::get(q)->contentData.clear();
+}
+
+void QQuickContainerPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ q->addItem(item);
+}
+
+qsizetype QQuickContainerPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return QQuickContainerPrivate::get(q)->contentModel->count();
+}
+
+QQuickItem *QQuickContainerPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return q->itemAt(index);
+}
+
+void QQuickContainerPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickContainer *q = static_cast<QQuickContainer *>(prop->object);
+ return QQuickContainerPrivate::get(q)->contentModel->clear();
+}
+
+void QQuickContainerPrivate::updateContentWidth()
+{
+ Q_Q(QQuickContainer);
+ if (hasContentWidth || qFuzzyCompare(contentWidth, implicitContentWidth) || !contentModel)
+ return;
+
+ contentWidth = implicitContentWidth;
+ emit q->contentWidthChanged();
+}
+
+void QQuickContainerPrivate::updateContentHeight()
+{
+ Q_Q(QQuickContainer);
+ if (hasContentHeight || qFuzzyCompare(contentHeight, implicitContentHeight) || !contentModel)
+ return;
+
+ contentHeight = implicitContentHeight;
+ emit q->contentHeightChanged();
+}
+
+QQuickContainer::QQuickContainer(QQuickItem *parent)
+ : QQuickControl(*(new QQuickContainerPrivate), parent)
+{
+ Q_D(QQuickContainer);
+ d->init();
+}
+
+QQuickContainer::QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent)
+ : QQuickControl(dd, parent)
+{
+ Q_D(QQuickContainer);
+ d->init();
+}
+
+QQuickContainer::~QQuickContainer()
+{
+ Q_D(QQuickContainer);
+ d->cleanup();
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::Container::count
+ \readonly
+
+ This property holds the number of items.
+*/
+int QQuickContainer::count() const
+{
+ Q_D(const QQuickContainer);
+ return d->contentModel->count();
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::Container::itemAt(int index)
+
+ Returns the item at \a index, or \c null if it does not exist.
+*/
+QQuickItem *QQuickContainer::itemAt(int index) const
+{
+ Q_D(const QQuickContainer);
+ return d->itemAt(index);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::addItem(Item item)
+
+ Adds an \a item.
+*/
+void QQuickContainer::addItem(QQuickItem *item)
+{
+ Q_D(QQuickContainer);
+ insertItem(d->contentModel->count(), item);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::insertItem(int index, Item item)
+
+ Inserts an \a item at \a index.
+*/
+void QQuickContainer::insertItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickContainer);
+ if (!item)
+ return;
+ const int count = d->contentModel->count();
+ if (index < 0 || index > count)
+ index = count;
+
+ int oldIndex = d->contentModel->indexOf(item, nullptr);
+ if (oldIndex != -1) {
+ if (oldIndex < index)
+ --index;
+ if (oldIndex != index)
+ d->moveItem(oldIndex, index, item);
+ } else {
+ d->insertItem(index, item);
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::moveItem(int from, int to)
+
+ Moves an item \a from one index \a to another.
+*/
+void QQuickContainer::moveItem(int from, int to)
+{
+ Q_D(QQuickContainer);
+ const int count = d->contentModel->count();
+ if (from < 0 || from > count - 1)
+ return;
+ if (to < 0 || to > count - 1)
+ to = count - 1;
+
+ if (from != to)
+ d->moveItem(from, to, d->itemAt(from));
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Container::removeItem(Item item)
+
+ Removes and destroys the specified \a item.
+*/
+void QQuickContainer::removeItem(QQuickItem *item)
+{
+ Q_D(QQuickContainer);
+ if (!item)
+ return;
+
+ const int index = d->contentModel->indexOf(item, nullptr);
+ if (index == -1)
+ return;
+
+ d->removeItem(index, item);
+ item->deleteLater();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod Item QtQuick.Controls::Container::takeItem(int index)
+
+ Removes and returns the item at \a index.
+
+ \note The ownership of the item is transferred to the caller.
+*/
+QQuickItem *QQuickContainer::takeItem(int index)
+{
+ Q_D(QQuickContainer);
+ const int count = d->contentModel->count();
+ if (index < 0 || index >= count)
+ return nullptr;
+
+ QQuickItem *item = itemAt(index);
+ if (item)
+ d->removeItem(index, item);
+ return item;
+}
+
+/*!
+ \qmlproperty model QtQuick.Controls::Container::contentModel
+ \readonly
+
+ This property holds the content model of items.
+
+ The content model is provided for visualization purposes. It can be assigned
+ as a model to a content item that presents the contents of the container.
+
+ \code
+ Container {
+ id: container
+ contentItem: ListView {
+ model: container.contentModel
+ }
+ }
+ \endcode
+
+ \sa contentData, contentChildren
+*/
+QVariant QQuickContainer::contentModel() const
+{
+ Q_D(const QQuickContainer);
+ return QVariant::fromValue(d->contentModel);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::Container::contentData
+ \qmldefault
+
+ This property holds the list of content data.
+
+ The list contains all objects that have been declared in QML as children
+ of the container, and also items that have been dynamically added or
+ inserted using the \l addItem() and \l insertItem() methods, respectively.
+
+ \note Unlike \c contentChildren, \c contentData does include non-visual QML
+ objects. It is not re-ordered when items are inserted or moved.
+
+ \sa Item::data, contentChildren
+*/
+QQmlListProperty<QObject> QQuickContainer::contentData()
+{
+ Q_D(QQuickContainer);
+ if (!d->contentItem)
+ d->executeContentItem();
+ return QQmlListProperty<QObject>(this, nullptr,
+ QQuickContainerPrivate::contentData_append,
+ QQuickContainerPrivate::contentData_count,
+ QQuickContainerPrivate::contentData_at,
+ QQuickContainerPrivate::contentData_clear);
+}
+
+/*!
+ \qmlproperty list<Item> QtQuick.Controls::Container::contentChildren
+
+ This property holds the list of content children.
+
+ The list contains all items that have been declared in QML as children
+ of the container, and also items that have been dynamically added or
+ inserted using the \l addItem() and \l insertItem() methods, respectively.
+
+ \note Unlike \c contentData, \c contentChildren does not include non-visual
+ QML objects. It is re-ordered when items are inserted or moved.
+
+ \sa Item::children, contentData
+*/
+QQmlListProperty<QQuickItem> QQuickContainer::contentChildren()
+{
+ return QQmlListProperty<QQuickItem>(this, nullptr,
+ QQuickContainerPrivate::contentChildren_append,
+ QQuickContainerPrivate::contentChildren_count,
+ QQuickContainerPrivate::contentChildren_at,
+ QQuickContainerPrivate::contentChildren_clear);
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::Container::currentIndex
+
+ This property holds the index of the current item.
+
+ \sa currentItem, {Managing the Current Index}
+*/
+int QQuickContainer::currentIndex() const
+{
+ Q_D(const QQuickContainer);
+ return d->currentIndex;
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::setCurrentIndex(int index)
+
+ Sets the current \a index of the container.
+
+ This method can be called to set a specific current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
+*/
+void QQuickContainer::setCurrentIndex(int index)
+{
+ Q_D(QQuickContainer);
+ if (d->currentIndex == index)
+ return;
+
+ d->currentIndex = index;
+ emit currentIndexChanged();
+ emit currentItemChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::incrementCurrentIndex()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ Increments the current index of the container.
+
+ This method can be called to alter the current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
+*/
+void QQuickContainer::incrementCurrentIndex()
+{
+ Q_D(QQuickContainer);
+ if (d->currentIndex < count() - 1)
+ setCurrentIndex(d->currentIndex + 1);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::decrementCurrentIndex()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ Decrements the current index of the container.
+
+ This method can be called to alter the current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
+*/
+void QQuickContainer::decrementCurrentIndex()
+{
+ Q_D(QQuickContainer);
+ if (d->currentIndex > 0)
+ setCurrentIndex(d->currentIndex - 1);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Container::currentItem
+ \readonly
+
+ This property holds the current item.
+
+ \sa currentIndex
+*/
+QQuickItem *QQuickContainer::currentItem() const
+{
+ Q_D(const QQuickContainer);
+ return itemAt(d->currentIndex);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Container::contentWidth
+
+ This property holds the content width. It is used for calculating the total
+ implicit width of the container.
+
+ Unless explicitly overridden, the content width is automatically calculated
+ based on the implicit width of the items in the container.
+
+ \sa contentHeight
+*/
+qreal QQuickContainer::contentWidth() const
+{
+ Q_D(const QQuickContainer);
+ return d->contentWidth;
+}
+
+void QQuickContainer::setContentWidth(qreal width)
+{
+ Q_D(QQuickContainer);
+ d->hasContentWidth = true;
+ if (qFuzzyCompare(d->contentWidth, width))
+ return;
+
+ d->contentWidth = width;
+ d->resizeContent();
+ emit contentWidthChanged();
+}
+
+void QQuickContainer::resetContentWidth()
+{
+ Q_D(QQuickContainer);
+ if (!d->hasContentWidth)
+ return;
+
+ d->hasContentWidth = false;
+ d->updateContentWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Container::contentHeight
+
+ This property holds the content height. It is used for calculating the total
+ implicit height of the container.
+
+ Unless explicitly overridden, the content height is automatically calculated
+ based on the implicit height of the items in the container.
+
+ \sa contentWidth
+*/
+qreal QQuickContainer::contentHeight() const
+{
+ Q_D(const QQuickContainer);
+ return d->contentHeight;
+}
+
+void QQuickContainer::setContentHeight(qreal height)
+{
+ Q_D(QQuickContainer);
+ d->hasContentHeight = true;
+ if (qFuzzyCompare(d->contentHeight, height))
+ return;
+
+ d->contentHeight = height;
+ d->resizeContent();
+ emit contentHeightChanged();
+}
+
+void QQuickContainer::resetContentHeight()
+{
+ Q_D(QQuickContainer);
+ if (!d->hasContentHeight)
+ return;
+
+ d->hasContentHeight = false;
+ d->updateContentHeight();
+}
+
+void QQuickContainer::componentComplete()
+{
+ Q_D(QQuickContainer);
+ QQuickControl::componentComplete();
+ d->reorderItems();
+}
+
+void QQuickContainer::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ Q_D(QQuickContainer);
+ QQuickControl::itemChange(change, data);
+ if (change == QQuickItem::ItemChildAddedChange && isComponentComplete() && data.item != d->background && data.item != d->contentItem) {
+ if (!QQuickItemPrivate::get(data.item)->isTransparentForPositioner() && d->contentModel->indexOf(data.item, nullptr) == -1)
+ addItem(data.item);
+ }
+}
+
+void QQuickContainer::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickContainer);
+ QQuickControl::contentItemChange(newItem, oldItem);
+
+ static const int slotIndex = metaObject()->indexOfSlot("_q_currentIndexChanged()");
+
+ if (oldItem) {
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+ QQuickItem *oldContentItem = effectiveContentItem(oldItem);
+ if (oldContentItem != oldItem)
+ QQuickItemPrivate::get(oldContentItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
+
+ int signalIndex = oldItem->metaObject()->indexOfSignal("currentIndexChanged()");
+ if (signalIndex != -1)
+ QMetaObject::disconnect(oldItem, signalIndex, this, slotIndex);
+ }
+
+ if (newItem) {
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+ QQuickItem *newContentItem = effectiveContentItem(newItem);
+ if (newContentItem != newItem)
+ QQuickItemPrivate::get(newContentItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
+
+ int signalIndex = newItem->metaObject()->indexOfSignal("currentIndexChanged()");
+ if (signalIndex != -1)
+ QMetaObject::connect(newItem, signalIndex, this, slotIndex);
+ }
+}
+
+bool QQuickContainer::isContent(QQuickItem *item) const
+{
+ // If the item has a QML context associated to it (it was created in QML),
+ // we add it to the content model. Otherwise, it's probably the default
+ // highlight item that is always created by the item views, which we need
+ // to exclude.
+ //
+ // TODO: Find a better way to identify/exclude the highlight item...
+ return qmlContext(item);
+}
+
+void QQuickContainer::itemAdded(int index, QQuickItem *item)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(item);
+}
+
+void QQuickContainer::itemMoved(int index, QQuickItem *item)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(item);
+}
+
+void QQuickContainer::itemRemoved(int index, QQuickItem *item)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(item);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcontainer_p.cpp"
diff --git a/src/quicktemplates2/qquickcontainer_p.h b/src/quicktemplates2/qquickcontainer_p.h
new file mode 100644
index 0000000000..ccfe4c5618
--- /dev/null
+++ b/src/quicktemplates2/qquickcontainer_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCONTAINER_P_H
+#define QQUICKCONTAINER_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickContainerPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickContainer : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
+ Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL)
+ Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData)
+ Q_PROPERTY(QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
+ Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth RESET resetContentWidth NOTIFY contentWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight RESET resetContentHeight NOTIFY contentHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DefaultProperty", "contentData")
+ QML_NAMED_ELEMENT(Container)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickContainer(QQuickItem *parent = nullptr);
+ ~QQuickContainer();
+
+ int count() const;
+ Q_INVOKABLE QQuickItem *itemAt(int index) const;
+ Q_INVOKABLE void addItem(QQuickItem *item);
+ Q_INVOKABLE void insertItem(int index, QQuickItem *item);
+ Q_INVOKABLE void moveItem(int from, int to);
+ Q_INVOKABLE void removeItem(QQuickItem *item);
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickItem *takeItem(int index);
+
+ QVariant contentModel() const;
+ QQmlListProperty<QObject> contentData();
+ QQmlListProperty<QQuickItem> contentChildren();
+
+ int currentIndex() const;
+ QQuickItem *currentItem() const;
+
+ // 2.5 (Qt 5.12)
+ qreal contentWidth() const;
+ void setContentWidth(qreal width);
+ void resetContentWidth();
+
+ qreal contentHeight() const;
+ void setContentHeight(qreal height);
+ void resetContentHeight();
+
+public Q_SLOTS:
+ void setCurrentIndex(int index);
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void incrementCurrentIndex();
+ Q_REVISION(2, 1) void decrementCurrentIndex();
+
+Q_SIGNALS:
+ void countChanged();
+ void contentChildrenChanged();
+ void currentIndexChanged();
+ void currentItemChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void contentWidthChanged();
+ Q_REVISION(2, 5) void contentHeightChanged();
+
+protected:
+ QQuickContainer(QQuickContainerPrivate &dd, QQuickItem *parent);
+
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+
+ virtual bool isContent(QQuickItem *item) const;
+ virtual void itemAdded(int index, QQuickItem *item);
+ virtual void itemMoved(int index, QQuickItem *item);
+ virtual void itemRemoved(int index, QQuickItem *item);
+
+private:
+ Q_DISABLE_COPY(QQuickContainer)
+ Q_DECLARE_PRIVATE(QQuickContainer)
+ Q_PRIVATE_SLOT(d_func(), void _q_currentIndexChanged())
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickContainer)
+
+#endif // QQUICKCONTAINER_P_H
diff --git a/src/quicktemplates2/qquickcontainer_p_p.h b/src/quicktemplates2/qquickcontainer_p_p.h
new file mode 100644
index 0000000000..b9f8eb0f01
--- /dev/null
+++ b/src/quicktemplates2/qquickcontainer_p_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCONTAINER_P_P_H
+#define QQUICKCONTAINER_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <private/qqmlobjectmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickContainerPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickContainer)
+
+public:
+ static QQuickContainerPrivate *get(QQuickContainer *container)
+ {
+ return container->d_func();
+ }
+
+ void init();
+ void cleanup();
+
+ QQuickItem *itemAt(int index) const;
+ void insertItem(int index, QQuickItem *item);
+ void moveItem(int from, int to, QQuickItem *item);
+ void removeItem(int index, QQuickItem *item);
+ void reorderItems();
+
+ void _q_currentIndexChanged();
+
+ void itemChildAdded(QQuickItem *item, QQuickItem *child) override;
+ void itemSiblingOrderChanged(QQuickItem *item) override;
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+ static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
+ static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
+ static void contentData_clear(QQmlListProperty<QObject> *prop);
+
+ static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj);
+ static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
+ static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
+ static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
+
+ void updateContentWidth();
+ void updateContentHeight();
+
+ bool hasContentWidth = false;
+ bool hasContentHeight = false;
+ qreal contentWidth = 0;
+ qreal contentHeight = 0;
+ QObjectList contentData;
+ QQmlObjectModel *contentModel = nullptr;
+ qsizetype currentIndex = -1;
+ bool updatingCurrent = false;
+ QQuickItemPrivate::ChangeTypes changeTypes = Destroyed | Parent | SiblingOrder;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKCONTAINER_P_P_H
diff --git a/src/quicktemplates2/qquickcontentitem.cpp b/src/quicktemplates2/qquickcontentitem.cpp
new file mode 100644
index 0000000000..325eb1fb45
--- /dev/null
+++ b/src/quicktemplates2/qquickcontentitem.cpp
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcontentitem_p.h"
+
+#include <QtQml/private/qqmlmetatype_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \internal
+
+ Helper class that aids debugging by producing more useful debugging output.
+*/
+
+QQuickContentItem::QQuickContentItem(QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setObjectName(QQmlMetaType::prettyTypeName(parent));
+}
+
+QQuickContentItem::QQuickContentItem(const QObject *scope, QQuickItem *parent)
+ : QQuickItem(parent)
+{
+ setObjectName(QQmlMetaType::prettyTypeName(scope));
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcontentitem_p.cpp"
diff --git a/src/quicktemplates2/qquickcontentitem_p.h b/src/quicktemplates2/qquickcontentitem_p.h
new file mode 100644
index 0000000000..df0f0b243a
--- /dev/null
+++ b/src/quicktemplates2/qquickcontentitem_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCONTENTITEM_P_H
+#define QQUICKCONTENTITEM_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/qquickitem.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickContentItem : public QQuickItem
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickContentItem(QQuickItem *parent = nullptr);
+ explicit QQuickContentItem(const QObject *scope, QQuickItem *parent);
+
+private:
+ Q_DISABLE_COPY(QQuickContentItem)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKCONTENTITEM_P_H
diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp
new file mode 100644
index 0000000000..140b2a7f17
--- /dev/null
+++ b/src/quicktemplates2/qquickcontrol.cpp
@@ -0,0 +1,2231 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcontrol_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/qguiapplication.h>
+#include "qquicklabel_p.h"
+#include "qquicklabel_p_p.h"
+#include "qquicktextarea_p.h"
+#include "qquicktextarea_p_p.h"
+#include "qquicktextfield_p.h"
+#include "qquicktextfield_p_p.h"
+#include "qquickpopup_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickapplicationwindow_p.h"
+#include "qquickdeferredexecute_p_p.h"
+#include "qquickcontentitem_p.h"
+
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcItemManagement, "qt.quick.controls.control.itemmanagement")
+
+/*!
+ \qmltype Control
+ \inherits Item
+//! \instantiates QQuickControl
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \brief Abstract base type providing functionality common to all controls.
+
+ Control is the base type of user interface controls. It receives input
+ events from the window system, and paints a representation of itself on
+ the screen.
+
+ \section1 Control Layout
+
+ The following diagram illustrates the layout of a typical control:
+
+ \image qtquickcontrols2-control.png
+
+ The \l {Item::}{implicitWidth} and \l {Item::}{implicitHeight} of a control
+ are typically based on the implicit sizes of the background and the content
+ item plus any insets and paddings. These properties determine how large
+ the control will be when no explicit \l {Item::}{width} or
+ \l {Item::}{height} is specified.
+
+ The geometry of the \l {Control::}{contentItem} is determined by the padding.
+ The following example reserves 10px padding between the boundaries of the
+ control and its content:
+
+ \code
+ Control {
+ padding: 10
+
+ contentItem: Text {
+ text: "Content"
+ }
+ }
+ \endcode
+
+ The \l {Control::}{background} item fills the entire width and height of the
+ control, unless insets or an explicit size have been given for it. Background
+ insets are useful for extending the touchable/interactive area of a control
+ without affecting its visual size. This is often used on touch devices to
+ ensure that a control is not too small to be interacted with by the user.
+ Insets affect the size of the control, and hence will affect how much space
+ they take up in a layout, for example.
+
+ Negative insets can be used to make the background larger than the control.
+ The following example uses negative insets to place a shadow outside the
+ control's boundaries:
+
+ \code
+ Control {
+ topInset: -2
+ leftInset: -2
+ rightInset: -6
+ bottomInset: -6
+
+ background: BorderImage {
+ source: ":/images/shadowed-background.png"
+ }
+ }
+ \endcode
+
+ \section1 Event Handling
+
+ All controls, except non-interactive indicators, do not let clicks and
+ touches through to items below them. For example, the \c console.log()
+ call in the example below will never be executed when clicking on the
+ Pane, because the \l MouseArea is below it in the scene:
+
+ \code
+ MouseArea {
+ anchors.fill: parent
+ onClicked: console.log("MouseArea was clicked")
+
+ Pane {
+ anchors.fill: parent
+ }
+ }
+ \endcode
+
+ \sa ApplicationWindow, Container, {Using Qt Quick Controls types in
+ property declarations}
+*/
+
+const QQuickItemPrivate::ChangeTypes QQuickControlPrivate::ImplicitSizeChanges = QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight | QQuickItemPrivate::Destroyed;
+
+static bool isKeyFocusReason(Qt::FocusReason reason)
+{
+ return reason == Qt::TabFocusReason || reason == Qt::BacktabFocusReason || reason == Qt::ShortcutFocusReason;
+}
+
+QQuickControlPrivate::QQuickControlPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installActivationObserver(this);
+#endif
+}
+
+QQuickControlPrivate::~QQuickControlPrivate()
+{
+}
+
+void QQuickControlPrivate::init()
+{
+ Q_Q(QQuickControl);
+ QObject::connect(q, &QQuickItem::baselineOffsetChanged, q, &QQuickControl::baselineOffsetChanged);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickControlPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
+{
+ if (point.id() == touchId)
+ return true;
+
+ if (touchId == -1 && point.state() == QEventPoint::Pressed) {
+ touchId = point.id();
+ return true;
+ }
+
+ // If the control is on a Flickable that has a pressDelay, then the press is never
+ // sent as a touch event, therefore we need to check for this case.
+ if (touchId == -1 && pressWasTouch && point.state() == QEventPoint::Released &&
+ point.position() == previousPressPos) {
+ return true;
+ }
+ return false;
+}
+#endif
+
+static void setActiveFocus(QQuickControl *control, Qt::FocusReason reason)
+{
+ QQuickControlPrivate *d = QQuickControlPrivate::get(control);
+ if (d->subFocusItem && d->window && d->flags & QQuickItem::ItemIsFocusScope)
+ QQuickWindowPrivate::get(d->window)->clearFocusInScope(control, d->subFocusItem, reason);
+ control->forceActiveFocus(reason);
+}
+
+void QQuickControlPrivate::handlePress(const QPointF &)
+{
+ Q_Q(QQuickControl);
+ if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && !QGuiApplication::styleHints()->setFocusOnTouchRelease())
+ setActiveFocus(q, Qt::MouseFocusReason);
+}
+
+void QQuickControlPrivate::handleMove(const QPointF &point)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_Q(QQuickControl);
+ q->setHovered(hoverEnabled && q->contains(point));
+#else
+ Q_UNUSED(point);
+#endif
+}
+
+void QQuickControlPrivate::handleRelease(const QPointF &)
+{
+ Q_Q(QQuickControl);
+ if ((focusPolicy & Qt::ClickFocus) == Qt::ClickFocus && QGuiApplication::styleHints()->setFocusOnTouchRelease())
+ setActiveFocus(q, Qt::MouseFocusReason);
+ touchId = -1;
+ pressWasTouch = false;
+ previousPressPos = QPointF();
+}
+
+void QQuickControlPrivate::handleUngrab()
+{
+ touchId = -1;
+}
+
+void QQuickControlPrivate::mirrorChange()
+{
+ Q_Q(QQuickControl);
+ q->mirrorChange();
+}
+
+void QQuickControlPrivate::setTopPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ extra.value().topPadding = value;
+ extra.value().hasTopPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldPadding.top(), value)) || (reset && !qFuzzyCompare(oldPadding.top(), getVerticalPadding()))) {
+ emit q->topPaddingChanged();
+ emit q->availableHeightChanged();
+ q->paddingChange(getPadding(), oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setLeftPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ extra.value().leftPadding = value;
+ extra.value().hasLeftPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldPadding.left(), value)) || (reset && !qFuzzyCompare(oldPadding.left(), getHorizontalPadding()))) {
+ emit q->leftPaddingChanged();
+ emit q->availableWidthChanged();
+ q->paddingChange(getPadding(), oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setRightPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ extra.value().rightPadding = value;
+ extra.value().hasRightPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldPadding.right(), value)) || (reset && !qFuzzyCompare(oldPadding.right(), getHorizontalPadding()))) {
+ emit q->rightPaddingChanged();
+ emit q->availableWidthChanged();
+ q->paddingChange(getPadding(), oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setBottomPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ extra.value().bottomPadding = value;
+ extra.value().hasBottomPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldPadding.bottom(), value)) || (reset && !qFuzzyCompare(oldPadding.bottom(), getVerticalPadding()))) {
+ emit q->bottomPaddingChanged();
+ emit q->availableHeightChanged();
+ q->paddingChange(getPadding(), oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setHorizontalPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ const qreal oldHorizontalPadding = getHorizontalPadding();
+ horizontalPadding = value;
+ hasHorizontalPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldHorizontalPadding, value)) || (reset && !qFuzzyCompare(oldHorizontalPadding, padding))) {
+ const QMarginsF newPadding = getPadding();
+ if (!qFuzzyCompare(newPadding.left(), oldPadding.left()))
+ emit q->leftPaddingChanged();
+ if (!qFuzzyCompare(newPadding.right(), oldPadding.right()))
+ emit q->rightPaddingChanged();
+ emit q->horizontalPaddingChanged();
+ emit q->availableWidthChanged();
+ q->paddingChange(newPadding, oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setVerticalPadding(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldPadding = getPadding();
+ const qreal oldVerticalPadding = getVerticalPadding();
+ verticalPadding = value;
+ hasVerticalPadding = !reset;
+ if ((!reset && !qFuzzyCompare(oldVerticalPadding, value)) || (reset && !qFuzzyCompare(oldVerticalPadding, padding))) {
+ const QMarginsF newPadding = getPadding();
+ if (!qFuzzyCompare(newPadding.top(), oldPadding.top()))
+ emit q->topPaddingChanged();
+ if (!qFuzzyCompare(newPadding.bottom(), oldPadding.bottom()))
+ emit q->bottomPaddingChanged();
+ emit q->verticalPaddingChanged();
+ emit q->availableHeightChanged();
+ q->paddingChange(newPadding, oldPadding);
+ }
+}
+
+void QQuickControlPrivate::setTopInset(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldInset = getInset();
+ extra.value().topInset = value;
+ extra.value().hasTopInset = !reset;
+ if (!qFuzzyCompare(oldInset.top(), value)) {
+ emit q->topInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickControlPrivate::setLeftInset(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldInset = getInset();
+ extra.value().leftInset = value;
+ extra.value().hasLeftInset = !reset;
+ if (!qFuzzyCompare(oldInset.left(), value)) {
+ emit q->leftInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickControlPrivate::setRightInset(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldInset = getInset();
+ extra.value().rightInset = value;
+ extra.value().hasRightInset = !reset;
+ if (!qFuzzyCompare(oldInset.right(), value)) {
+ emit q->rightInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickControlPrivate::setBottomInset(qreal value, bool reset)
+{
+ Q_Q(QQuickControl);
+ const QMarginsF oldInset = getInset();
+ extra.value().bottomInset = value;
+ extra.value().hasBottomInset = !reset;
+ if (!qFuzzyCompare(oldInset.bottom(), value)) {
+ emit q->bottomInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickControlPrivate::resizeBackground()
+{
+ if (!background)
+ return;
+
+ resizingBackground = true;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ bool changeWidth = false;
+ bool changeHeight = false;
+ if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
+ || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
+ background->setX(getLeftInset());
+ changeWidth = !p->width.hasBinding();
+ }
+ if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
+ || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
+ background->setY(getTopInset());
+ changeHeight = !p->height.hasBinding();
+ }
+ if (changeHeight || changeWidth) {
+ auto newWidth = changeWidth ?
+ width.valueBypassingBindings() - getLeftInset() - getRightInset() :
+ p->width.valueBypassingBindings();
+ auto newHeight = changeHeight ?
+ height.valueBypassingBindings() - getTopInset() - getBottomInset() :
+ p->height.valueBypassingBindings();
+ background->setSize({newWidth, newHeight});
+ }
+
+ resizingBackground = false;
+}
+
+void QQuickControlPrivate::resizeContent()
+{
+ Q_Q(QQuickControl);
+ if (contentItem) {
+ contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding()));
+ contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight()));
+ }
+}
+
+QQuickItem *QQuickControlPrivate::getContentItem()
+{
+ if (!contentItem)
+ executeContentItem();
+ return contentItem;
+}
+
+void QQuickControlPrivate::setContentItem_helper(QQuickItem *item, bool notify)
+{
+ Q_Q(QQuickControl);
+ if (contentItem == item)
+ return;
+
+ if (!contentItem.isExecuting())
+ cancelContentItem();
+
+ QQuickItem *oldContentItem = contentItem;
+ if (oldContentItem) {
+ disconnect(oldContentItem, &QQuickItem::baselineOffsetChanged, this, &QQuickControlPrivate::updateBaselineOffset);
+ if (oldContentItem)
+ QQuickItemPrivate::get(oldContentItem)->removeItemChangeListener(this, QQuickControlPrivate::Focus);
+ removeImplicitSizeListener(oldContentItem);
+ }
+
+ contentItem = item;
+ q->contentItemChange(item, oldContentItem);
+ QQuickControlPrivate::hideOldItem(oldContentItem);
+
+ if (item) {
+ connect(contentItem.data(), &QQuickItem::baselineOffsetChanged, this, &QQuickControlPrivate::updateBaselineOffset);
+ // We need to update the control's focusReason when the contentItem receives or loses focus. Since focusPolicy
+ // (or other properties impacting focus handling, like QQuickItem::activeFocusOnTab) might change later, and
+ // since the content item might also change focus programmatically, we always have to listen for those events.
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickControlPrivate::Focus);
+ if (!item->parentItem())
+ item->setParentItem(q);
+ if (componentComplete)
+ resizeContent();
+ addImplicitSizeListener(contentItem);
+ }
+
+ updateImplicitContentSize();
+ updateBaselineOffset();
+
+ if (notify && !contentItem.isExecuting())
+ emit q->contentItemChanged();
+}
+
+qreal QQuickControlPrivate::getContentWidth() const
+{
+ return contentItem ? contentItem->implicitWidth() : 0;
+}
+
+qreal QQuickControlPrivate::getContentHeight() const
+{
+ return contentItem ? contentItem->implicitHeight() : 0;
+}
+
+void QQuickControlPrivate::updateImplicitContentWidth()
+{
+ Q_Q(QQuickControl);
+ const qreal oldWidth = implicitContentWidth;
+ implicitContentWidth = getContentWidth();
+ if (!qFuzzyCompare(implicitContentWidth, oldWidth))
+ emit q->implicitContentWidthChanged();
+}
+
+void QQuickControlPrivate::updateImplicitContentHeight()
+{
+ Q_Q(QQuickControl);
+ const qreal oldHeight = implicitContentHeight;
+ implicitContentHeight = getContentHeight();
+ if (!qFuzzyCompare(implicitContentHeight, oldHeight))
+ emit q->implicitContentHeightChanged();
+}
+
+void QQuickControlPrivate::updateImplicitContentSize()
+{
+ Q_Q(QQuickControl);
+ const qreal oldWidth = implicitContentWidth;
+ const qreal oldHeight = implicitContentHeight;
+ implicitContentWidth = getContentWidth();
+ implicitContentHeight = getContentHeight();
+ if (!qFuzzyCompare(implicitContentWidth, oldWidth))
+ emit q->implicitContentWidthChanged();
+ if (!qFuzzyCompare(implicitContentHeight, oldHeight))
+ emit q->implicitContentHeightChanged();
+}
+
+QPalette QQuickControlPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::System);
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickControlPrivate::accessibilityActiveChanged(bool active)
+{
+ Q_Q(QQuickControl);
+ return q->accessibilityActiveChanged(active);
+}
+
+QAccessible::Role QQuickControlPrivate::accessibleRole() const
+{
+ Q_Q(const QQuickControl);
+ return q->accessibleRole();
+}
+
+QQuickAccessibleAttached *QQuickControlPrivate::accessibleAttached(const QObject *object)
+{
+ if (!QAccessible::isActive())
+ return nullptr;
+ return QQuickAccessibleAttached::attachedProperties(object);
+}
+#endif
+
+/*!
+ \internal
+
+ Returns the font that the control w inherits from its ancestors and
+ QGuiApplication::font.
+*/
+QFont QQuickControlPrivate::parentFont(const QQuickItem *item)
+{
+ QQuickItem *p = item->parentItem();
+ while (p) {
+ if (QQuickControl *control = qobject_cast<QQuickControl *>(p))
+ return control->font();
+ else if (QQuickLabel *label = qobject_cast<QQuickLabel *>(p))
+ return label->font();
+ else if (QQuickTextField *textField = qobject_cast<QQuickTextField *>(p))
+ return textField->font();
+ else if (QQuickTextArea *textArea = qobject_cast<QQuickTextArea *>(p))
+ return textArea->font();
+
+ p = p->parentItem();
+ }
+
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(item->window()))
+ return window->font();
+
+ return QQuickTheme::font(QQuickTheme::System);
+}
+
+/*!
+ \internal
+
+ Determine which font is implicitly imposed on this control by its ancestors
+ and QGuiApplication::font, resolve this against its own font (attributes from
+ the implicit font are copied over). Then propagate this font to this
+ control's children.
+*/
+void QQuickControlPrivate::resolveFont()
+{
+ Q_Q(QQuickControl);
+ inheritFont(parentFont(q));
+}
+
+void QQuickControlPrivate::inheritFont(const QFont &font)
+{
+ Q_Q(QQuickControl);
+ QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
+ parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
+
+ const QFont defaultFont = q->defaultFont();
+ QFont resolvedFont = parentFont.resolve(defaultFont);
+
+ setFont_helper(resolvedFont);
+}
+
+/*!
+ \internal
+
+ Assign \a font to this control, and propagate it to all children.
+*/
+void QQuickControlPrivate::updateFont(const QFont &font)
+{
+ Q_Q(QQuickControl);
+ QFont oldFont = resolvedFont;
+ resolvedFont = font;
+
+ if (oldFont != font)
+ q->fontChange(font, oldFont);
+
+ QQuickControlPrivate::updateFontRecur(q, font);
+
+ if (oldFont != font)
+ emit q->fontChanged();
+}
+
+void QQuickControlPrivate::updateFontRecur(QQuickItem *item, const QFont &font)
+{
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
+ if (QQuickControl *control = qobject_cast<QQuickControl *>(child))
+ QQuickControlPrivate::get(control)->inheritFont(font);
+ else if (QQuickLabel *label = qobject_cast<QQuickLabel *>(child))
+ QQuickLabelPrivate::get(label)->inheritFont(font);
+ else if (QQuickTextArea *textArea = qobject_cast<QQuickTextArea *>(child))
+ QQuickTextAreaPrivate::get(textArea)->inheritFont(font);
+ else if (QQuickTextField *textField = qobject_cast<QQuickTextField *>(child))
+ QQuickTextFieldPrivate::get(textField)->inheritFont(font);
+ else
+ QQuickControlPrivate::updateFontRecur(child, font);
+ }
+}
+
+QLocale QQuickControlPrivate::calcLocale(const QQuickItem *item)
+{
+ const QQuickItem *p = item;
+ while (p) {
+ if (const QQuickControl *control = qobject_cast<const QQuickControl *>(p))
+ return control->locale();
+
+ QVariant v = p->property("locale");
+ if (v.isValid() && v.userType() == QMetaType::QLocale)
+ return v.toLocale();
+
+ p = p->parentItem();
+ }
+
+ if (item) {
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(item->window()))
+ return window->locale();
+ }
+
+ return QLocale();
+}
+
+void QQuickControlPrivate::updateLocale(const QLocale &l, bool e)
+{
+ Q_Q(QQuickControl);
+ if (!e && hasLocale)
+ return;
+
+ QLocale old = q->locale();
+ hasLocale = e;
+ if (old != l) {
+ locale = l;
+ q->localeChange(l, old);
+ QQuickControlPrivate::updateLocaleRecur(q, l);
+ emit q->localeChanged();
+ }
+}
+
+void QQuickControlPrivate::updateLocaleRecur(QQuickItem *item, const QLocale &l)
+{
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
+ if (QQuickControl *control = qobject_cast<QQuickControl *>(child))
+ QQuickControlPrivate::get(control)->updateLocale(l, false);
+ else
+ updateLocaleRecur(child, l);
+ }
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickControlPrivate::updateHoverEnabled(bool enabled, bool xplicit)
+{
+ Q_Q(QQuickControl);
+ if (!xplicit && explicitHoverEnabled)
+ return;
+
+ bool wasEnabled = q->isHoverEnabled();
+ explicitHoverEnabled = xplicit;
+ if (wasEnabled != enabled) {
+ q->setAcceptHoverEvents(enabled);
+ QQuickControlPrivate::updateHoverEnabledRecur(q, enabled);
+ emit q->hoverEnabledChanged();
+ }
+}
+
+void QQuickControlPrivate::updateHoverEnabledRecur(QQuickItem *item, bool enabled)
+{
+ const auto childItems = item->childItems();
+ for (QQuickItem *child : childItems) {
+ if (QQuickControl *control = qobject_cast<QQuickControl *>(child))
+ QQuickControlPrivate::get(control)->updateHoverEnabled(enabled, false);
+ else
+ updateHoverEnabledRecur(child, enabled);
+ }
+}
+
+bool QQuickControlPrivate::calcHoverEnabled(const QQuickItem *item)
+{
+ const QQuickItem *p = item;
+ while (p) {
+ // QQuickPopupItem accepts hover events to avoid leaking them through.
+ // Don't inherit that to the children of the popup, but fallback to the
+ // environment variable or style hint.
+ if (qobject_cast<const QQuickPopupItem *>(p))
+ break;
+
+ if (const QQuickControl *control = qobject_cast<const QQuickControl *>(p))
+ return control->isHoverEnabled();
+
+ QVariant v = p->property("hoverEnabled");
+ if (v.isValid() && v.userType() == QMetaType::Bool)
+ return v.toBool();
+
+ p = p->parentItem();
+ }
+
+ bool ok = false;
+ int env = qEnvironmentVariableIntValue("QT_QUICK_CONTROLS_HOVER_ENABLED", &ok);
+ if (ok)
+ return env != 0;
+
+ // TODO: QQuickApplicationWindow::isHoverEnabled()
+
+ return QGuiApplication::styleHints()->useHoverEffects();
+}
+#endif
+
+static inline QString contentItemName() { return QStringLiteral("contentItem"); }
+
+void QQuickControlPrivate::cancelContentItem()
+{
+ Q_Q(QQuickControl);
+ quickCancelDeferred(q, contentItemName());
+}
+
+void QQuickControlPrivate::executeContentItem(bool complete)
+{
+ Q_Q(QQuickControl);
+ if (contentItem.wasExecuted())
+ return;
+
+ if (!contentItem || complete)
+ quickBeginDeferred(q, contentItemName(), contentItem);
+ if (complete)
+ quickCompleteDeferred(q, contentItemName(), contentItem);
+}
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickControlPrivate::cancelBackground()
+{
+ Q_Q(QQuickControl);
+ quickCancelDeferred(q, backgroundName());
+}
+
+void QQuickControlPrivate::executeBackground(bool complete)
+{
+ Q_Q(QQuickControl);
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
+}
+
+/*
+ \internal
+
+ Hides an item that was replaced by a newer one, rather than
+ deleting it, as the item is typically created in QML and hence
+ we don't own it.
+*/
+void QQuickControlPrivate::hideOldItem(QQuickItem *item)
+{
+ if (!item)
+ return;
+
+ qCDebug(lcItemManagement) << "hiding old item" << item;
+
+ item->setVisible(false);
+ item->setParentItem(nullptr);
+
+#if QT_CONFIG(accessibility)
+ // Remove the item from the accessibility tree.
+ QQuickAccessibleAttached *accessible = accessibleAttached(item);
+ if (accessible)
+ accessible->setIgnored(true);
+#endif
+}
+
+/*
+ \internal
+
+ Named "unhide" because it's used for cases where an item
+ that was previously hidden by \l hideOldItem() wants to be
+ shown by a control again, such as a ScrollBar in ScrollView.
+*/
+void QQuickControlPrivate::unhideOldItem(QQuickControl *control, QQuickItem *item)
+{
+ Q_ASSERT(item);
+ qCDebug(lcItemManagement) << "unhiding old item" << item;
+
+ item->setVisible(true);
+ item->setParentItem(control);
+
+#if QT_CONFIG(accessibility)
+ // Add the item back in to the accessibility tree.
+ QQuickAccessibleAttached *accessible = accessibleAttached(item);
+ if (accessible)
+ accessible->setIgnored(false);
+#endif
+}
+
+void QQuickControlPrivate::updateBaselineOffset()
+{
+ Q_Q(QQuickControl);
+ if (extra.isAllocated() && extra.value().hasBaselineOffset)
+ return;
+
+ if (!contentItem)
+ q->QQuickItem::setBaselineOffset(0);
+ else
+ q->QQuickItem::setBaselineOffset(getTopPadding() + contentItem->baselineOffset());
+}
+
+void QQuickControlPrivate::addImplicitSizeListener(QQuickItem *item, ChangeTypes changes)
+{
+ addImplicitSizeListener(item, this, changes);
+}
+
+void QQuickControlPrivate::removeImplicitSizeListener(QQuickItem *item, ChangeTypes changes)
+{
+ removeImplicitSizeListener(item, this, changes);
+}
+
+void QQuickControlPrivate::addImplicitSizeListener(QQuickItem *item, QQuickItemChangeListener *listener, ChangeTypes changes)
+{
+ if (!item || !listener)
+ return;
+ QQuickItemPrivate::get(item)->addItemChangeListener(listener, changes);
+}
+
+void QQuickControlPrivate::removeImplicitSizeListener(QQuickItem *item, QQuickItemChangeListener *listener, ChangeTypes changes)
+{
+ if (!item || !listener)
+ return;
+ QQuickItemPrivate::get(item)->removeItemChangeListener(listener, changes);
+}
+
+void QQuickControlPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickControl);
+ if (item == background)
+ emit q->implicitBackgroundWidthChanged();
+ else if (item == contentItem)
+ updateImplicitContentWidth();
+}
+
+void QQuickControlPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickControl);
+ if (item == background)
+ emit q->implicitBackgroundHeightChanged();
+ else if (item == contentItem)
+ updateImplicitContentHeight();
+}
+
+void QQuickControlPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(diff);
+ if (resizingBackground || item != background || !change.sizeChange())
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ // Only set hasBackgroundWidth/Height if it was a width/height change,
+ // otherwise we're prevented from setting a width/height in the future.
+ if (change.widthChange())
+ extra.value().hasBackgroundWidth = p->widthValid();
+ if (change.heightChange())
+ extra.value().hasBackgroundHeight = p->heightValid();
+ resizeBackground();
+}
+
+void QQuickControlPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickControl);
+ if (item == background) {
+ background = nullptr;
+ emit q->implicitBackgroundWidthChanged();
+ emit q->implicitBackgroundHeightChanged();
+ } else if (item == contentItem) {
+ contentItem = nullptr;
+ updateImplicitContentSize();
+ }
+}
+
+void QQuickControlPrivate::itemFocusChanged(QQuickItem *item, Qt::FocusReason reason)
+{
+ Q_Q(QQuickControl);
+ if (item == contentItem || item == q)
+ q->setFocusReason(reason);
+}
+
+QQuickControl::QQuickControl(QQuickItem *parent)
+ : QQuickItem(*(new QQuickControlPrivate), parent)
+{
+ Q_D(QQuickControl);
+ d->init();
+}
+
+QQuickControl::QQuickControl(QQuickControlPrivate &dd, QQuickItem *parent)
+ : QQuickItem(dd, parent)
+{
+ Q_D(QQuickControl);
+ d->init();
+}
+
+QQuickControl::~QQuickControl()
+{
+ Q_D(QQuickControl);
+ d->removeImplicitSizeListener(d->background, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ d->removeImplicitSizeListener(d->contentItem);
+ if (d->contentItem)
+ QQuickItemPrivate::get(d->contentItem)->removeItemChangeListener(d, QQuickItemPrivate::Focus);
+#if QT_CONFIG(accessibility)
+ QAccessible::removeActivationObserver(d);
+#endif
+}
+
+void QQuickControl::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ Q_D(QQuickControl);
+ QQuickItem::itemChange(change, value);
+ switch (change) {
+ case ItemEnabledHasChanged:
+ enabledChange();
+ break;
+ case ItemVisibleHasChanged:
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!value.boolValue)
+ setHovered(false);
+#endif
+ break;
+ case ItemSceneChange:
+ case ItemParentHasChanged:
+ if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
+ d->resolveFont();
+ if (!d->hasLocale)
+ d->updateLocale(QQuickControlPrivate::calcLocale(d->parentItem), false); // explicit=false
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+ }
+ break;
+ case ItemActiveFocusHasChanged:
+ if (isKeyFocusReason(d->focusReason))
+ emit visualFocusChanged();
+ break;
+ default:
+ break;
+ }
+}
+
+/*!
+ \qmlproperty font QtQuick.Controls::Control::font
+
+ This property holds the font currently set for the control.
+
+ This property describes the control's requested font. The font is used by the control's
+ style when rendering standard components, and is available as a means to ensure that custom
+ controls can maintain consistency with the native platform's native look and feel. It's common
+ that different platforms, or different styles, define different fonts for an application.
+
+ The default font depends on the system environment. ApplicationWindow maintains a system/theme
+ font which serves as a default for all controls. There may also be special font defaults for
+ certain types of controls. You can also set the default font for controls by either:
+
+ \list
+ \li passing a custom font to QGuiApplication::setFont(), before loading the QML; or
+ \li specifying the fonts in the \l {Qt Quick Controls 2 Configuration File}{qtquickcontrols2.conf file}.
+ \endlist
+
+ Finally, the font is matched against Qt's font database to find the best match.
+
+ Control propagates explicit font properties from parent to children. If you change a specific
+ property on a control's font, that property propagates to all of the control's children,
+ overriding any system defaults for that property.
+
+ \code
+ Page {
+ font.family: "Courier"
+
+ Column {
+ Label {
+ text: qsTr("This will use Courier...")
+ }
+
+ Switch {
+ text: qsTr("... and so will this")
+ }
+ }
+ }
+ \endcode
+
+ For the full list of available font properties, see the
+ \l [QtQuick]{font}{font QML Basic Type} documentation.
+*/
+QFont QQuickControl::font() const
+{
+ Q_D(const QQuickControl);
+ return d->resolvedFont;
+}
+
+void QQuickControl::setFont(const QFont &font)
+{
+ Q_D(QQuickControl);
+ if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
+ return;
+
+ d->extra.value().requestedFont = font;
+ d->resolveFont();
+}
+
+void QQuickControl::resetFont()
+{
+ setFont(QFont());
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::availableWidth
+ \readonly
+
+ This property holds the width available to the \l contentItem after
+ deducting horizontal padding from the \l {Item::}{width} of the control.
+
+ \sa {Control Layout}, padding, leftPadding, rightPadding
+*/
+qreal QQuickControl::availableWidth() const
+{
+ return qMax<qreal>(0.0, width() - leftPadding() - rightPadding());
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::availableHeight
+ \readonly
+
+ This property holds the height available to the \l contentItem after
+ deducting vertical padding from the \l {Item::}{height} of the control.
+
+ \sa {Control Layout}, padding, topPadding, bottomPadding
+*/
+qreal QQuickControl::availableHeight() const
+{
+ return qMax<qreal>(0.0, height() - topPadding() - bottomPadding());
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::padding
+
+ This property holds the default padding.
+
+ Padding adds a space between each edge of the content item and the
+ background item, effectively controlling the size of the content item. To
+ specify a padding value for a specific edge of the control, set its
+ relevant property:
+
+ \list
+ \li \l {Control::}{leftPadding}
+ \li \l {Control::}{rightPadding}
+ \li \l {Control::}{topPadding}
+ \li \l {Control::}{bottomPadding}
+ \endlist
+
+ \note Different styles may specify the default padding for certain controls
+ in different ways, and these ways may change over time as the design
+ guidelines that the style is based on evolve. To ensure that these changes
+ don't affect the padding values you have specified, it is best to use the
+ most specific properties available. For example, rather than setting
+ the \l padding property:
+
+ \code
+ padding: 0
+ \endcode
+
+ set each specific property instead:
+
+ \code
+ leftPadding: 0
+ rightPadding: 0
+ topPadding: 0
+ bottomPadding: 0
+ \endcode
+
+ \sa {Control Layout}, availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding
+*/
+qreal QQuickControl::padding() const
+{
+ Q_D(const QQuickControl);
+ return d->padding;
+}
+
+void QQuickControl::setPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ if (qFuzzyCompare(d->padding, padding))
+ return;
+
+ const QMarginsF oldPadding = d->getPadding();
+ const qreal oldVerticalPadding = d->getVerticalPadding();
+ const qreal oldHorizontalPadding = d->getHorizontalPadding();
+
+ d->padding = padding;
+ emit paddingChanged();
+
+ const QMarginsF newPadding = d->getPadding();
+ const qreal newVerticalPadding = d->getVerticalPadding();
+ const qreal newHorizontalPadding = d->getHorizontalPadding();
+
+ if (!qFuzzyCompare(newPadding.top(), oldPadding.top()))
+ emit topPaddingChanged();
+ if (!qFuzzyCompare(newPadding.left(), oldPadding.left()))
+ emit leftPaddingChanged();
+ if (!qFuzzyCompare(newPadding.right(), oldPadding.right()))
+ emit rightPaddingChanged();
+ if (!qFuzzyCompare(newPadding.bottom(), oldPadding.bottom()))
+ emit bottomPaddingChanged();
+ if (!qFuzzyCompare(newVerticalPadding, oldVerticalPadding))
+ emit verticalPaddingChanged();
+ if (!qFuzzyCompare(newHorizontalPadding, oldHorizontalPadding))
+ emit horizontalPaddingChanged();
+ if (!qFuzzyCompare(newPadding.top(), oldPadding.top()) || !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom()))
+ emit availableHeightChanged();
+ if (!qFuzzyCompare(newPadding.left(), oldPadding.left()) || !qFuzzyCompare(newPadding.right(), oldPadding.right()))
+ emit availableWidthChanged();
+
+ paddingChange(newPadding, oldPadding);
+}
+
+void QQuickControl::resetPadding()
+{
+ setPadding(0);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::topPadding
+
+ This property holds the top padding. Unless explicitly set, the value
+ is equal to \c verticalPadding.
+
+ \sa {Control Layout}, padding, bottomPadding, verticalPadding, availableHeight
+*/
+qreal QQuickControl::topPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getTopPadding();
+}
+
+void QQuickControl::setTopPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setTopPadding(padding);
+}
+
+void QQuickControl::resetTopPadding()
+{
+ Q_D(QQuickControl);
+ d->setTopPadding(0, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::leftPadding
+
+ This property holds the left padding. Unless explicitly set, the value
+ is equal to \c horizontalPadding.
+
+ \sa {Control Layout}, padding, rightPadding, horizontalPadding, availableWidth
+*/
+qreal QQuickControl::leftPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getLeftPadding();
+}
+
+void QQuickControl::setLeftPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setLeftPadding(padding);
+}
+
+void QQuickControl::resetLeftPadding()
+{
+ Q_D(QQuickControl);
+ d->setLeftPadding(0, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::rightPadding
+
+ This property holds the right padding. Unless explicitly set, the value
+ is equal to \c horizontalPadding.
+
+ \sa {Control Layout}, padding, leftPadding, horizontalPadding, availableWidth
+*/
+qreal QQuickControl::rightPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getRightPadding();
+}
+
+void QQuickControl::setRightPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setRightPadding(padding);
+}
+
+void QQuickControl::resetRightPadding()
+{
+ Q_D(QQuickControl);
+ d->setRightPadding(0, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::bottomPadding
+
+ This property holds the bottom padding. Unless explicitly set, the value
+ is equal to \c verticalPadding.
+
+ \sa {Control Layout}, padding, topPadding, verticalPadding, availableHeight
+*/
+qreal QQuickControl::bottomPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getBottomPadding();
+}
+
+void QQuickControl::setBottomPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setBottomPadding(padding);
+}
+
+void QQuickControl::resetBottomPadding()
+{
+ Q_D(QQuickControl);
+ d->setBottomPadding(0, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Control::spacing
+
+ This property holds the spacing.
+
+ Spacing is useful for controls that have multiple or repetitive building
+ blocks. For example, some styles use spacing to determine the distance
+ between the text and indicator of \l CheckBox. Spacing is not enforced by
+ Control, so each style may interpret it differently, and some may ignore it
+ altogether.
+*/
+qreal QQuickControl::spacing() const
+{
+ Q_D(const QQuickControl);
+ return d->spacing;
+}
+
+void QQuickControl::setSpacing(qreal spacing)
+{
+ Q_D(QQuickControl);
+ if (qFuzzyCompare(d->spacing, spacing))
+ return;
+
+ qreal oldSpacing = d->spacing;
+ d->spacing = spacing;
+ emit spacingChanged();
+ spacingChange(spacing, oldSpacing);
+}
+
+void QQuickControl::resetSpacing()
+{
+ setSpacing(0);
+}
+
+/*!
+ \qmlproperty Locale QtQuick.Controls::Control::locale
+
+ This property holds the locale of the control.
+
+ It contains locale specific properties for formatting data and numbers.
+ Unless a special locale has been set, this is either the parent's locale
+ or the default locale.
+
+ Control propagates the locale from parent to children. If you change the
+ control's locale, that locale propagates to all of the control's children,
+ overriding the system default locale.
+
+ \sa mirrored
+*/
+QLocale QQuickControl::locale() const
+{
+ Q_D(const QQuickControl);
+ return d->locale;
+}
+
+void QQuickControl::setLocale(const QLocale &locale)
+{
+ Q_D(QQuickControl);
+ if (d->hasLocale && d->locale == locale)
+ return;
+
+ d->updateLocale(locale, true); // explicit=true
+}
+
+void QQuickControl::resetLocale()
+{
+ Q_D(QQuickControl);
+ if (!d->hasLocale)
+ return;
+
+ d->hasLocale = false;
+ d->updateLocale(QQuickControlPrivate::calcLocale(d->parentItem), false); // explicit=false
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Control::mirrored
+ \readonly
+
+ This property holds whether the control is mirrored.
+
+ This property is provided for convenience. A control is considered mirrored
+ when its visual layout direction is right-to-left; that is, when
+ \l {LayoutMirroring::enabled}{LayoutMirroring.enabled} is \c true.
+
+ As of Qt 6.2, the \l locale property no longer affects this property.
+
+ \sa {LayoutMirroring}{LayoutMirroring}, {Right-to-left User Interfaces}
+*/
+bool QQuickControl::isMirrored() const
+{
+ Q_D(const QQuickControl);
+ return d->isMirrored();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Control::focusPolicy
+
+ This property determines the way the control accepts focus.
+
+ \value Qt.TabFocus The control accepts focus by tabbing.
+ \value Qt.ClickFocus The control accepts focus by clicking.
+ \value Qt.StrongFocus The control accepts focus by both tabbing and clicking.
+ \value Qt.WheelFocus The control accepts focus by tabbing, clicking, and using the mouse wheel.
+ \value Qt.NoFocus The control does not accept focus.
+*/
+Qt::FocusPolicy QQuickControl::focusPolicy() const
+{
+ Q_D(const QQuickControl);
+ uint policy = d->focusPolicy;
+ if (activeFocusOnTab())
+ policy |= Qt::TabFocus;
+ return static_cast<Qt::FocusPolicy>(policy);
+}
+
+void QQuickControl::setFocusPolicy(Qt::FocusPolicy policy)
+{
+ Q_D(QQuickControl);
+ if (d->focusPolicy == policy)
+ return;
+
+ d->focusPolicy = policy;
+ setActiveFocusOnTab(policy & Qt::TabFocus);
+ emit focusPolicyChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Control::focusReason
+ \readonly
+
+ \include qquickcontrol-focusreason.qdocinc
+
+ \sa visualFocus
+*/
+Qt::FocusReason QQuickControl::focusReason() const
+{
+ Q_D(const QQuickControl);
+ return d->focusReason;
+}
+
+void QQuickControl::setFocusReason(Qt::FocusReason reason)
+{
+ Q_D(QQuickControl);
+ if (d->focusReason == reason)
+ return;
+
+ Qt::FocusReason oldReason = d->focusReason;
+ d->focusReason = reason;
+ emit focusReasonChanged();
+ if (isKeyFocusReason(oldReason) != isKeyFocusReason(reason))
+ emit visualFocusChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Control::visualFocus
+ \readonly
+
+ This property holds whether the control has visual focus. This property
+ is \c true when the control has active focus and the focus reason is either
+ \c Qt.TabFocusReason, \c Qt.BacktabFocusReason, or \c Qt.ShortcutFocusReason.
+
+ In general, for visualizing key focus, this property is preferred over
+ \l Item::activeFocus. This ensures that key focus is only visualized when
+ interacting with keys - not when interacting via touch or mouse.
+
+ \sa focusReason, Item::activeFocus
+*/
+bool QQuickControl::hasVisualFocus() const
+{
+ Q_D(const QQuickControl);
+ return d->activeFocus && isKeyFocusReason(d->focusReason);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Control::hovered
+ \readonly
+
+ This property holds whether the control is hovered.
+
+ \sa hoverEnabled
+*/
+bool QQuickControl::isHovered() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickControl);
+ return d->hovered;
+#else
+ return false;
+#endif
+}
+
+void QQuickControl::setHovered(bool hovered)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickControl);
+ if (hovered == d->hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+ hoverChange();
+#else
+ Q_UNUSED(hovered);
+#endif
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Control::hoverEnabled
+
+ This property determines whether the control accepts hover events. The default value
+ is \c Qt.styleHints.useHoverEffects.
+
+ Setting this property propagates the value to all child controls that do not have
+ \c hoverEnabled explicitly set.
+
+ You can also enable or disable hover effects for all Qt Quick Controls applications
+ by setting the \c QT_QUICK_CONTROLS_HOVER_ENABLED \l {Supported Environment Variables
+ in Qt Quick Controls}{environment variable}.
+
+ \sa hovered
+*/
+bool QQuickControl::isHoverEnabled() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickControl);
+ return d->hoverEnabled;
+#else
+ return false;
+#endif
+}
+
+void QQuickControl::setHoverEnabled(bool enabled)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickControl);
+ if (d->explicitHoverEnabled && enabled == d->hoverEnabled)
+ return;
+
+ d->updateHoverEnabled(enabled, true); // explicit=true
+#else
+ Q_UNUSED(enabled);
+#endif
+}
+
+void QQuickControl::resetHoverEnabled()
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickControl);
+ if (!d->explicitHoverEnabled)
+ return;
+
+ d->explicitHoverEnabled = false;
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Control::wheelEnabled
+
+ This property determines whether the control handles wheel events. The default value is \c false.
+
+ \note Care must be taken when enabling wheel events for controls within scrollable items such
+ as \l Flickable, as the control will consume the events and hence interrupt scrolling of the
+ Flickable.
+*/
+bool QQuickControl::isWheelEnabled() const
+{
+ Q_D(const QQuickControl);
+ return d->wheelEnabled;
+}
+
+void QQuickControl::setWheelEnabled(bool enabled)
+{
+ Q_D(QQuickControl);
+ if (d->wheelEnabled == enabled)
+ return;
+
+ d->wheelEnabled = enabled;
+ emit wheelEnabledChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Control::background
+
+ This property holds the background item.
+
+ \code
+ Button {
+ id: control
+ text: qsTr("Button")
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: enabled ? 1 : 0.3
+ color: control.down ? "#d0d0d0" : "#e0e0e0"
+ }
+ }
+ \endcode
+
+ \input qquickcontrol-background.qdocinc notes
+
+ \sa {Control Layout}
+*/
+QQuickItem *QQuickControl::background() const
+{
+ QQuickControlPrivate *d = const_cast<QQuickControlPrivate *>(d_func());
+ if (!d->background)
+ d->executeBackground();
+ return d->background;
+}
+
+void QQuickControl::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickControl);
+ if (d->background == background)
+ return;
+
+ if (!d->background.isExecuting())
+ d->cancelBackground();
+
+ const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
+ const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
+
+ if (d->extra.isAllocated()) {
+ d->extra.value().hasBackgroundWidth = false;
+ d->extra.value().hasBackgroundHeight = false;
+ }
+
+ d->removeImplicitSizeListener(d->background, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ QQuickControlPrivate::hideOldItem(d->background);
+ d->background = background;
+
+ if (background) {
+ background->setParentItem(this);
+ if (qFuzzyIsNull(background->z()))
+ background->setZ(-1);
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (p->widthValid() || p->heightValid()) {
+ d->extra.value().hasBackgroundWidth = p->widthValid();
+ d->extra.value().hasBackgroundHeight = p->heightValid();
+ }
+ if (isComponentComplete())
+ d->resizeBackground();
+ d->addImplicitSizeListener(background, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ }
+
+ if (!qFuzzyCompare(oldImplicitBackgroundWidth, implicitBackgroundWidth()))
+ emit implicitBackgroundWidthChanged();
+ if (!qFuzzyCompare(oldImplicitBackgroundHeight, implicitBackgroundHeight()))
+ emit implicitBackgroundHeightChanged();
+ if (!d->background.isExecuting())
+ emit backgroundChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Control::contentItem
+
+ This property holds the visual content item.
+
+ \code
+ Button {
+ id: control
+ text: qsTr("Button")
+ contentItem: Label {
+ text: control.text
+ font: control.font
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ \endcode
+
+ \note The content item is automatically positioned and resized to fit
+ within the \l padding of the control. Bindings to the
+ \l[QtQuick]{Item::}{x}, \l[QtQuick]{Item::}{y},
+ \l[QtQuick]{Item::}{width}, and \l[QtQuick]{Item::}{height}
+ properties of the contentItem are not respected.
+
+ \note Most controls use the implicit size of the content item to calculate
+ the implicit size of the control itself. If you replace the content item
+ with a custom one, you should also consider providing a sensible implicit
+ size for it (unless it is an item like \l Text which has its own implicit
+ size).
+
+ \sa {Control Layout}, padding
+*/
+QQuickItem *QQuickControl::contentItem() const
+{
+ QQuickControlPrivate *d = const_cast<QQuickControlPrivate *>(d_func());
+ if (!d->contentItem)
+ d->setContentItem_helper(d->getContentItem(), false);
+ return d->contentItem;
+}
+
+void QQuickControl::setContentItem(QQuickItem *item)
+{
+ Q_D(QQuickControl);
+ d->setContentItem_helper(item, true);
+}
+
+qreal QQuickControl::baselineOffset() const
+{
+ Q_D(const QQuickControl);
+ return d->baselineOffset;
+}
+
+void QQuickControl::setBaselineOffset(qreal offset)
+{
+ Q_D(QQuickControl);
+ d->extra.value().hasBaselineOffset = true;
+ QQuickItem::setBaselineOffset(offset);
+}
+
+void QQuickControl::resetBaselineOffset()
+{
+ Q_D(QQuickControl);
+ if (!d->extra.isAllocated() || !d->extra.value().hasBaselineOffset)
+ return;
+
+ if (d->extra.isAllocated())
+ d->extra.value().hasBaselineOffset = false;
+ d->updateBaselineOffset();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::horizontalPadding
+
+ This property holds the horizontal padding. Unless explicitly set, the value
+ is equal to \c padding.
+
+ \sa {Control Layout}, padding, leftPadding, rightPadding, verticalPadding
+*/
+qreal QQuickControl::horizontalPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getHorizontalPadding();
+}
+
+void QQuickControl::setHorizontalPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setHorizontalPadding(padding);
+}
+
+void QQuickControl::resetHorizontalPadding()
+{
+ Q_D(QQuickControl);
+ d->setHorizontalPadding(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::verticalPadding
+
+ This property holds the vertical padding. Unless explicitly set, the value
+ is equal to \c padding.
+
+ \sa {Control Layout}, padding, topPadding, bottomPadding, horizontalPadding
+*/
+qreal QQuickControl::verticalPadding() const
+{
+ Q_D(const QQuickControl);
+ return d->getVerticalPadding();
+}
+
+void QQuickControl::setVerticalPadding(qreal padding)
+{
+ Q_D(QQuickControl);
+ d->setVerticalPadding(padding);
+}
+
+void QQuickControl::resetVerticalPadding()
+{
+ Q_D(QQuickControl);
+ d->setVerticalPadding(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::implicitContentWidth
+ \readonly
+
+ This property holds the implicit content width.
+
+ For basic controls, the value is equal to \c {contentItem ? contentItem.implicitWidth : 0}.
+ For types that inherit Container or Pane, the value is calculated based on the content children.
+
+ This is typically used, together with \l implicitBackgroundWidth, to calculate
+ the \l {Item::}{implicitWidth}:
+
+ \code
+ Control {
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ }
+ \endcode
+
+ \sa implicitContentHeight, implicitBackgroundWidth
+*/
+qreal QQuickControl::implicitContentWidth() const
+{
+ Q_D(const QQuickControl);
+ return d->implicitContentWidth;
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::implicitContentHeight
+ \readonly
+
+ This property holds the implicit content height.
+
+ For basic controls, the value is equal to \c {contentItem ? contentItem.implicitHeight : 0}.
+ For types that inherit Container or Pane, the value is calculated based on the content children.
+
+ This is typically used, together with \l implicitBackgroundHeight, to calculate
+ the \l {Item::}{implicitHeight}:
+
+ \code
+ Control {
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ }
+ \endcode
+
+ \sa implicitContentWidth, implicitBackgroundHeight
+*/
+qreal QQuickControl::implicitContentHeight() const
+{
+ Q_D(const QQuickControl);
+ return d->implicitContentHeight;
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::implicitBackgroundWidth
+ \readonly
+
+ This property holds the implicit background width.
+
+ The value is equal to \c {background ? background.implicitWidth : 0}.
+
+ This is typically used, together with \l implicitContentWidth, to calculate
+ the \l {Item::}{implicitWidth}:
+
+ \code
+ Control {
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ }
+ \endcode
+
+ \sa implicitBackgroundHeight, implicitContentWidth
+*/
+qreal QQuickControl::implicitBackgroundWidth() const
+{
+ Q_D(const QQuickControl);
+ if (!d->background)
+ return 0;
+ return d->background->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::implicitBackgroundHeight
+ \readonly
+
+ This property holds the implicit background height.
+
+ The value is equal to \c {background ? background.implicitHeight : 0}.
+
+ This is typically used, together with \l implicitContentHeight, to calculate
+ the \l {Item::}{implicitHeight}:
+
+ \code
+ Control {
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+ }
+ \endcode
+
+ \sa implicitBackgroundWidth, implicitContentHeight
+*/
+qreal QQuickControl::implicitBackgroundHeight() const
+{
+ Q_D(const QQuickControl);
+ if (!d->background)
+ return 0;
+ return d->background->implicitHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::topInset
+
+ This property holds the top inset for the background.
+
+ \sa {Control Layout}, bottomInset
+*/
+qreal QQuickControl::topInset() const
+{
+ Q_D(const QQuickControl);
+ return d->getTopInset();
+}
+
+void QQuickControl::setTopInset(qreal inset)
+{
+ Q_D(QQuickControl);
+ d->setTopInset(inset);
+}
+
+void QQuickControl::resetTopInset()
+{
+ Q_D(QQuickControl);
+ d->setTopInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::leftInset
+
+ This property holds the left inset for the background.
+
+ \sa {Control Layout}, rightInset
+*/
+qreal QQuickControl::leftInset() const
+{
+ Q_D(const QQuickControl);
+ return d->getLeftInset();
+}
+
+void QQuickControl::setLeftInset(qreal inset)
+{
+ Q_D(QQuickControl);
+ d->setLeftInset(inset);
+}
+
+void QQuickControl::resetLeftInset()
+{
+ Q_D(QQuickControl);
+ d->setLeftInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::rightInset
+
+ This property holds the right inset for the background.
+
+ \sa {Control Layout}, leftInset
+*/
+qreal QQuickControl::rightInset() const
+{
+ Q_D(const QQuickControl);
+ return d->getRightInset();
+}
+
+void QQuickControl::setRightInset(qreal inset)
+{
+ Q_D(QQuickControl);
+ d->setRightInset(inset);
+}
+
+void QQuickControl::resetRightInset()
+{
+ Q_D(QQuickControl);
+ d->setRightInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Control::bottomInset
+
+ This property holds the bottom inset for the background.
+
+ \sa {Control Layout}, topInset
+*/
+qreal QQuickControl::bottomInset() const
+{
+ Q_D(const QQuickControl);
+ return d->getBottomInset();
+}
+
+void QQuickControl::setBottomInset(qreal inset)
+{
+ Q_D(QQuickControl);
+ d->setBottomInset(inset);
+}
+
+void QQuickControl::resetBottomInset()
+{
+ Q_D(QQuickControl);
+ d->setBottomInset(0, true);
+}
+
+void QQuickControl::classBegin()
+{
+ Q_D(QQuickControl);
+ QQuickItem::classBegin();
+ d->resolveFont();
+}
+
+void QQuickControl::componentComplete()
+{
+ Q_D(QQuickControl);
+ d->executeBackground(true);
+ d->executeContentItem(true);
+ QQuickItem::componentComplete();
+ d->resizeBackground();
+ d->resizeContent();
+ d->updateBaselineOffset();
+ if (!d->hasLocale)
+ d->locale = QQuickControlPrivate::calcLocale(d->parentItem);
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ setAcceptHoverEvents(QQuickControlPrivate::calcHoverEnabled(d->parentItem));
+#endif
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ accessibilityActiveChanged(true);
+#endif
+}
+
+QFont QQuickControl::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::System);
+}
+
+void QQuickControl::focusInEvent(QFocusEvent *event)
+{
+ QQuickItem::focusInEvent(event);
+ setFocusReason(event->reason());
+}
+
+void QQuickControl::focusOutEvent(QFocusEvent *event)
+{
+ QQuickItem::focusOutEvent(event);
+ setFocusReason(event->reason());
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickControl::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickControl);
+ setHovered(d->hoverEnabled);
+ event->ignore();
+}
+
+void QQuickControl::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickControl);
+ setHovered(d->hoverEnabled && contains(event->position()));
+ event->ignore();
+}
+
+void QQuickControl::hoverLeaveEvent(QHoverEvent *event)
+{
+ setHovered(false);
+ event->ignore();
+}
+#endif
+
+void QQuickControl::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickControl);
+ d->handlePress(event->position());
+ if (event->source() == Qt::MouseEventSynthesizedByQt) {
+ d->pressWasTouch = true;
+ d->previousPressPos = event->position();
+ }
+ event->accept();
+}
+
+void QQuickControl::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickControl);
+ d->handleMove(event->position());
+ event->accept();
+}
+
+void QQuickControl::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickControl);
+ d->handleRelease(event->position());
+ event->accept();
+}
+
+void QQuickControl::mouseUngrabEvent()
+{
+ Q_D(QQuickControl);
+ d->handleUngrab();
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickControl::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickControl);
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (!d->acceptTouch(point))
+ continue;
+
+ switch (point.state()) {
+ case QEventPoint::Pressed:
+ d->handlePress(point.position());
+ break;
+ case QEventPoint::Updated:
+ d->handleMove(point.position());
+ break;
+ case QEventPoint::Released:
+ d->handleRelease(point.position());
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case QEvent::TouchCancel:
+ d->handleUngrab();
+ break;
+
+ default:
+ QQuickItem::touchEvent(event);
+ break;
+ }
+}
+
+void QQuickControl::touchUngrabEvent()
+{
+ Q_D(QQuickControl);
+ d->handleUngrab();
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickControl::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickControl);
+ if ((d->focusPolicy & Qt::WheelFocus) == Qt::WheelFocus)
+ setActiveFocus(this, Qt::MouseFocusReason);
+
+ event->setAccepted(d->wheelEnabled);
+}
+#endif
+
+void QQuickControl::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickControl);
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ d->resizeBackground();
+ d->resizeContent();
+ if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width()))
+ emit availableWidthChanged();
+ if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height()))
+ emit availableHeightChanged();
+}
+
+void QQuickControl::enabledChange()
+{
+}
+
+void QQuickControl::fontChange(const QFont &newFont, const QFont &oldFont)
+{
+ Q_UNUSED(newFont);
+ Q_UNUSED(oldFont);
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickControl::hoverChange()
+{
+}
+#endif
+
+void QQuickControl::mirrorChange()
+{
+ emit mirroredChanged();
+}
+
+void QQuickControl::spacingChange(qreal newSpacing, qreal oldSpacing)
+{
+ Q_UNUSED(newSpacing);
+ Q_UNUSED(oldSpacing);
+}
+
+void QQuickControl::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
+{
+ Q_D(QQuickControl);
+ Q_UNUSED(newPadding);
+ Q_UNUSED(oldPadding);
+ d->resizeContent();
+ d->updateBaselineOffset();
+}
+
+void QQuickControl::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_UNUSED(newItem);
+ Q_UNUSED(oldItem);
+}
+
+void QQuickControl::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
+{
+ Q_UNUSED(newLocale);
+ Q_UNUSED(oldLocale);
+}
+
+void QQuickControl::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
+{
+ Q_D(QQuickControl);
+ Q_UNUSED(newInset);
+ Q_UNUSED(oldInset);
+ d->resizeBackground();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickControl::accessibleRole() const
+{
+ return QAccessible::NoRole;
+}
+
+void QQuickControl::accessibilityActiveChanged(bool active)
+{
+ if (!active)
+ return;
+
+ QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(this, true));
+ Q_ASSERT(accessibleAttached);
+ accessibleAttached->setRole(accessibleRole());
+}
+#endif
+
+QString QQuickControl::accessibleName() const
+{
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this))
+ return accessibleAttached->name();
+#endif
+ return QString();
+}
+
+void QQuickControl::maybeSetAccessibleName(const QString &name)
+{
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this)) {
+ if (!accessibleAttached->wasNameExplicitlySet())
+ accessibleAttached->setNameImplicitly(name);
+ }
+#else
+ Q_UNUSED(name);
+#endif
+}
+
+QVariant QQuickControl::accessibleProperty(const char *propertyName)
+{
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ return QQuickAccessibleAttached::property(this, propertyName);
+#endif
+ Q_UNUSED(propertyName);
+ return QVariant();
+}
+
+bool QQuickControl::setAccessibleProperty(const char *propertyName, const QVariant &value)
+{
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ return QQuickAccessibleAttached::setProperty(this, propertyName, value);
+#endif
+ Q_UNUSED(propertyName);
+ Q_UNUSED(value);
+ return false;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickcontrol_p.cpp"
diff --git a/src/quicktemplates2/qquickcontrol_p.h b/src/quicktemplates2/qquickcontrol_p.h
new file mode 100644
index 0000000000..79fb3915b0
--- /dev/null
+++ b/src/quicktemplates2/qquickcontrol_p.h
@@ -0,0 +1,320 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCONTROL_P_H
+#define QQUICKCONTROL_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/qlocale.h>
+#include <QtGui/qpalette.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickpalette_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickControlPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickControl : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL)
+ Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL)
+ Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL)
+ Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL)
+ Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL)
+ Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL)
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing RESET resetSpacing NOTIFY spacingChanged FINAL)
+ Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL)
+ Q_PROPERTY(bool mirrored READ isMirrored NOTIFY mirroredChanged FINAL)
+ Q_PROPERTY(Qt::FocusPolicy focusPolicy READ focusPolicy WRITE setFocusPolicy NOTIFY focusPolicyChanged FINAL)
+ Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL)
+ Q_PROPERTY(bool visualFocus READ hasVisualFocus NOTIFY visualFocusChanged FINAL)
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL)
+ Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled RESET resetHoverEnabled NOTIFY hoverEnabledChanged FINAL)
+ Q_PROPERTY(bool wheelEnabled READ isWheelEnabled WRITE setWheelEnabled NOTIFY wheelEnabledChanged FINAL)
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL)
+ Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset RESET resetBaselineOffset NOTIFY baselineOffsetChanged FINAL)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal horizontalPadding READ horizontalPadding WRITE setHorizontalPadding RESET resetHorizontalPadding NOTIFY horizontalPaddingChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal verticalPadding READ verticalPadding WRITE setVerticalPadding RESET resetVerticalPadding NOTIFY verticalPaddingChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitContentWidth READ implicitContentWidth NOTIFY implicitContentWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitContentHeight READ implicitContentHeight NOTIFY implicitContentHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundWidth READ implicitBackgroundWidth NOTIFY implicitBackgroundWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundHeight READ implicitBackgroundHeight NOTIFY implicitBackgroundHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal topInset READ topInset WRITE setTopInset RESET resetTopInset NOTIFY topInsetChanged FINAL REVISION(2, 5))
+ 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_CLASSINFO("DeferredPropertyNames", "background,contentItem")
+ QML_NAMED_ELEMENT(Control)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickControl(QQuickItem *parent = nullptr);
+ ~QQuickControl();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+ void resetFont();
+
+ qreal availableWidth() const;
+ qreal availableHeight() const;
+
+ qreal padding() const;
+ void setPadding(qreal padding);
+ void resetPadding();
+
+ qreal topPadding() const;
+ void setTopPadding(qreal padding);
+ void resetTopPadding();
+
+ qreal leftPadding() const;
+ void setLeftPadding(qreal padding);
+ void resetLeftPadding();
+
+ qreal rightPadding() const;
+ void setRightPadding(qreal padding);
+ void resetRightPadding();
+
+ qreal bottomPadding() const;
+ void setBottomPadding(qreal padding);
+ void resetBottomPadding();
+
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+ void resetSpacing();
+
+ QLocale locale() const;
+ void setLocale(const QLocale &locale);
+ void resetLocale();
+
+ bool isMirrored() const;
+
+ Qt::FocusPolicy focusPolicy() const;
+ void setFocusPolicy(Qt::FocusPolicy policy);
+
+ Qt::FocusReason focusReason() const;
+ void setFocusReason(Qt::FocusReason reason);
+
+ bool hasVisualFocus() const;
+
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ bool isHoverEnabled() const;
+ void setHoverEnabled(bool enabled);
+ void resetHoverEnabled();
+
+ bool isWheelEnabled() const;
+ void setWheelEnabled(bool enabled);
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ QQuickItem *contentItem() const;
+ void setContentItem(QQuickItem *item);
+
+ qreal baselineOffset() const;
+ void setBaselineOffset(qreal offset);
+ void resetBaselineOffset();
+
+ // 2.5 (Qt 5.12)
+ qreal horizontalPadding() const;
+ void setHorizontalPadding(qreal padding);
+ void resetHorizontalPadding();
+
+ qreal verticalPadding() const;
+ void setVerticalPadding(qreal padding);
+ void resetVerticalPadding();
+
+ qreal implicitContentWidth() const;
+ qreal implicitContentHeight() const;
+
+ qreal implicitBackgroundWidth() const;
+ qreal implicitBackgroundHeight() const;
+
+ qreal topInset() const;
+ void setTopInset(qreal inset);
+ void resetTopInset();
+
+ qreal leftInset() const;
+ void setLeftInset(qreal inset);
+ void resetLeftInset();
+
+ qreal rightInset() const;
+ void setRightInset(qreal inset);
+ void resetRightInset();
+
+ qreal bottomInset() const;
+ void setBottomInset(qreal inset);
+ void resetBottomInset();
+
+Q_SIGNALS:
+ void fontChanged();
+ void availableWidthChanged();
+ void availableHeightChanged();
+ void paddingChanged();
+ void topPaddingChanged();
+ void leftPaddingChanged();
+ void rightPaddingChanged();
+ void bottomPaddingChanged();
+ void spacingChanged();
+ void localeChanged();
+ void mirroredChanged();
+ void focusPolicyChanged();
+ void focusReasonChanged();
+ void visualFocusChanged();
+ void hoveredChanged();
+ void hoverEnabledChanged();
+ void wheelEnabledChanged();
+ void backgroundChanged();
+ void contentItemChanged();
+ void baselineOffsetChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void horizontalPaddingChanged();
+ Q_REVISION(2, 5) void verticalPaddingChanged();
+ Q_REVISION(2, 5) void implicitContentWidthChanged();
+ Q_REVISION(2, 5) void implicitContentHeightChanged();
+ Q_REVISION(2, 5) void implicitBackgroundWidthChanged();
+ Q_REVISION(2, 5) void implicitBackgroundHeightChanged();
+ Q_REVISION(2, 5) void topInsetChanged();
+ Q_REVISION(2, 5) void leftInsetChanged();
+ Q_REVISION(2, 5) void rightInsetChanged();
+ Q_REVISION(2, 5) void bottomInsetChanged();
+
+protected:
+ virtual QFont defaultFont() const;
+
+ QQuickControl(QQuickControlPrivate &dd, QQuickItem *parent);
+
+ void classBegin() override;
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+#if QT_CONFIG(quicktemplates2_hover)
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+#endif
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseUngrabEvent() override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+ void touchUngrabEvent() override;
+#endif
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ virtual void fontChange(const QFont &newFont, const QFont &oldFont);
+#if QT_CONFIG(quicktemplates2_hover)
+ virtual void hoverChange();
+#endif
+ virtual void mirrorChange();
+ virtual void spacingChange(qreal newSpacing, qreal oldSpacing);
+ virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding);
+ virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem);
+ virtual void localeChange(const QLocale &newLocale, const QLocale &oldLocale);
+ virtual void insetChange(const QMarginsF &newInset, const QMarginsF &oldInset);
+ virtual void enabledChange();
+
+#if QT_CONFIG(accessibility)
+ virtual QAccessible::Role accessibleRole() const;
+ virtual void accessibilityActiveChanged(bool active);
+#endif
+
+ // helper functions which avoid to check QT_CONFIG(accessibility)
+ QString accessibleName() const;
+ void maybeSetAccessibleName(const QString &name);
+
+ QVariant accessibleProperty(const char *propertyName);
+ bool setAccessibleProperty(const char *propertyName, const QVariant &value);
+
+private:
+ Q_DISABLE_COPY(QQuickControl)
+ Q_DECLARE_PRIVATE(QQuickControl)
+};
+
+struct QQuickItemForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickItem)
+ QML_ADDED_IN_VERSION(2, 3)
+};
+
+struct QQuickColorGroupForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickColorGroup)
+ QML_ADDED_IN_VERSION(6, 0)
+};
+
+struct QQuickPaletteForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickPalette)
+ QML_ADDED_IN_VERSION(6, 0)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickControl)
+
+#endif // QQUICKCONTROL_P_H
diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h
new file mode 100644
index 0000000000..aa187dbbd6
--- /dev/null
+++ b/src/quicktemplates2/qquickcontrol_p_p.h
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKCONTROL_P_P_H
+#define QQUICKCONTROL_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickdeferredpointer_p_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQml/private/qlazilyallocated_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcItemManagement)
+
+class QQuickAccessibleAttached;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickControlPrivate : public QQuickItemPrivate, public QQuickItemChangeListener
+#if QT_CONFIG(accessibility)
+ , public QAccessible::ActivationObserver
+#endif
+{
+ Q_DECLARE_PUBLIC(QQuickControl)
+
+public:
+ QQuickControlPrivate();
+ ~QQuickControlPrivate();
+
+ static QQuickControlPrivate *get(QQuickControl *control)
+ {
+ return control->d_func();
+ }
+
+ void init();
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ virtual bool acceptTouch(const QTouchEvent::TouchPoint &point);
+#endif
+ virtual void handlePress(const QPointF &point);
+ virtual void handleMove(const QPointF &point);
+ virtual void handleRelease(const QPointF &point);
+ virtual void handleUngrab();
+
+ void mirrorChange() override;
+
+ inline QMarginsF getPadding() const { return QMarginsF(getLeftPadding(), getTopPadding(), getRightPadding(), getBottomPadding()); }
+ inline qreal getTopPadding() const { return extra.isAllocated() && extra->hasTopPadding ? extra->topPadding : getVerticalPadding(); }
+ inline qreal getLeftPadding() const { return extra.isAllocated() && extra->hasLeftPadding ? extra->leftPadding : getHorizontalPadding(); }
+ inline qreal getRightPadding() const { return extra.isAllocated() && extra->hasRightPadding ? extra->rightPadding : getHorizontalPadding(); }
+ inline qreal getBottomPadding() const { return extra.isAllocated() && extra->hasBottomPadding ? extra->bottomPadding : getVerticalPadding(); }
+ inline qreal getHorizontalPadding() const { return hasHorizontalPadding ? horizontalPadding : padding; }
+ inline qreal getVerticalPadding() const { return hasVerticalPadding ? verticalPadding : padding; }
+
+ void setTopPadding(qreal value, bool reset = false);
+ void setLeftPadding(qreal value, bool reset = false);
+ void setRightPadding(qreal value, bool reset = false);
+ void setBottomPadding(qreal value, bool reset = false);
+ void setHorizontalPadding(qreal value, bool reset = false);
+ void setVerticalPadding(qreal value, bool reset = false);
+
+ inline QMarginsF getInset() const { return QMarginsF(getLeftInset(), getTopInset(), getRightInset(), getBottomInset()); }
+ inline qreal getTopInset() const { return extra.isAllocated() ? extra->topInset : 0; }
+ inline qreal getLeftInset() const { return extra.isAllocated() ? extra->leftInset : 0; }
+ inline qreal getRightInset() const { return extra.isAllocated() ? extra->rightInset : 0; }
+ inline qreal getBottomInset() const { return extra.isAllocated() ? extra->bottomInset : 0; }
+
+ void setTopInset(qreal value, bool reset = false);
+ void setLeftInset(qreal value, bool reset = false);
+ void setRightInset(qreal value, bool reset = false);
+ void setBottomInset(qreal value, bool reset = false);
+
+ virtual void resizeBackground();
+ virtual void resizeContent();
+
+ virtual QQuickItem *getContentItem();
+ void setContentItem_helper(QQuickItem *item, bool notify = true);
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+ static QQuickAccessibleAttached *accessibleAttached(const QObject *object);
+#endif
+
+ virtual void resolveFont();
+ void inheritFont(const QFont &font);
+ void updateFont(const QFont &font);
+ static void updateFontRecur(QQuickItem *item, const QFont &font);
+ inline void setFont_helper(const QFont &font) {
+ if (resolvedFont.resolveMask() == font.resolveMask() && resolvedFont == font)
+ return;
+ updateFont(font);
+ }
+ static QFont parentFont(const QQuickItem *item);
+
+ void updateLocale(const QLocale &l, bool e);
+ static void updateLocaleRecur(QQuickItem *item, const QLocale &l);
+ static QLocale calcLocale(const QQuickItem *item);
+
+#if QT_CONFIG(quicktemplates2_hover)
+ void updateHoverEnabled(bool enabled, bool xplicit);
+ static void updateHoverEnabledRecur(QQuickItem *item, bool enabled);
+ static bool calcHoverEnabled(const QQuickItem *item);
+#endif
+
+ virtual void cancelContentItem();
+ virtual void executeContentItem(bool complete = false);
+
+ virtual void cancelBackground();
+ virtual void executeBackground(bool complete = false);
+
+ static void hideOldItem(QQuickItem *item);
+ static void unhideOldItem(QQuickControl *control, QQuickItem *item);
+
+ void updateBaselineOffset();
+
+ static const ChangeTypes ImplicitSizeChanges;
+
+ void addImplicitSizeListener(QQuickItem *item, ChangeTypes changes = ImplicitSizeChanges);
+ void removeImplicitSizeListener(QQuickItem *item, ChangeTypes changes = ImplicitSizeChanges);
+
+ static void addImplicitSizeListener(QQuickItem *item, QQuickItemChangeListener *listener, ChangeTypes changes = ImplicitSizeChanges);
+ static void removeImplicitSizeListener(QQuickItem *item, QQuickItemChangeListener *listener, ChangeTypes changes = ImplicitSizeChanges);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemDestroyed(QQuickItem *item) override;
+ void itemFocusChanged(QQuickItem *item, Qt::FocusReason reason) override;
+
+ virtual qreal getContentWidth() const;
+ virtual qreal getContentHeight() const;
+
+ void updateImplicitContentWidth();
+ void updateImplicitContentHeight();
+ void updateImplicitContentSize();
+
+ QPalette defaultPalette() const override;
+
+ struct ExtraData {
+ bool hasTopPadding = false;
+ bool hasLeftPadding = false;
+ bool hasRightPadding = false;
+ bool hasBottomPadding = false;
+ bool hasBaselineOffset = false;
+ bool hasTopInset = false;
+ bool hasLeftInset = false;
+ bool hasRightInset = false;
+ bool hasBottomInset = false;
+ bool hasBackgroundWidth = false;
+ bool hasBackgroundHeight = false;
+ qreal topPadding = 0;
+ qreal leftPadding = 0;
+ qreal rightPadding = 0;
+ qreal bottomPadding = 0;
+ qreal topInset = 0;
+ qreal leftInset = 0;
+ qreal rightInset = 0;
+ qreal bottomInset = 0;
+ QFont requestedFont;
+ };
+ QLazilyAllocated<ExtraData> extra;
+
+ bool hasHorizontalPadding = false;
+ bool hasVerticalPadding = false;
+ bool hasLocale = false;
+ bool wheelEnabled = false;
+#if QT_CONFIG(quicktemplates2_hover)
+ bool hovered = false;
+ bool explicitHoverEnabled = false;
+#endif
+ bool resizingBackground = false;
+ bool pressWasTouch = false;
+ int touchId = -1;
+ QPointF previousPressPos;
+ qreal padding = 0;
+ qreal horizontalPadding = 0;
+ qreal verticalPadding = 0;
+ qreal implicitContentWidth = 0;
+ qreal implicitContentHeight = 0;
+ qreal spacing = 0;
+ QLocale locale;
+ QFont resolvedFont;
+ Qt::FocusPolicy focusPolicy = Qt::NoFocus;
+ Qt::FocusReason focusReason = Qt::OtherFocusReason;
+ QQuickDeferredPointer<QQuickItem> background;
+ QQuickDeferredPointer<QQuickItem> contentItem;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKCONTROL_P_P_H
diff --git a/src/quicktemplates2/qquickdeferredexecute.cpp b/src/quicktemplates2/qquickdeferredexecute.cpp
new file mode 100644
index 0000000000..817415c492
--- /dev/null
+++ b/src/quicktemplates2/qquickdeferredexecute.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtCore/qhash.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/private/qqmldata_p.h>
+#include <QtQml/private/qqmlcomponent_p.h>
+#include <QtQml/private/qqmlobjectcreator_p.h>
+
+#include <deque>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtQuickPrivate {
+
+typedef QHash<size_t, QQmlComponentPrivate::DeferredState *> DeferredStates;
+
+static inline size_t qHash(QObject *object, const QString &propertyName)
+{
+ return ::qHash(object) + ::qHash(propertyName);
+}
+
+Q_GLOBAL_STATIC(DeferredStates, deferredStates)
+
+static void cancelDeferred(QQmlData *ddata, int propertyIndex)
+{
+ auto dit = ddata->deferredData.rbegin();
+ while (dit != ddata->deferredData.rend()) {
+ (*dit)->bindings.remove(propertyIndex);
+ ++dit;
+ }
+}
+
+static bool beginDeferred(QQmlEnginePrivate *enginePriv, const QQmlProperty &property, QQmlComponentPrivate::DeferredState *deferredState)
+{
+ QObject *object = property.object();
+ QQmlData *ddata = QQmlData::get(object);
+ Q_ASSERT(!ddata->deferredData.isEmpty());
+
+ int propertyIndex = property.index();
+ int wasInProgress = enginePriv->inProgressCreations;
+
+ for (auto dit = ddata->deferredData.rbegin(); dit != ddata->deferredData.rend(); ++dit) {
+ QQmlData::DeferredData *deferData = *dit;
+
+ auto bindings = deferData->bindings;
+ auto range = bindings.equal_range(propertyIndex);
+ if (range.first == bindings.end())
+ continue;
+
+ QQmlComponentPrivate::ConstructionState *state = new QQmlComponentPrivate::ConstructionState;
+ state->completePending = true;
+
+ QQmlContextData *creationContext = nullptr;
+ state->creator.reset(new QQmlObjectCreator(deferData->context->parent(), deferData->compilationUnit, creationContext));
+
+ enginePriv->inProgressCreations++;
+
+ std::deque<const QV4::CompiledData::Binding *> reversedBindings;
+ std::copy(range.first, range.second, std::front_inserter(reversedBindings));
+ state->creator->beginPopulateDeferred(deferData->context);
+ for (const QV4::CompiledData::Binding *binding : reversedBindings)
+ state->creator->populateDeferredBinding(property, deferData->deferredIdx, binding);
+ state->creator->finalizePopulateDeferred();
+ state->errors << state->creator->errors;
+
+ deferredState->constructionStates += state;
+
+ // Cleanup any remaining deferred bindings for this property, also in inner contexts,
+ // to avoid executing them later and overriding the property that was just populated.
+ cancelDeferred(ddata, propertyIndex);
+ break;
+ }
+
+ return enginePriv->inProgressCreations > wasInProgress;
+}
+
+void beginDeferred(QObject *object, const QString &property)
+{
+ QQmlData *data = QQmlData::get(object);
+ if (data && !data->deferredData.isEmpty() && !data->wasDeleted(object) && data->context) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+
+ QQmlComponentPrivate::DeferredState *state = new QQmlComponentPrivate::DeferredState;
+ if (beginDeferred(ep, QQmlProperty(object, property), state))
+ deferredStates()->insert(qHash(object, property), state);
+ else
+ delete state;
+
+ // Release deferred data for those compilation units that no longer have deferred bindings
+ data->releaseDeferredData();
+ }
+}
+
+void cancelDeferred(QObject *object, const QString &property)
+{
+ QQmlData *data = QQmlData::get(object);
+ if (data)
+ cancelDeferred(data, QQmlProperty(object, property).index());
+}
+
+void completeDeferred(QObject *object, const QString &property)
+{
+ QQmlData *data = QQmlData::get(object);
+ QQmlComponentPrivate::DeferredState *state = deferredStates()->take(qHash(object, property));
+ if (data && state && !data->wasDeleted(object)) {
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(data->context->engine());
+ QQmlComponentPrivate::completeDeferred(ep, state);
+ }
+ delete state;
+}
+
+} // QtQuickPrivate
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickdeferredexecute_p_p.h b/src/quicktemplates2/qquickdeferredexecute_p_p.h
new file mode 100644
index 0000000000..55750a6a06
--- /dev/null
+++ b/src/quicktemplates2/qquickdeferredexecute_p_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDEFERREDEXECUTE_P_P_H
+#define QQUICKDEFERREDEXECUTE_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 <QtCore/qglobal.h>
+#include <QtQuickTemplates2/private/qquickdeferredpointer_p_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+#include <QtQml/private/qqmlvme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QString;
+class QObject;
+
+namespace QtQuickPrivate {
+ Q_QUICKTEMPLATES2_PRIVATE_EXPORT void beginDeferred(QObject *object, const QString &property);
+ Q_QUICKTEMPLATES2_PRIVATE_EXPORT void cancelDeferred(QObject *object, const QString &property);
+ Q_QUICKTEMPLATES2_PRIVATE_EXPORT void completeDeferred(QObject *object, const QString &property);
+}
+
+template<typename T>
+void quickBeginDeferred(QObject *object, const QString &property, QQuickDeferredPointer<T> &delegate)
+{
+ if (!QQmlVME::componentCompleteEnabled())
+ return;
+
+ delegate.setExecuting(true);
+ QtQuickPrivate::beginDeferred(object, property);
+ delegate.setExecuting(false);
+}
+
+inline void quickCancelDeferred(QObject *object, const QString &property)
+{
+ QtQuickPrivate::cancelDeferred(object, property);
+}
+
+template<typename T>
+void quickCompleteDeferred(QObject *object, const QString &property, QQuickDeferredPointer<T> &delegate)
+{
+ Q_ASSERT(!delegate.wasExecuted());
+ QtQuickPrivate::completeDeferred(object, property);
+ delegate.setExecuted();
+}
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDEFERREDEXECUTE_P_P_H
diff --git a/src/quicktemplates2/qquickdeferredpointer_p_p.h b/src/quicktemplates2/qquickdeferredpointer_p_p.h
new file mode 100644
index 0000000000..f70b5dc647
--- /dev/null
+++ b/src/quicktemplates2/qquickdeferredpointer_p_p.h
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDEFERREDPOINTER_P_P_H
+#define QQUICKDEFERREDPOINTER_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 <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+template<typename T>
+class QQuickDeferredPointer
+{
+public:
+ inline QQuickDeferredPointer();
+ inline QQuickDeferredPointer(T *);
+ inline QQuickDeferredPointer(const QQuickDeferredPointer<T> &o);
+
+ inline bool isNull() const;
+
+ inline bool wasExecuted() const;
+ inline void setExecuted();
+
+ inline bool isExecuting() const;
+ inline void setExecuting(bool);
+
+ inline operator T*() const;
+ inline operator bool() const;
+
+ inline T *data() const;
+ inline T *operator*() const;
+ inline T *operator->() const;
+
+ inline QQuickDeferredPointer<T> &operator=(T *);
+ inline QQuickDeferredPointer<T> &operator=(const QQuickDeferredPointer &o);
+
+private:
+ quintptr ptr_value = 0;
+
+ static const quintptr WasExecutedBit = 0x1;
+ static const quintptr IsExecutingBit = 0x2;
+ static const quintptr FlagsMask = WasExecutedBit | IsExecutingBit;
+};
+
+template<typename T>
+QQuickDeferredPointer<T>::QQuickDeferredPointer()
+{
+}
+
+template<typename T>
+QQuickDeferredPointer<T>::QQuickDeferredPointer(T *v)
+: ptr_value(quintptr(v))
+{
+ Q_ASSERT((ptr_value & FlagsMask) == 0);
+}
+
+template<typename T>
+QQuickDeferredPointer<T>::QQuickDeferredPointer(const QQuickDeferredPointer<T> &o)
+: ptr_value(o.ptr_value)
+{
+}
+
+template<typename T>
+bool QQuickDeferredPointer<T>::isNull() const
+{
+ return 0 == (ptr_value & (~FlagsMask));
+}
+
+template<typename T>
+bool QQuickDeferredPointer<T>::wasExecuted() const
+{
+ return ptr_value & WasExecutedBit;
+}
+
+template<typename T>
+void QQuickDeferredPointer<T>::setExecuted()
+{
+ ptr_value |= WasExecutedBit;
+}
+
+template<typename T>
+bool QQuickDeferredPointer<T>::isExecuting() const
+{
+ return ptr_value & IsExecutingBit;
+}
+
+template<typename T>
+void QQuickDeferredPointer<T>::setExecuting(bool b)
+{
+ if (b)
+ ptr_value |= IsExecutingBit;
+ else
+ ptr_value &= ~IsExecutingBit;
+}
+
+template<typename T>
+QQuickDeferredPointer<T>::operator T*() const
+{
+ return data();
+}
+
+template<typename T>
+QQuickDeferredPointer<T>::operator bool() const
+{
+ return !isNull();
+}
+
+template<typename T>
+T *QQuickDeferredPointer<T>::data() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+T *QQuickDeferredPointer<T>::operator*() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+T *QQuickDeferredPointer<T>::operator->() const
+{
+ return (T *)(ptr_value & ~FlagsMask);
+}
+
+template<typename T>
+QQuickDeferredPointer<T> &QQuickDeferredPointer<T>::operator=(T *o)
+{
+ Q_ASSERT((quintptr(o) & FlagsMask) == 0);
+
+ ptr_value = quintptr(o) | (ptr_value & FlagsMask);
+ return *this;
+}
+
+template<typename T>
+QQuickDeferredPointer<T> &QQuickDeferredPointer<T>::operator=(const QQuickDeferredPointer &o)
+{
+ ptr_value = o.ptr_value;
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDEFERREDPOINTER_P_P_H
diff --git a/src/quicktemplates2/qquickdelaybutton.cpp b/src/quicktemplates2/qquickdelaybutton.cpp
new file mode 100644
index 0000000000..25e12263f4
--- /dev/null
+++ b/src/quicktemplates2/qquickdelaybutton.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdelaybutton_p.h"
+#include "qquickabstractbutton_p_p.h"
+
+#include <QtQuick/private/qquickanimation_p.h>
+#include <QtQuick/private/qquicktransition_p.h>
+#include <QtQuick/private/qquicktransitionmanager_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype DelayButton
+ \inherits AbstractButton
+//! \instantiates QQuickDelayButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.9
+ \ingroup qtquickcontrols2-buttons
+ \brief Check button that triggers when held down long enough.
+
+ \image qtquickcontrols2-delaybutton.gif
+
+ DelayButton is a checkable button that incorporates a delay before the
+ button becomes \l {AbstractButton::}{checked} and the \l activated()
+ signal is emitted. This delay prevents accidental presses.
+
+ The current progress is expressed as a decimal value between \c 0.0
+ and \c 1.0. The time it takes for \l activated() to be emitted is
+ measured in milliseconds, and can be set with the \l delay property.
+
+ The progress is indicated by a progress indicator on the button.
+
+ \sa {Customizing DelayButton}, {Button Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DelayButton::activated()
+
+ This signal is emitted when \l progress reaches \c 1.0.
+*/
+
+class QQuickDelayTransitionManager;
+
+class QQuickDelayButtonPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDelayButton)
+
+public:
+ void beginTransition(qreal to);
+ void finishTransition();
+ void cancelTransition();
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::Button); }
+
+ int delay = 300;
+ qreal progress = 0.0;
+ QQuickTransition *transition = nullptr;
+ QScopedPointer<QQuickDelayTransitionManager> transitionManager;
+};
+
+class QQuickDelayTransitionManager : public QQuickTransitionManager
+{
+public:
+ QQuickDelayTransitionManager(QQuickDelayButton *button) : m_button(button) { }
+
+ void transition(QQuickTransition *transition, qreal progress);
+
+protected:
+ void finished() override;
+
+private:
+ QQuickDelayButton *m_button = nullptr;
+};
+
+void QQuickDelayTransitionManager::transition(QQuickTransition *transition, qreal progress)
+{
+ qmlExecuteDeferred(transition);
+
+ QQmlProperty defaultTarget(m_button, QLatin1String("progress"));
+ QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
+ const int count = animations.count(&animations);
+ for (int i = 0; i < count; ++i) {
+ QQuickAbstractAnimation *anim = animations.at(&animations, i);
+ anim->setDefaultTarget(defaultTarget);
+ }
+
+ QList<QQuickStateAction> actions;
+ actions << QQuickStateAction(m_button, QLatin1String("progress"), progress);
+ QQuickTransitionManager::transition(actions, transition, m_button);
+}
+
+void QQuickDelayTransitionManager::finished()
+{
+ if (qFuzzyCompare(m_button->progress(), qreal(1.0)))
+ emit m_button->activated();
+}
+
+void QQuickDelayButtonPrivate::beginTransition(qreal to)
+{
+ Q_Q(QQuickDelayButton);
+ if (!transition) {
+ q->setProgress(to);
+ finishTransition();
+ return;
+ }
+
+ if (!transitionManager)
+ transitionManager.reset(new QQuickDelayTransitionManager(q));
+
+ transitionManager->transition(transition, to);
+}
+
+void QQuickDelayButtonPrivate::finishTransition()
+{
+ Q_Q(QQuickDelayButton);
+ if (qFuzzyCompare(progress, qreal(1.0)))
+ emit q->activated();
+}
+
+void QQuickDelayButtonPrivate::cancelTransition()
+{
+ if (transitionManager)
+ transitionManager->cancel();
+}
+
+QQuickDelayButton::QQuickDelayButton(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickDelayButtonPrivate), parent)
+{
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::DelayButton::delay
+
+ This property holds the time it takes (in milliseconds) for \l progress
+ to reach \c 1.0 and emit \l activated().
+
+ The default value is \c 3000 ms.
+*/
+int QQuickDelayButton::delay() const
+{
+ Q_D(const QQuickDelayButton);
+ return d->delay;
+}
+
+void QQuickDelayButton::setDelay(int delay)
+{
+ Q_D(QQuickDelayButton);
+ if (d->delay == delay)
+ return;
+
+ d->delay = delay;
+ emit delayChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::DelayButton::progress
+ \readonly
+
+ This property holds the current progress as displayed by the progress
+ indicator, in the range \c 0.0 - \c 1.0.
+*/
+qreal QQuickDelayButton::progress() const
+{
+ Q_D(const QQuickDelayButton);
+ return d->progress;
+}
+
+void QQuickDelayButton::setProgress(qreal progress)
+{
+ Q_D(QQuickDelayButton);
+ if (qFuzzyCompare(d->progress, progress))
+ return;
+
+ d->progress = progress;
+ emit progressChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::DelayButton::transition
+
+ This property holds the transition that is applied on the \l progress
+ property when the button is pressed or released.
+*/
+QQuickTransition *QQuickDelayButton::transition() const
+{
+ Q_D(const QQuickDelayButton);
+ return d->transition;
+}
+
+void QQuickDelayButton::setTransition(QQuickTransition *transition)
+{
+ Q_D(QQuickDelayButton);
+ if (d->transition == transition)
+ return;
+
+ d->transition = transition;
+ emit transitionChanged();
+}
+
+void QQuickDelayButton::buttonChange(ButtonChange change)
+{
+ Q_D(QQuickDelayButton);
+ switch (change) {
+ case ButtonCheckedChange:
+ d->cancelTransition();
+ setProgress(d->checked ? 1.0 : 0.0);
+ break;
+ case ButtonPressedChanged:
+ if (!d->checked)
+ d->beginTransition(d->pressed ? 1.0 : 0.0);
+ break;
+ default:
+ QQuickAbstractButton::buttonChange(change);
+ break;
+ }
+}
+
+void QQuickDelayButton::nextCheckState()
+{
+ Q_D(QQuickDelayButton);
+ setChecked(!d->checked && qFuzzyCompare(d->progress, qreal(1.0)));
+}
+
+QFont QQuickDelayButton::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Button);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickdelaybutton_p.cpp"
diff --git a/src/quicktemplates2/qquickdelaybutton_p.h b/src/quicktemplates2/qquickdelaybutton_p.h
new file mode 100644
index 0000000000..a697bca807
--- /dev/null
+++ b/src/quicktemplates2/qquickdelaybutton_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDELAYBUTTON_P_H
+#define QQUICKDELAYBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTransition;
+class QQuickDelayButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDelayButton : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL)
+ Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged FINAL)
+ Q_PROPERTY(QQuickTransition *transition READ transition WRITE setTransition NOTIFY transitionChanged FINAL)
+ QML_NAMED_ELEMENT(DelayButton)
+ QML_ADDED_IN_VERSION(2, 2)
+
+public:
+ explicit QQuickDelayButton(QQuickItem *parent = nullptr);
+
+ int delay() const;
+ void setDelay(int delay);
+
+ qreal progress() const;
+ void setProgress(qreal progress);
+
+ QQuickTransition *transition() const;
+ void setTransition(QQuickTransition *transition);
+
+Q_SIGNALS:
+ void activated();
+ void delayChanged();
+ void progressChanged();
+ void transitionChanged();
+
+protected:
+ void buttonChange(ButtonChange change) override;
+ void nextCheckState() override;
+
+ QFont defaultFont() const override;
+
+private:
+ Q_DISABLE_COPY(QQuickDelayButton)
+ Q_DECLARE_PRIVATE(QQuickDelayButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDelayButton)
+
+#endif // QQUICKDELAYBUTTON_P_H
diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp
new file mode 100644
index 0000000000..2c38ff7558
--- /dev/null
+++ b/src/quicktemplates2/qquickdial.cpp
@@ -0,0 +1,861 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdial_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+
+#include <cmath>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Dial
+ \inherits Control
+//! \instantiates QQuickDial
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \brief Circular dial that is rotated to set a value.
+
+ The Dial is similar to a traditional dial knob that is found on devices
+ such as stereos or industrial equipment. It allows the user to specify a
+ value within a range.
+
+ \image qtquickcontrols2-dial-no-wrap.gif
+
+ The value of the dial is set with the \l value property. The range is
+ set with the \l from and \l to properties. To enable or disable wrapping,
+ use the \l wrap property.
+
+ The dial can be manipulated with a keyboard. It supports the following
+ actions:
+
+ \table
+ \header \li \b {Action} \li \b {Key}
+ \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Left
+ \row \li Decrease \l value by \l stepSize \li \c Qt.Key_Down
+ \row \li Set \l value to \l from \li \c Qt.Key_Home
+ \row \li Increase \l value by \l stepSize \li \c Qt.Key_Right
+ \row \li Increase \l value by \l stepSize \li \c Qt.Key_Up
+ \row \li Set \l value to \l to \li \c Qt.Key_End
+ \endtable
+
+ \include qquickdial.qdocinc inputMode
+
+ \sa {Customizing Dial}, {Input Controls}
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal QtQuick.Controls::Dial::moved()
+
+ This signal is emitted when the dial has been interactively moved
+ by the user by either touch, mouse, or keys.
+*/
+
+static const qreal startAngleRadians = (M_PI * 2.0) * (4.0 / 6.0);
+static const qreal startAngle = -140;
+static const qreal endAngleRadians = (M_PI * 2.0) * (5.0 / 6.0);
+static const qreal endAngle = 140;
+
+class QQuickDialPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDial)
+
+public:
+ qreal valueAt(qreal position) const;
+ qreal snapPosition(qreal position) const;
+ qreal positionAt(const QPointF &point) const;
+ qreal circularPositionAt(const QPointF &point) const;
+ qreal linearPositionAt(const QPointF &point) const;
+ void setPosition(qreal position);
+ void updatePosition();
+ bool isLargeChange(const QPointF &eventPos, qreal proposedPosition) const;
+ bool isHorizontalOrVertical() const;
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void cancelHandle();
+ void executeHandle(bool complete = false);
+
+ void updateAllValuesAreInteger();
+
+ qreal from = 0;
+ qreal to = 1;
+ qreal value = 0;
+ qreal position = 0;
+ qreal angle = startAngle;
+ qreal stepSize = 0;
+ QPointF pressPoint;
+ qreal positionBeforePress = 0;
+ QQuickDial::SnapMode snapMode = QQuickDial::NoSnap;
+ QQuickDial::InputMode inputMode = QQuickDial::Circular;
+ QQuickDeferredPointer<QQuickItem> handle;
+ bool wrap = false;
+ bool live = true;
+ bool pressed = false;
+ bool allValuesAreInteger = false;
+};
+
+qreal QQuickDialPrivate::valueAt(qreal position) const
+{
+ qreal value = from + (to - from) * position;
+
+ /* play nice with users expecting that integer from, to and stepSize leads to
+ integer values - given that we are using floating point internally (and in
+ the API of value), this does not hold, but it is easy enough to handle
+ */
+ if (allValuesAreInteger)
+ value = qRound(value);
+
+ return value;
+}
+
+qreal QQuickDialPrivate::snapPosition(qreal position) const
+{
+ const qreal range = to - from;
+ if (qFuzzyIsNull(range))
+ return position;
+
+ const qreal effectiveStep = stepSize / range;
+ if (qFuzzyIsNull(effectiveStep))
+ return position;
+
+ return qRound(position / effectiveStep) * effectiveStep;
+}
+
+qreal QQuickDialPrivate::positionAt(const QPointF &point) const
+{
+ return inputMode == QQuickDial::Circular ? circularPositionAt(point) : linearPositionAt(point);
+}
+
+qreal QQuickDialPrivate::circularPositionAt(const QPointF &point) const
+{
+ qreal yy = height / 2.0 - point.y();
+ qreal xx = point.x() - width / 2.0;
+ qreal angle = (xx || yy) ? std::atan2(yy, xx) : 0;
+
+ if (angle < M_PI / -2)
+ angle = angle + M_PI * 2;
+
+ qreal normalizedAngle = (startAngleRadians - angle) / endAngleRadians;
+ return normalizedAngle;
+}
+
+qreal QQuickDialPrivate::linearPositionAt(const QPointF &point) const
+{
+ // This value determines the range (either horizontal or vertical)
+ // within which the dial can be dragged.
+ // The larger this value is, the further the drag distance
+ // must be to go from a position of e.g. 0.0 to 1.0.
+ qreal dragArea = 0;
+
+ // The linear input mode uses a "relative" input system,
+ // where the distance from the press point is used to calculate
+ // the change in position. Moving the mouse above the press
+ // point increases the position (when inputMode is Vertical),
+ // and vice versa. This prevents the dial from jumping when clicked.
+ qreal dragDistance = 0;
+
+ if (inputMode == QQuickDial::Horizontal) {
+ dragArea = width * 2;
+ dragDistance = pressPoint.x() - point.x();
+ } else {
+ dragArea = height * 2;
+ dragDistance = point.y() - pressPoint.y();
+ }
+ const qreal normalisedDifference = dragDistance / dragArea;
+ return qBound(qreal(0), positionBeforePress - normalisedDifference, qreal(1));
+}
+
+void QQuickDialPrivate::setPosition(qreal pos)
+{
+ Q_Q(QQuickDial);
+ pos = qBound<qreal>(qreal(0), pos, qreal(1));
+ if (qFuzzyCompare(position, pos))
+ return;
+
+ position = pos;
+
+ angle = startAngle + position * qAbs(endAngle - startAngle);
+
+ emit q->positionChanged();
+ emit q->angleChanged();
+}
+
+void QQuickDialPrivate::updatePosition()
+{
+ qreal pos = 0;
+ if (!qFuzzyCompare(from, to))
+ pos = (value - from) / (to - from);
+ setPosition(pos);
+}
+
+bool QQuickDialPrivate::isLargeChange(const QPointF &eventPos, qreal proposedPosition) const
+{
+ return qAbs(proposedPosition - position) >= qreal(0.5) && eventPos.y() >= height / 2;
+}
+
+bool QQuickDialPrivate::isHorizontalOrVertical() const
+{
+ return inputMode == QQuickDial::Horizontal || inputMode == QQuickDial::Vertical;
+}
+
+void QQuickDialPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickDial);
+ QQuickControlPrivate::handlePress(point);
+ pressPoint = point;
+ positionBeforePress = position;
+ q->setPressed(true);
+}
+
+void QQuickDialPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickDial);
+ QQuickControlPrivate::handleMove(point);
+ const qreal oldPos = position;
+ qreal pos = positionAt(point);
+ if (snapMode == QQuickDial::SnapAlways)
+ pos = snapPosition(pos);
+
+ if (wrap || isHorizontalOrVertical() || !isLargeChange(point, pos)) {
+ if (live)
+ q->setValue(valueAt(pos));
+ else
+ setPosition(pos);
+ if (!qFuzzyCompare(pos, oldPos))
+ emit q->moved();
+ }
+}
+
+void QQuickDialPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickDial);
+ QQuickControlPrivate::handleRelease(point);
+ if (q->keepMouseGrab() || q->keepTouchGrab()) {
+ const qreal oldPos = position;
+ qreal pos = positionAt(point);
+ if (snapMode != QQuickDial::NoSnap)
+ pos = snapPosition(pos);
+
+ if (wrap || isHorizontalOrVertical() || !isLargeChange(point, pos))
+ q->setValue(valueAt(pos));
+ if (!qFuzzyCompare(pos, oldPos))
+ emit q->moved();
+
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+ }
+
+ q->setPressed(false);
+ pressPoint = QPointF();
+ positionBeforePress = 0;
+}
+
+void QQuickDialPrivate::handleUngrab()
+{
+ Q_Q(QQuickDial);
+ QQuickControlPrivate::handleUngrab();
+ pressPoint = QPointF();
+ positionBeforePress = 0;
+ q->setPressed(false);
+}
+
+static inline QString handleName() { return QStringLiteral("handle"); }
+
+void QQuickDialPrivate::cancelHandle()
+{
+ Q_Q(QQuickDial);
+ quickCancelDeferred(q, handleName());
+}
+
+void QQuickDialPrivate::executeHandle(bool complete)
+{
+ Q_Q(QQuickDial);
+ if (handle.wasExecuted())
+ return;
+
+ if (!handle || complete)
+ quickBeginDeferred(q, handleName(), handle);
+ if (complete)
+ quickCompleteDeferred(q, handleName(), handle);
+}
+
+template<typename ...Real>
+static bool areRepresentableAsInteger(Real... numbers) {
+ auto check = [](qreal number) -> bool { return std::nearbyint(number) == number; };
+ return (... && check(numbers));
+}
+
+void QQuickDialPrivate::updateAllValuesAreInteger()
+{
+ allValuesAreInteger = areRepresentableAsInteger(to, from, stepSize) && stepSize != 0.0;
+}
+
+QQuickDial::QQuickDial(QQuickItem *parent)
+ : QQuickControl(*(new QQuickDialPrivate), parent)
+{
+ setActiveFocusOnTab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::from
+
+ This property holds the starting value for the range. The default value is \c 0.0.
+
+ \sa to, value
+*/
+qreal QQuickDial::from() const
+{
+ Q_D(const QQuickDial);
+ return d->from;
+}
+
+void QQuickDial::setFrom(qreal from)
+{
+ Q_D(QQuickDial);
+ if (qFuzzyCompare(d->from, from))
+ return;
+
+ d->from = from;
+ emit fromChanged();
+ d->updateAllValuesAreInteger();
+ if (isComponentComplete()) {
+ setValue(d->value);
+ d->updatePosition();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::to
+
+ This property holds the end value for the range. The default value is
+ \c 1.0.
+
+ \sa from, value
+*/
+qreal QQuickDial::to() const
+{
+ Q_D(const QQuickDial);
+ return d->to;
+}
+
+void QQuickDial::setTo(qreal to)
+{
+ Q_D(QQuickDial);
+ if (qFuzzyCompare(d->to, to))
+ return;
+
+ d->to = to;
+ d->updateAllValuesAreInteger();
+ emit toChanged();
+ if (isComponentComplete()) {
+ setValue(d->value);
+ d->updatePosition();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::value
+
+ This property holds the value in the range \c from - \c to. The default
+ value is \c 0.0.
+
+ \sa position, live
+*/
+qreal QQuickDial::value() const
+{
+ Q_D(const QQuickDial);
+ return d->value;
+}
+
+void QQuickDial::setValue(qreal value)
+{
+ Q_D(QQuickDial);
+ if (isComponentComplete())
+ value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to);
+
+ if (qFuzzyCompare(d->value, value))
+ return;
+
+ d->value = value;
+ d->updatePosition();
+ emit valueChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::position
+ \readonly
+
+ This property holds the logical position of the handle.
+
+ The position is expressed as a fraction of the control's angle range (the
+ range within which the handle can be moved) in the range \c {0.0 - 1.0}.
+
+ \sa value, angle
+*/
+qreal QQuickDial::position() const
+{
+ Q_D(const QQuickDial);
+ return d->position;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::angle
+ \readonly
+
+ This property holds the angle of the handle.
+
+ The range is from \c -140 degrees to \c 140 degrees.
+
+ \sa position
+*/
+qreal QQuickDial::angle() const
+{
+ Q_D(const QQuickDial);
+ return d->angle;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Dial::stepSize
+
+ This property holds the step size.
+
+ The step size determines the amount by which the dial's value
+ is increased and decreased when interacted with via the keyboard.
+ For example, a step size of \c 0.2, will result in the dial's
+ value increasing and decreasing in increments of \c 0.2.
+
+ The step size is only respected for touch and mouse interaction
+ when \l snapMode is set to a value other than \c Dial.NoSnap.
+
+ The default value is \c 0.0, which results in an effective step
+ size of \c 0.1 for keyboard interaction.
+
+ \sa snapMode, increase(), decrease()
+*/
+qreal QQuickDial::stepSize() const
+{
+ Q_D(const QQuickDial);
+ return d->stepSize;
+}
+
+void QQuickDial::setStepSize(qreal step)
+{
+ Q_D(QQuickDial);
+ if (qFuzzyCompare(d->stepSize, step))
+ return;
+
+ d->stepSize = step;
+ d->updateAllValuesAreInteger();
+ emit stepSizeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Dial::snapMode
+
+ This property holds the snap mode.
+
+ The snap mode works with the \l stepSize to allow the handle to snap to
+ certain points along the dial.
+
+ Possible values:
+ \value Dial.NoSnap The dial does not snap (default).
+ \value Dial.SnapAlways The dial snaps while the handle is dragged.
+ \value Dial.SnapOnRelease The dial does not snap while being dragged, but only after the handle is released.
+
+ \sa stepSize
+*/
+QQuickDial::SnapMode QQuickDial::snapMode() const
+{
+ Q_D(const QQuickDial);
+ return d->snapMode;
+}
+
+void QQuickDial::setSnapMode(SnapMode mode)
+{
+ Q_D(QQuickDial);
+ if (d->snapMode == mode)
+ return;
+
+ d->snapMode = mode;
+ emit snapModeChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty enumeration QtQuick.Controls::Dial::inputMode
+
+ This property holds the input mode.
+
+ \include qquickdial.qdocinc inputMode
+
+ The default value is \c Dial.Circular.
+*/
+QQuickDial::InputMode QQuickDial::inputMode() const
+{
+ Q_D(const QQuickDial);
+ return d->inputMode;
+}
+
+void QQuickDial::setInputMode(QQuickDial::InputMode mode)
+{
+ Q_D(QQuickDial);
+ if (d->inputMode == mode)
+ return;
+
+ d->inputMode = mode;
+ emit inputModeChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Dial::wrap
+
+ This property holds whether the dial wraps when dragged.
+
+ For example, when this property is set to \c true, dragging the dial past
+ the \l to position will result in the handle being positioned at the
+ \l from position, and vice versa:
+
+ \image qtquickcontrols2-dial-wrap.gif
+
+ When this property is \c false, it's not possible to drag the dial across
+ the from and to values.
+
+ \image qtquickcontrols2-dial-no-wrap.gif
+
+ The default value is \c false.
+*/
+bool QQuickDial::wrap() const
+{
+ Q_D(const QQuickDial);
+ return d->wrap;
+}
+
+void QQuickDial::setWrap(bool wrap)
+{
+ Q_D(QQuickDial);
+ if (d->wrap == wrap)
+ return;
+
+ d->wrap = wrap;
+ emit wrapChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Dial::pressed
+
+ This property holds whether the dial is pressed.
+
+ The dial will be pressed when either the mouse is pressed over it, or a key
+ such as \c Qt.Key_Left is held down. If you'd prefer not to have the dial
+ be pressed upon key presses (due to styling reasons, for example), you can
+ use the \l {Keys}{Keys attached property}:
+
+ \code
+ Dial {
+ Keys.onLeftPressed: {}
+ }
+ \endcode
+
+ This will result in pressed only being \c true upon mouse presses.
+*/
+bool QQuickDial::isPressed() const
+{
+ Q_D(const QQuickDial);
+ return d->pressed;
+}
+
+void QQuickDial::setPressed(bool pressed)
+{
+ Q_D(QQuickDial);
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ setAccessibleProperty("pressed", pressed);
+ emit pressedChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Dial::handle
+
+ This property holds the handle of the dial.
+
+ The handle acts as a visual indicator of the position of the dial.
+
+ \sa {Customizing Dial}
+*/
+QQuickItem *QQuickDial::handle() const
+{
+ QQuickDialPrivate *d = const_cast<QQuickDialPrivate *>(d_func());
+ if (!d->handle)
+ d->executeHandle();
+ return d->handle;
+}
+
+void QQuickDial::setHandle(QQuickItem *handle)
+{
+ Q_D(QQuickDial);
+ if (handle == d->handle)
+ return;
+
+ if (!d->handle.isExecuting())
+ d->cancelHandle();
+
+ QQuickControlPrivate::hideOldItem(d->handle);
+ d->handle = handle;
+ if (d->handle && !d->handle->parentItem())
+ d->handle->setParentItem(this);
+ if (!d->handle.isExecuting())
+ emit handleChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::Dial::live
+
+ This property holds whether the dial provides live updates for the \l value
+ property while the handle is dragged.
+
+ The default value is \c true.
+
+ \sa value
+*/
+bool QQuickDial::live() const
+{
+ Q_D(const QQuickDial);
+ return d->live;
+}
+
+void QQuickDial::setLive(bool live)
+{
+ Q_D(QQuickDial);
+ if (d->live == live)
+ return;
+
+ d->live = live;
+ emit liveChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dial::increase()
+
+ Increases the value by \l stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickDial::increase()
+{
+ Q_D(QQuickDial);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(d->value + step);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dial::decrease()
+
+ Decreases the value by \l stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickDial::decrease()
+{
+ Q_D(QQuickDial);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(d->value - step);
+}
+
+void QQuickDial::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickDial);
+ const qreal oldValue = d->value;
+ switch (event->key()) {
+ case Qt::Key_Left:
+ case Qt::Key_Down:
+ setPressed(true);
+ if (isMirrored())
+ increase();
+ else
+ decrease();
+ break;
+
+ case Qt::Key_Right:
+ case Qt::Key_Up:
+ setPressed(true);
+ if (isMirrored())
+ decrease();
+ else
+ increase();
+ break;
+
+ case Qt::Key_Home:
+ setPressed(true);
+ setValue(isMirrored() ? d->to : d->from);
+ break;
+
+ case Qt::Key_End:
+ setPressed(true);
+ setValue(isMirrored() ? d->from : d->to);
+ break;
+
+ default:
+ event->ignore();
+ QQuickControl::keyPressEvent(event);
+ break;
+ }
+ if (!qFuzzyCompare(d->value, oldValue))
+ emit moved();
+}
+
+void QQuickDial::keyReleaseEvent(QKeyEvent *event)
+{
+ QQuickControl::keyReleaseEvent(event);
+ setPressed(false);
+}
+
+void QQuickDial::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickDial);
+ QQuickControl::mousePressEvent(event);
+ d->handleMove(event->position());
+ setKeepMouseGrab(true);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickDial::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickDial);
+ switch (event->type()) {
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (!d->acceptTouch(point))
+ continue;
+
+ switch (point.state()) {
+ case QEventPoint::Updated:
+ if (!keepTouchGrab()) {
+ bool overXDragThreshold = QQuickWindowPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(), Qt::XAxis, &point);
+ setKeepTouchGrab(overXDragThreshold);
+
+ if (!overXDragThreshold) {
+ bool overYDragThreshold = QQuickWindowPrivate::dragOverThreshold(point.position().y() - d->pressPoint.y(), Qt::YAxis, &point);
+ setKeepTouchGrab(overYDragThreshold);
+ }
+ }
+ if (keepTouchGrab())
+ d->handleMove(point.position());
+ break;
+
+ default:
+ QQuickControl::touchEvent(event);
+ break;
+ }
+ }
+ break;
+
+ default:
+ QQuickControl::touchEvent(event);
+ break;
+ }
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickDial::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickDial);
+ QQuickControl::wheelEvent(event);
+ if (d->wheelEnabled) {
+ const qreal oldValue = d->value;
+ const QPointF angle = event->angleDelta();
+ const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) / int(QWheelEvent::DefaultDeltasPerStep);
+ const qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(oldValue + step * delta);
+ event->setAccepted(!qFuzzyCompare(d->value, oldValue));
+ }
+}
+#endif
+
+void QQuickDial::mirrorChange()
+{
+ QQuickControl::mirrorChange();
+ emit angleChanged();
+}
+
+void QQuickDial::componentComplete()
+{
+ Q_D(QQuickDial);
+ d->executeHandle(true);
+ QQuickControl::componentComplete();
+ setValue(d->value);
+ d->updatePosition();
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickDial::accessibilityActiveChanged(bool active)
+{
+ QQuickControl::accessibilityActiveChanged(active);
+
+ Q_D(QQuickDial);
+ if (active)
+ setAccessibleProperty("pressed", d->pressed);
+}
+
+QAccessible::Role QQuickDial::accessibleRole() const
+{
+ return QAccessible::Dial;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickdial_p.cpp"
diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h
new file mode 100644
index 0000000000..67bbc18390
--- /dev/null
+++ b/src/quicktemplates2/qquickdial_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIAL_P_H
+#define QQUICKDIAL_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/qvariant.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDialAttached;
+class QQuickDialPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDial : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal angle READ angle NOTIFY angleChanged FINAL)
+ Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap NOTIFY wrapChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION(2, 2))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(InputMode inputMode READ inputMode WRITE setInputMode NOTIFY inputModeChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "background,handle")
+ QML_NAMED_ELEMENT(Dial)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickDial(QQuickItem *parent = nullptr);
+
+ qreal from() const;
+ void setFrom(qreal from);
+
+ qreal to() const;
+ void setTo(qreal to);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+ qreal position() const;
+
+ qreal angle() const;
+
+ qreal stepSize() const;
+ void setStepSize(qreal step);
+
+ enum SnapMode {
+ NoSnap,
+ SnapAlways,
+ SnapOnRelease
+ };
+ Q_ENUM(SnapMode)
+
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ enum InputMode {
+ Circular,
+ Horizontal,
+ Vertical,
+ };
+ Q_ENUM(InputMode)
+
+ bool wrap() const;
+ void setWrap(bool wrap);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ QQuickItem *handle() const;
+ void setHandle(QQuickItem *handle);
+
+ // 2.2 (Qt 5.9)
+ bool live() const;
+ void setLive(bool live);
+
+ // 2.5 (Qt 5.12)
+ InputMode inputMode() const;
+ void setInputMode(InputMode mode);
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void valueChanged();
+ void positionChanged();
+ void angleChanged();
+ void stepSizeChanged();
+ void snapModeChanged();
+ void wrapChanged();
+ void pressedChanged();
+ void handleChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void moved();
+ Q_REVISION(2, 2) void liveChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void inputModeChanged();
+
+protected:
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ void mirrorChange() override;
+ void componentComplete() override;
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickDial)
+ Q_DECLARE_PRIVATE(QQuickDial)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDial)
+
+#endif // QQUICKDIAL_P_H
diff --git a/src/quicktemplates2/qquickdialog.cpp b/src/quicktemplates2/qquickdialog.cpp
new file mode 100644
index 0000000000..812d1c1ac2
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog.cpp
@@ -0,0 +1,578 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdialog_p.h"
+#include "qquickdialog_p_p.h"
+#include "qquickdialogbuttonbox_p.h"
+#include "qquickabstractbutton_p.h"
+#include "qquickpopupitem_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Dialog
+ \inherits Popup
+//! \instantiates QQuickDialog
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-dialogs
+ \ingroup qtquickcontrols2-popups
+ \brief Popup dialog with standard buttons and a title, used for short-term interaction with the user.
+ \since 5.8
+
+ A dialog is a popup mostly used for short-term tasks and brief communications
+ with the user. Similarly to \l ApplicationWindow and \l Page, Dialog is organized
+ into three sections: \l header, \l {Popup::}{contentItem}, and \l footer.
+
+ \image qtquickcontrols2-page-wireframe.png
+
+ \section1 Dialog Title and Buttons
+
+ Dialog's \l title is displayed by a style-specific title bar that is assigned
+ as a dialog \l header by default.
+
+ Dialog's standard buttons are managed by a \l DialogButtonBox that is assigned
+ as a dialog \l footer by default. The dialog's \l standardButtons property is
+ forwarded to the respective property of the button box. Furthermore, the
+ \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals of the button box are connected to the respective signals in Dialog.
+
+ \snippet qtquickcontrols2-dialog.qml 1
+
+ \section1 Modal Dialogs
+
+ A \l {Popup::}{modal} dialog blocks input to other content beneath
+ the dialog. When a modal dialog is opened, the user must finish
+ interacting with the dialog and close it before they can access any
+ other content in the same window.
+
+ \snippet qtquickcontrols2-dialog-modal.qml 1
+
+ \section1 Modeless Dialogs
+
+ A modeless dialog is a dialog that operates independently of other
+ content around the dialog. When a modeless dialog is opened, the user
+ is allowed to interact with both the dialog and the other content in
+ the same window.
+
+ \snippet qtquickcontrols2-dialog-modeless.qml 1
+
+ \sa DialogButtonBox, {Popup Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Dialog::accepted()
+
+ This signal is emitted when the dialog has been accepted either
+ interactively or by calling \l accept().
+
+ \note This signal is \e not emitted when closing the dialog with
+ \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
+
+ \sa rejected()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Dialog::rejected()
+
+ This signal is emitted when the dialog has been rejected either
+ interactively or by calling \l reject().
+
+ \note This signal is \e not emitted when closing the dialog with
+ \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
+
+ \sa accepted()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::Dialog::applied()
+
+ This signal is emitted when the \c Dialog.Apply standard button is clicked.
+
+ \sa discarded(), reset()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::Dialog::reset()
+
+ This signal is emitted when the \c Dialog.Reset standard button is clicked.
+
+ \sa discarded(), applied()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::Dialog::discarded()
+
+ This signal is emitted when the \c Dialog.Discard standard button is clicked.
+
+ \sa reset(), applied()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::Dialog::helpRequested()
+
+ This signal is emitted when the \c Dialog.Help standard button is clicked.
+
+ \sa accepted(), rejected()
+*/
+
+QPlatformDialogHelper::ButtonRole QQuickDialogPrivate::buttonRole(QQuickAbstractButton *button)
+{
+ const QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
+ return attached ? attached->buttonRole() : QPlatformDialogHelper::InvalidRole;
+}
+
+void QQuickDialogPrivate::handleAccept()
+{
+ Q_Q(QQuickDialog);
+ q->accept();
+}
+
+void QQuickDialogPrivate::handleReject()
+{
+ Q_Q(QQuickDialog);
+ q->reject();
+}
+
+void QQuickDialogPrivate::handleClick(QQuickAbstractButton *button)
+{
+ Q_Q(QQuickDialog);
+ switch (buttonRole(button)) {
+ case QPlatformDialogHelper::ApplyRole:
+ emit q->applied();
+ break;
+ case QPlatformDialogHelper::ResetRole:
+ emit q->reset();
+ break;
+ case QPlatformDialogHelper::DestructiveRole:
+ emit q->discarded();
+ break;
+ case QPlatformDialogHelper::HelpRole:
+ emit q->helpRequested();
+ break;
+ default:
+ break;
+ }
+}
+
+QQuickDialog::QQuickDialog(QObject *parent)
+ : QQuickDialog(*(new QQuickDialogPrivate), parent)
+{
+}
+
+QQuickDialog::QQuickDialog(QQuickDialogPrivate &dd, QObject *parent)
+ : QQuickPopup(dd, parent)
+{
+ Q_D(QQuickDialog);
+ 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);
+ QObject::connect(d->popupItem, &QQuickPopupItem::implicitHeaderHeightChanged, this, &QQuickDialog::implicitHeaderHeightChanged);
+ QObject::connect(d->popupItem, &QQuickPopupItem::implicitFooterWidthChanged, this, &QQuickDialog::implicitFooterWidthChanged);
+ QObject::connect(d->popupItem, &QQuickPopupItem::implicitFooterHeightChanged, this, &QQuickDialog::implicitFooterHeightChanged);
+}
+
+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);
+ QObject::disconnect(d->popupItem, &QQuickPopupItem::implicitHeaderHeightChanged, this, &QQuickDialog::implicitHeaderHeightChanged);
+ QObject::disconnect(d->popupItem, &QQuickPopupItem::implicitFooterWidthChanged, this, &QQuickDialog::implicitFooterWidthChanged);
+ QObject::disconnect(d->popupItem, &QQuickPopupItem::implicitFooterHeightChanged, this, &QQuickDialog::implicitFooterHeightChanged);
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::Dialog::title
+
+ This property holds the dialog title.
+
+ The title is displayed in the dialog header.
+
+ \code
+ Dialog {
+ title: qsTr("About")
+
+ Label {
+ text: "Lorem ipsum..."
+ }
+ }
+ \endcode
+*/
+QString QQuickDialog::title() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->title();
+}
+
+void QQuickDialog::setTitle(const QString &title)
+{
+ Q_D(QQuickDialog);
+ d->popupItem->setTitle(title);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Dialog::header
+
+ This property holds the dialog header item. The header item is positioned to
+ the top, and resized to the width of the dialog. The default value is \c null.
+
+ \note Assigning a \l DialogButtonBox as a dialog header automatically connects
+ its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals to the respective signals in Dialog.
+
+ \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
+ header automatically sets the respective \l DialogButtonBox::position,
+ \l ToolBar::position, or \l TabBar::position property to \c Header.
+
+ \sa footer
+*/
+QQuickItem *QQuickDialog::header() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->header();
+}
+
+void QQuickDialog::setHeader(QQuickItem *header)
+{
+ Q_D(QQuickDialog);
+ QQuickItem *oldHeader = d->popupItem->header();
+ if (oldHeader == header)
+ return;
+
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(oldHeader)) {
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::accepted, d, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::rejected, d, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::clicked, d, &QQuickDialogPrivate::handleClick);
+ if (d->buttonBox == buttonBox)
+ d->buttonBox = nullptr;
+ }
+
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(header)) {
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::accepted, d, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::rejected, d, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::clicked, d, &QQuickDialogPrivate::handleClick);
+ d->buttonBox = buttonBox;
+ buttonBox->setStandardButtons(d->standardButtons);
+ }
+
+ d->popupItem->setHeader(header);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Dialog::footer
+
+ This property holds the dialog footer item. The footer item is positioned to
+ the bottom, and resized to the width of the dialog. The default value is \c null.
+
+ \note Assigning a \l DialogButtonBox as a dialog footer automatically connects
+ its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals to the respective signals in Dialog.
+
+ \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
+ footer automatically sets the respective \l DialogButtonBox::position,
+ \l ToolBar::position, or \l TabBar::position property to \c Footer.
+
+ \sa header
+*/
+QQuickItem *QQuickDialog::footer() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->footer();
+}
+
+void QQuickDialog::setFooter(QQuickItem *footer)
+{
+ Q_D(QQuickDialog);
+ QQuickItem *oldFooter = d->popupItem->footer();
+ if (oldFooter == footer)
+ return;
+
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(oldFooter)) {
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::accepted, d, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::rejected, d, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::disconnect(buttonBox, &QQuickDialogButtonBox::clicked, d, &QQuickDialogPrivate::handleClick);
+ if (d->buttonBox == buttonBox)
+ d->buttonBox = nullptr;
+ }
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(footer)) {
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::accepted, d, &QQuickDialogPrivate::handleAccept);
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::rejected, d, &QQuickDialogPrivate::handleReject);
+ QObjectPrivate::connect(buttonBox, &QQuickDialogButtonBox::clicked, d, &QQuickDialogPrivate::handleClick);
+ d->buttonBox = buttonBox;
+ buttonBox->setStandardButtons(d->standardButtons);
+ }
+
+ d->popupItem->setFooter(footer);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Dialog::standardButtons
+
+ This property holds a combination of standard buttons that are used by the dialog.
+
+ \snippet qtquickcontrols2-dialog.qml 1
+
+ The buttons will be positioned in the appropriate order for the user's platform.
+
+ Possible flags:
+ \value Dialog.Ok An "OK" button defined with the \c AcceptRole.
+ \value Dialog.Open An "Open" button defined with the \c AcceptRole.
+ \value Dialog.Save A "Save" button defined with the \c AcceptRole.
+ \value Dialog.Cancel A "Cancel" button defined with the \c RejectRole.
+ \value Dialog.Close A "Close" button defined with the \c RejectRole.
+ \value Dialog.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
+ \value Dialog.Apply An "Apply" button defined with the \c ApplyRole.
+ \value Dialog.Reset A "Reset" button defined with the \c ResetRole.
+ \value Dialog.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
+ \value Dialog.Help A "Help" button defined with the \c HelpRole.
+ \value Dialog.SaveAll A "Save All" button defined with the \c AcceptRole.
+ \value Dialog.Yes A "Yes" button defined with the \c YesRole.
+ \value Dialog.YesToAll A "Yes to All" button defined with the \c YesRole.
+ \value Dialog.No A "No" button defined with the \c NoRole.
+ \value Dialog.NoToAll A "No to All" button defined with the \c NoRole.
+ \value Dialog.Abort An "Abort" button defined with the \c RejectRole.
+ \value Dialog.Retry A "Retry" button defined with the \c AcceptRole.
+ \value Dialog.Ignore An "Ignore" button defined with the \c AcceptRole.
+ \value Dialog.NoButton An invalid button.
+
+ \sa DialogButtonBox
+*/
+QPlatformDialogHelper::StandardButtons QQuickDialog::standardButtons() const
+{
+ Q_D(const QQuickDialog);
+ return d->standardButtons;
+}
+
+void QQuickDialog::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
+{
+ Q_D(QQuickDialog);
+ if (d->standardButtons == buttons)
+ return;
+
+ d->standardButtons = buttons;
+ if (d->buttonBox)
+ d->buttonBox->setStandardButtons(buttons);
+ emit standardButtonsChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod AbstractButton QtQuick.Controls::Dialog::standardButton(StandardButton button)
+
+ Returns the specified standard \a button, or \c null if it does not exist.
+
+ \sa standardButtons
+*/
+QQuickAbstractButton *QQuickDialog::standardButton(QPlatformDialogHelper::StandardButton button) const
+{
+ Q_D(const QQuickDialog);
+ if (!d->buttonBox)
+ return nullptr;
+ return d->buttonBox->standardButton(button);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty int QtQuick.Controls::Dialog::result
+
+ This property holds the result code.
+
+ Standard result codes:
+ \value Dialog.Accepted The dialog was accepted.
+ \value Dialog.Rejected The dialog was rejected.
+
+ \sa accept(), reject(), done()
+*/
+int QQuickDialog::result() const
+{
+ Q_D(const QQuickDialog);
+ return d->result;
+}
+
+void QQuickDialog::setResult(int result)
+{
+ Q_D(QQuickDialog);
+ if (d->result == result)
+ return;
+
+ d->result = result;
+ emit resultChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Dialog::implicitHeaderWidth
+ \readonly
+
+ This property holds the implicit header width.
+
+ The value is equal to \c {header && header.visible ? header.implicitWidth : 0}.
+
+ \sa implicitHeaderHeight, implicitFooterWidth
+*/
+qreal QQuickDialog::implicitHeaderWidth() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->implicitHeaderWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Dialog::implicitHeaderHeight
+ \readonly
+
+ This property holds the implicit header height.
+
+ The value is equal to \c {header && header.visible ? header.implicitHeight : 0}.
+
+ \sa implicitHeaderWidth, implicitFooterHeight
+*/
+qreal QQuickDialog::implicitHeaderHeight() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->implicitHeaderHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Dialog::implicitFooterWidth
+ \readonly
+
+ This property holds the implicit footer width.
+
+ The value is equal to \c {footer && footer.visible ? footer.implicitWidth : 0}.
+
+ \sa implicitFooterHeight, implicitHeaderWidth
+*/
+qreal QQuickDialog::implicitFooterWidth() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->implicitFooterWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Dialog::implicitFooterHeight
+ \readonly
+
+ This property holds the implicit footer height.
+
+ The value is equal to \c {footer && footer.visible ? footer.implicitHeight : 0}.
+
+ \sa implicitFooterWidth, implicitHeaderHeight
+*/
+qreal QQuickDialog::implicitFooterHeight() const
+{
+ Q_D(const QQuickDialog);
+ return d->popupItem->implicitFooterHeight();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dialog::accept()
+
+ Emits the \l accepted() signal and closes the dialog.
+
+ \sa reject(), done()
+*/
+void QQuickDialog::accept()
+{
+ done(Accepted);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dialog::reject()
+
+ Emits the \l rejected() signal and closes the dialog.
+
+ \sa accept(), done()
+*/
+void QQuickDialog::reject()
+{
+ done(Rejected);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Dialog::done(int result)
+
+ \list 1
+ \li Sets the \a result.
+ \li Emits \l accepted() or \l rejected() depending on
+ whether the result is \c Dialog.Accepted or \c Dialog.Rejected,
+ respectively.
+ \li Emits \l{Popup::}{closed()}.
+ \endlist
+
+ \sa accept(), reject(), result
+*/
+void QQuickDialog::done(int result)
+{
+ setResult(result);
+
+ if (result == Accepted)
+ emit accepted();
+ else if (result == Rejected)
+ emit rejected();
+
+ close();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickDialog::accessibleRole() const
+{
+ return QAccessible::Dialog;
+}
+
+void QQuickDialog::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::accessibilityActiveChanged(active);
+
+ if (active)
+ maybeSetAccessibleName(d->popupItem->title());
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickdialog_p.cpp"
diff --git a/src/quicktemplates2/qquickdialog_p.h b/src/quicktemplates2/qquickdialog_p.h
new file mode 100644
index 0000000000..9b42fa1519
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog_p.h
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOG_P_H
+#define QQUICKDIALOG_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDialogPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialog : public QQuickPopup
+{
+ Q_OBJECT
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL)
+ Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(int result READ result WRITE setResult NOTIFY resultChanged FINAL REVISION(2, 3))
+ QML_EXTENDED_NAMESPACE(QPlatformDialogHelper)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitHeaderWidth READ implicitHeaderWidth NOTIFY implicitHeaderWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitHeaderHeight READ implicitHeaderHeight NOTIFY implicitHeaderHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitFooterWidth READ implicitFooterWidth NOTIFY implicitFooterWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitFooterHeight READ implicitFooterHeight NOTIFY implicitFooterHeightChanged FINAL REVISION(2, 5))
+ QML_NAMED_ELEMENT(Dialog)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickDialog(QObject *parent = nullptr);
+ ~QQuickDialog();
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QQuickItem *header() const;
+ void setHeader(QQuickItem *header);
+
+ QQuickItem *footer() const;
+ void setFooter(QQuickItem *footer);
+
+ QPlatformDialogHelper::StandardButtons standardButtons() const;
+ void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons);
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickAbstractButton *standardButton(QPlatformDialogHelper::StandardButton button) const;
+
+ // 2.3 (Qt 5.10)
+ enum StandardCode { Rejected, Accepted };
+ Q_ENUM(StandardCode)
+
+ int result() const;
+ void setResult(int result);
+
+ // 2.5 (Qt 5.12)
+ qreal implicitHeaderWidth() const;
+ qreal implicitHeaderHeight() const;
+
+ qreal implicitFooterWidth() const;
+ qreal implicitFooterHeight() const;
+
+public Q_SLOTS:
+ virtual void accept();
+ virtual void reject();
+ virtual void done(int result);
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+ void titleChanged();
+ void headerChanged();
+ void footerChanged();
+ void standardButtonsChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void applied();
+ Q_REVISION(2, 3) void reset();
+ Q_REVISION(2, 3) void discarded();
+ Q_REVISION(2, 3) void helpRequested();
+ Q_REVISION(2, 3) void resultChanged();
+ // 2.5 (Qt 5.12)
+ void implicitHeaderWidthChanged();
+ void implicitHeaderHeightChanged();
+ void implicitFooterWidthChanged();
+ void implicitFooterHeightChanged();
+
+protected:
+ QQuickDialog(QQuickDialogPrivate &dd, QObject *parent);
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickDialog)
+ Q_DECLARE_PRIVATE(QQuickDialog)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDialog)
+
+#endif // QQUICKDIALOG_P_H
diff --git a/src/quicktemplates2/qquickdialog_p_p.h b/src/quicktemplates2/qquickdialog_p_p.h
new file mode 100644
index 0000000000..eb40c918a4
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog_p_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOG_P_P_H
+#define QQUICKDIALOG_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 <QtQuickTemplates2/private/qquickdialog_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAbstractButton;
+class QQuickDialogButtonBox;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogPrivate : public QQuickPopupPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialog)
+
+public:
+ static QQuickDialogPrivate *get(QQuickDialog *dialog)
+ {
+ return dialog->d_func();
+ }
+
+ static QPlatformDialogHelper::ButtonRole buttonRole(QQuickAbstractButton *button);
+
+ virtual void handleAccept();
+ virtual void handleReject();
+ virtual void handleClick(QQuickAbstractButton *button);
+
+ int result = 0;
+ QString title;
+ QQuickDialogButtonBox *buttonBox = nullptr;
+ QPlatformDialogHelper::StandardButtons standardButtons = QPlatformDialogHelper::NoButton;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDIALOG_P_P_H
diff --git a/src/quicktemplates2/qquickdialogbuttonbox.cpp b/src/quicktemplates2/qquickdialogbuttonbox.cpp
new file mode 100644
index 0000000000..8c62e4ed68
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox.cpp
@@ -0,0 +1,868 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdialogbuttonbox_p.h"
+#include "qquickdialogbuttonbox_p_p.h"
+#include "qquickabstractbutton_p.h"
+#include "qquickbutton_p.h"
+#include "qquickdialog_p_p.h"
+
+#include <QtCore/qpointer.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype DialogButtonBox
+ \inherits Container
+//! \instantiates QQuickDialogButtonBox
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-dialogs
+ \brief A button box used in dialogs.
+ \since 5.8
+
+ Dialogs and message boxes typically present buttons in an order that
+ conforms to the interface guidelines for that platform. Invariably,
+ different platforms have their dialog buttons in different orders.
+ DialogButtonBox allows a developer to add buttons to it and will
+ automatically use the appropriate order for the user's platform.
+
+ Most buttons for a dialog follow certain roles. Such roles include:
+
+ \list
+ \li Accepting or rejecting the dialog.
+ \li Asking for help.
+ \li Performing actions on the dialog itself (such as resetting fields or
+ applying changes).
+ \endlist
+
+ There can also be alternate ways of dismissing the dialog which may cause
+ destructive results.
+
+ Most dialogs have buttons that can almost be considered standard (e.g.
+ \uicontrol OK and \uicontrol Cancel buttons). It is sometimes convenient
+ to create these buttons in a standard way.
+
+ There are a couple ways of using DialogButtonBox. One way is to specify
+ the standard buttons (e.g. \uicontrol OK, \uicontrol Cancel, \uicontrol Save)
+ and let the button box setup the buttons.
+
+ \image qtquickcontrols2-dialogbuttonbox.png
+
+ \snippet qtquickcontrols2-dialogbuttonbox.qml 1
+
+ Alternatively, buttons and their roles can be specified by hand:
+
+ \snippet qtquickcontrols2-dialogbuttonbox-attached.qml 1
+
+ You can also mix and match normal buttons and standard buttons.
+
+ When a button is clicked in the button box, the \l clicked() signal is
+ emitted for the actual button that is pressed. In addition, the
+ following signals are automatically emitted when a button with the
+ respective role(s) is pressed:
+
+ \table
+ \header
+ \li Role
+ \li Signal
+ \row
+ \li \c AcceptRole, \c YesRole
+ \li \l accepted()
+ \row
+ \li \c ApplyRole
+ \li \l applied()
+ \row
+ \li \c DiscardRole
+ \li \l discarded()
+ \row
+ \li \c HelpRole
+ \li \l helpRequested()
+ \row
+ \li \c RejectRole, \c NoRole
+ \li \l rejected()
+ \row
+ \li \c ResetRole
+ \li \l reset()
+ \endtable
+
+ \sa Dialog
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::accepted()
+
+ This signal is emitted when a button defined with the \c AcceptRole or
+ \c YesRole is clicked.
+
+ \sa rejected(), clicked(), helpRequested()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::rejected()
+
+ This signal is emitted when a button defined with the \c RejectRole or
+ \c NoRole is clicked.
+
+ \sa accepted(), helpRequested(), clicked()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::DialogButtonBox::applied()
+
+ This signal is emitted when a button defined with the \c ApplyRole is
+ clicked.
+
+ \sa discarded(), reset()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::DialogButtonBox::reset()
+
+ This signal is emitted when a button defined with the \c ResetRole is
+ clicked.
+
+ \sa discarded(), applied()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlsignal QtQuick.Controls::DialogButtonBox::discarded()
+
+ This signal is emitted when a button defined with the \c DiscardRole is
+ clicked.
+
+ \sa reset(), applied()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::helpRequested()
+
+ This signal is emitted when a button defined with the \c HelpRole is clicked.
+
+ \sa accepted(), rejected(), clicked()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::clicked(AbstractButton button)
+
+ This signal is emitted when a \a button inside the button box is clicked.
+
+ \sa accepted(), rejected(), helpRequested()
+*/
+
+static QPlatformDialogHelper::ButtonLayout platformButtonLayout()
+{
+ return QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::DialogButtonBoxLayout).value<QPlatformDialogHelper::ButtonLayout>();
+}
+
+void QQuickDialogButtonBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitWidthChanged(item);
+ if (item == contentItem)
+ resizeContent();
+ else
+ updateImplicitContentWidth();
+}
+
+void QQuickDialogButtonBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitHeightChanged(item);
+ if (item == contentItem)
+ resizeContent();
+ else
+ updateImplicitContentHeight();
+}
+
+// adapted from QStyle::alignedRect()
+static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
+{
+ alignment = QGuiApplicationPrivate::visualAlignment(direction, alignment);
+ qreal x = rectangle.x();
+ qreal y = rectangle.y();
+ qreal w = size.width();
+ qreal h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter || (alignment & Qt::AlignVertical_Mask) == 0)
+ y += (rectangle.size().height() - h) / 2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rectangle.size().height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rectangle.size().width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += (rectangle.size().width() - w) / 2;
+ return QRectF(x, y, w, h);
+}
+
+void QQuickDialogButtonBoxPrivate::resizeContent()
+{
+ Q_Q(QQuickDialogButtonBox);
+ if (!contentItem || !contentModel)
+ return;
+
+ QRectF geometry = q->boundingRect().adjusted(q->leftPadding(), q->topPadding(), -q->rightPadding(), -q->bottomPadding());
+ if (alignment != 0)
+ geometry = alignedRect(q->isMirrored() ? Qt::RightToLeft : Qt::LeftToRight, alignment, QSizeF(contentWidth, contentHeight), geometry);
+
+ contentItem->setPosition(geometry.topLeft());
+ contentItem->setSize(geometry.size());
+}
+
+void QQuickDialogButtonBoxPrivate::updateLayout()
+{
+ Q_Q(QQuickDialogButtonBox);
+ const int count = contentModel->count();
+ if (count <= 0)
+ return;
+
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ const int valign = alignment & Qt::AlignVertical_Mask;
+
+ QList<QQuickAbstractButton *> buttons;
+ const qreal cw = (alignment & Qt::AlignHorizontal_Mask) == 0 ? q->availableWidth() : contentWidth;
+ const qreal itemWidth = (cw - qMax(0, count - 1) * spacing) / count;
+
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid()) {
+ if (!halign)
+ item->setWidth(itemWidth);
+ else
+ item->resetWidth();
+ if (!valign)
+ item->setHeight(contentHeight);
+ else
+ item->resetHeight();
+ p->widthValidFlag = false;
+ }
+ }
+ buttons += static_cast<QQuickAbstractButton *>(item);
+ }
+
+ struct ButtonLayout {
+ ButtonLayout(QPlatformDialogHelper::ButtonLayout layout)
+ : m_layout(QPlatformDialogHelper::buttonLayout(Qt::Horizontal, layout))
+ {
+ }
+
+ bool operator()(QQuickAbstractButton *first, QQuickAbstractButton *second)
+ {
+ const QPlatformDialogHelper::ButtonRole firstRole = QQuickDialogPrivate::buttonRole(first);
+ const QPlatformDialogHelper::ButtonRole secondRole = QQuickDialogPrivate::buttonRole(second);
+
+ if (firstRole != secondRole && firstRole != QPlatformDialogHelper::InvalidRole && secondRole != QPlatformDialogHelper::InvalidRole) {
+ const int *l = m_layout;
+ while (*l != QPlatformDialogHelper::EOL) {
+ // Unset the Reverse flag.
+ const int role = (*l & ~QPlatformDialogHelper::Reverse);
+ if (role == firstRole)
+ return true;
+ if (role == secondRole)
+ return false;
+ ++l;
+ }
+ }
+
+ if (firstRole == secondRole)
+ return false;
+
+ return firstRole != QPlatformDialogHelper::InvalidRole;
+ }
+ const int *m_layout;
+ };
+
+ std::stable_sort(buttons.begin(), buttons.end(), ButtonLayout(static_cast<QPlatformDialogHelper::ButtonLayout>(buttonLayout)));
+
+ for (int i = 0; i < buttons.count() - 1; ++i)
+ q->insertItem(i, buttons.at(i));
+}
+
+qreal QQuickDialogButtonBoxPrivate::getContentWidth() const
+{
+ Q_Q(const QQuickDialogButtonBox);
+ if (!contentModel)
+ return 0;
+
+ const int count = contentModel->count();
+ const qreal totalSpacing = qMax(0, count - 1) * spacing;
+ qreal totalWidth = totalSpacing;
+ qreal maxWidth = 0;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ totalWidth += item->implicitWidth();
+ maxWidth = qMax(maxWidth, item->implicitWidth());
+ }
+ }
+ if ((alignment & Qt::AlignHorizontal_Mask) == 0)
+ totalWidth = qMax(totalWidth, count * maxWidth + totalSpacing);
+ return totalWidth;
+}
+
+qreal QQuickDialogButtonBoxPrivate::getContentHeight() const
+{
+ Q_Q(const QQuickDialogButtonBox);
+ if (!contentModel)
+ return 0;
+
+ const int count = contentModel->count();
+ qreal maxHeight = 0;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item)
+ maxHeight = qMax(maxHeight, item->implicitHeight());
+ }
+ return maxHeight;
+}
+
+void QQuickDialogButtonBoxPrivate::handleClick()
+{
+ Q_Q(QQuickDialogButtonBox);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
+ if (!button)
+ return;
+
+ // Can't fetch this *after* emitting clicked, as clicked may destroy the button
+ // or change its role. Now changing the role is not possible yet, but arguably
+ // both clicked and accepted/rejected/etc. should be emitted "atomically"
+ // depending on whatever role the button had at the time of the click.
+ const QPlatformDialogHelper::ButtonRole role = QQuickDialogPrivate::buttonRole(button);
+ QPointer<QQuickDialogButtonBox> guard(q);
+
+ emit q->clicked(button);
+
+ if (!guard)
+ return;
+
+ switch (role) {
+ case QPlatformDialogHelper::AcceptRole:
+ case QPlatformDialogHelper::YesRole:
+ emit q->accepted();
+ break;
+ case QPlatformDialogHelper::RejectRole:
+ case QPlatformDialogHelper::NoRole:
+ emit q->rejected();
+ break;
+ case QPlatformDialogHelper::ApplyRole:
+ emit q->applied();
+ break;
+ case QPlatformDialogHelper::ResetRole:
+ emit q->reset();
+ break;
+ case QPlatformDialogHelper::DestructiveRole:
+ emit q->discarded();
+ break;
+ case QPlatformDialogHelper::HelpRole:
+ emit q->helpRequested();
+ break;
+ default:
+ break;
+ }
+}
+
+QString QQuickDialogButtonBoxPrivate::buttonText(QPlatformDialogHelper::StandardButton standardButton)
+{
+ return QPlatformTheme::removeMnemonics(QGuiApplicationPrivate::platformTheme()->standardButtonText(standardButton));
+}
+
+QQuickAbstractButton *QQuickDialogButtonBoxPrivate::createStandardButton(QPlatformDialogHelper::StandardButton standardButton)
+{
+ Q_Q(QQuickDialogButtonBox);
+ if (!delegate)
+ return nullptr;
+
+ QQmlContext *creationContext = delegate->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext, q);
+ context->setContextObject(q);
+
+ QObject *object = delegate->beginCreate(context);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(object);
+ if (button) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, true));
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton = standardButton;
+ attached->setButtonRole(QPlatformDialogHelper::buttonRole(standardButton));
+ button->setText(buttonText(standardButton));
+ delegate->completeCreate();
+ button->setParent(q);
+ return button;
+ }
+
+ delete object;
+ return nullptr;
+}
+
+void QQuickDialogButtonBoxPrivate::removeStandardButtons()
+{
+ Q_Q(QQuickDialogButtonBox);
+ int i = q->count() - 1;
+ while (i >= 0) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->itemAt(i));
+ if (button) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(
+ qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
+ if (attached) {
+ QQuickDialogButtonBoxAttachedPrivate *p = QQuickDialogButtonBoxAttachedPrivate::get(attached);
+ if (p->standardButton != QPlatformDialogHelper::NoButton) {
+ q->removeItem(button);
+ button->deleteLater();
+ }
+ }
+ }
+ --i;
+ }
+}
+
+void QQuickDialogButtonBoxPrivate::updateLanguage()
+{
+ Q_Q(QQuickDialogButtonBox);
+ int i = q->count() - 1;
+ while (i >= 0) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(itemAt(i));
+ if (button) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(
+ qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, true));
+ const auto boxAttachedPrivate = QQuickDialogButtonBoxAttachedPrivate::get(attached);
+ const QPlatformDialogHelper::StandardButton standardButton = boxAttachedPrivate->standardButton;
+ // The button might be a custom one with explicitly specified text, so we shouldn't change it in that case.
+ if (standardButton != QPlatformDialogHelper::NoButton) {
+ button->setText(buttonText(standardButton));
+ }
+ }
+ --i;
+ }
+}
+
+QQuickDialogButtonBox::QQuickDialogButtonBox(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickDialogButtonBoxPrivate), parent)
+{
+ Q_D(QQuickDialogButtonBox);
+ d->changeTypes |= QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+ d->buttonLayout = platformButtonLayout();
+}
+
+QQuickDialogButtonBox::~QQuickDialogButtonBox()
+{
+ Q_D(QQuickDialogButtonBox);
+ // QQuickContainerPrivate does call this, but as our type information has already been
+ // destroyed by that point (since this destructor has already run), it won't call our
+ // implementation. So, we need to make sure our implementation is called. If we don't do this,
+ // the listener we installed on the contentItem won't get removed, possibly resulting in
+ // heap-use-after-frees.
+ contentItemChange(nullptr, d->contentItem);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::position
+
+ This property holds the position of the button box.
+
+ \note If the button box is assigned as a header or footer of ApplicationWindow
+ or Page, the appropriate position is set automatically.
+
+ Possible values:
+ \value DialogButtonBox.Header The button box is at the top, as a window or page header.
+ \value DialogButtonBox.Footer The button box is at the bottom, as a window or page header.
+
+ The default value is \c Footer.
+
+ \sa Dialog::header, Dialog::footer
+*/
+QQuickDialogButtonBox::Position QQuickDialogButtonBox::position() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->position;
+}
+
+void QQuickDialogButtonBox::setPosition(Position position)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->position == position)
+ return;
+
+ d->position = position;
+ emit positionChanged();
+}
+
+/*!
+ \qmlproperty flags QtQuick.Controls::DialogButtonBox::alignment
+
+ This property holds the alignment of the buttons.
+
+ Possible values:
+ \value undefined The buttons are resized to fill the available space.
+ \value Qt.AlignLeft The buttons are aligned to the left.
+ \value Qt.AlignHCenter The buttons are horizontally centered.
+ \value Qt.AlignRight The buttons are aligned to the right.
+ \value Qt.AlignTop The buttons are aligned to the top.
+ \value Qt.AlignVCenter The buttons are vertically centered.
+ \value Qt.AlignBottom The buttons are aligned to the bottom.
+*/
+Qt::Alignment QQuickDialogButtonBox::alignment() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->alignment;
+}
+
+void QQuickDialogButtonBox::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->alignment == alignment)
+ return;
+
+ d->alignment = alignment;
+ if (isComponentComplete()) {
+ d->resizeContent();
+ polish();
+ }
+ emit alignmentChanged();
+}
+
+void QQuickDialogButtonBox::resetAlignment()
+{
+ setAlignment({});
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::standardButtons
+
+ This property holds a combination of standard buttons that are used by the button box.
+
+ \snippet qtquickcontrols2-dialogbuttonbox.qml 1
+
+ The buttons will be positioned in the appropriate order for the user's platform.
+
+ Possible flags:
+ \value DialogButtonBox.Ok An "OK" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Open An "Open" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Save A "Save" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Cancel A "Cancel" button defined with the \c RejectRole.
+ \value DialogButtonBox.Close A "Close" button defined with the \c RejectRole.
+ \value DialogButtonBox.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
+ \value DialogButtonBox.Apply An "Apply" button defined with the \c ApplyRole.
+ \value DialogButtonBox.Reset A "Reset" button defined with the \c ResetRole.
+ \value DialogButtonBox.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
+ \value DialogButtonBox.Help A "Help" button defined with the \c HelpRole.
+ \value DialogButtonBox.SaveAll A "Save All" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Yes A "Yes" button defined with the \c YesRole.
+ \value DialogButtonBox.YesToAll A "Yes to All" button defined with the \c YesRole.
+ \value DialogButtonBox.No A "No" button defined with the \c NoRole.
+ \value DialogButtonBox.NoToAll A "No to All" button defined with the \c NoRole.
+ \value DialogButtonBox.Abort An "Abort" button defined with the \c RejectRole.
+ \value DialogButtonBox.Retry A "Retry" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Ignore An "Ignore" button defined with the \c AcceptRole.
+ \value DialogButtonBox.NoButton An invalid button.
+
+ \sa standardButton()
+*/
+QPlatformDialogHelper::StandardButtons QQuickDialogButtonBox::standardButtons() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->standardButtons;
+}
+
+void QQuickDialogButtonBox::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->standardButtons == buttons)
+ return;
+
+ d->removeStandardButtons();
+
+ for (int i = QPlatformDialogHelper::FirstButton; i <= QPlatformDialogHelper::LastButton; i<<=1) {
+ QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(i);
+ if (standardButton & buttons) {
+ QQuickAbstractButton *button = d->createStandardButton(standardButton);
+ if (button)
+ addItem(button);
+ }
+ }
+
+ if (isComponentComplete())
+ polish();
+
+ d->standardButtons = buttons;
+ emit standardButtonsChanged();
+}
+
+/*!
+ \qmlmethod AbstractButton QtQuick.Controls::DialogButtonBox::standardButton(StandardButton button)
+
+ Returns the specified standard \a button, or \c null if it does not exist.
+
+ \sa standardButtons
+*/
+QQuickAbstractButton *QQuickDialogButtonBox::standardButton(QPlatformDialogHelper::StandardButton button) const
+{
+ Q_D(const QQuickDialogButtonBox);
+ if (Q_UNLIKELY(!(d->standardButtons & button)))
+ return nullptr;
+ for (int i = 0, n = count(); i < n; ++i) {
+ QQuickAbstractButton *btn = qobject_cast<QQuickAbstractButton *>(d->itemAt(i));
+ if (Q_LIKELY(btn)) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(btn, false));
+ if (attached && QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton == button)
+ return btn;
+ }
+ }
+ return nullptr;
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::DialogButtonBox::delegate
+
+ This property holds a delegate for creating standard buttons.
+
+ \sa standardButtons
+*/
+QQmlComponent *QQuickDialogButtonBox::delegate() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->delegate;
+}
+
+void QQuickDialogButtonBox::setDelegate(QQmlComponent* delegate)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->delegate == delegate)
+ return;
+
+ delete d->delegate;
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+QQuickDialogButtonBoxAttached *QQuickDialogButtonBox::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickDialogButtonBoxAttached(object);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::buttonLayout
+
+ This property holds the button layout policy to be used when arranging the buttons contained in the button box.
+ The default value is platform-specific.
+
+ Available values:
+ \value DialogButtonBox.WinLayout Use a policy appropriate for applications on Windows.
+ \value DialogButtonBox.MacLayout Use a policy appropriate for applications on macOS.
+ \value DialogButtonBox.KdeLayout Use a policy appropriate for applications on KDE.
+ \value DialogButtonBox.GnomeLayout Use a policy appropriate for applications on GNOME.
+ \value DialogButtonBox.AndroidLayout Use a policy appropriate for applications on Android.
+*/
+QPlatformDialogHelper::ButtonLayout QQuickDialogButtonBox::buttonLayout() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->buttonLayout;
+}
+
+void QQuickDialogButtonBox::setButtonLayout(QPlatformDialogHelper::ButtonLayout layout)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->buttonLayout == layout)
+ return;
+
+ d->buttonLayout = layout;
+ if (isComponentComplete())
+ d->updateLayout();
+ emit buttonLayoutChanged();
+}
+
+void QQuickDialogButtonBox::resetButtonLayout()
+{
+ setButtonLayout(platformButtonLayout());
+}
+
+void QQuickDialogButtonBox::updatePolish()
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::updatePolish();
+ d->updateLayout();
+}
+
+bool QQuickDialogButtonBox::event(QEvent *e)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (e->type() == QEvent::LanguageChange)
+ d->updateLanguage();
+ return QQuickContainer::event(e);
+}
+
+void QQuickDialogButtonBox::componentComplete()
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::componentComplete();
+ d->updateLayout();
+}
+
+void QQuickDialogButtonBox::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::geometryChange(newGeometry, oldGeometry);
+ d->updateLayout();
+}
+
+void QQuickDialogButtonBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::contentItemChange(newItem, oldItem);
+ if (oldItem)
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+ if (newItem)
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+}
+
+bool QQuickDialogButtonBox::isContent(QQuickItem *item) const
+{
+ return qobject_cast<QQuickAbstractButton *>(item);
+}
+
+void QQuickDialogButtonBox::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickDialogButtonBox);
+ Q_UNUSED(index);
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
+ QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
+ if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(this);
+ d->updateImplicitContentSize();
+ if (isComponentComplete())
+ polish();
+}
+
+void QQuickDialogButtonBox::itemRemoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickDialogButtonBox);
+ Q_UNUSED(index);
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
+ if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(nullptr);
+ d->updateImplicitContentSize();
+ if (isComponentComplete())
+ polish();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickDialogButtonBox::accessibleRole() const
+{
+ return QAccessible::PageTabList;
+}
+#endif
+
+void QQuickDialogButtonBoxAttachedPrivate::setButtonBox(QQuickDialogButtonBox *box)
+{
+ Q_Q(QQuickDialogButtonBoxAttached);
+ if (buttonBox == box)
+ return;
+
+ buttonBox = box;
+ emit q->buttonBoxChanged();
+}
+
+QQuickDialogButtonBoxAttached::QQuickDialogButtonBoxAttached(QObject *parent)
+ : QObject(*(new QQuickDialogButtonBoxAttachedPrivate), parent)
+{
+ Q_D(QQuickDialogButtonBoxAttached);
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
+ while (parentItem && !d->buttonBox) {
+ d->buttonBox = qobject_cast<QQuickDialogButtonBox *>(parentItem);
+ parentItem = parentItem->parentItem();
+ }
+}
+
+/*!
+ \qmlattachedproperty DialogButtonBox QtQuick.Controls::DialogButtonBox::buttonBox
+ \readonly
+
+ This attached property holds the button box that manages this button, or
+ \c null if the button is not in a button box.
+*/
+QQuickDialogButtonBox *QQuickDialogButtonBoxAttached::buttonBox() const
+{
+ Q_D(const QQuickDialogButtonBoxAttached);
+ return d->buttonBox;
+}
+
+/*!
+ \qmlattachedproperty enumeration QtQuick.Controls::DialogButtonBox::buttonRole
+
+ This attached property holds the role of each button in a button box.
+
+ \snippet qtquickcontrols2-dialogbuttonbox-attached.qml 1
+
+ Available values:
+ \value DialogButtonBox.InvalidRole The button is invalid.
+ \value DialogButtonBox.AcceptRole Clicking the button causes the dialog to be accepted (e.g. \uicontrol OK).
+ \value DialogButtonBox.RejectRole Clicking the button causes the dialog to be rejected (e.g. \uicontrol Cancel).
+ \value DialogButtonBox.DestructiveRole Clicking the button causes a destructive change (e.g. for discarding changes) and closes the dialog.
+ \value DialogButtonBox.ActionRole Clicking the button causes changes to the elements within the dialog.
+ \value DialogButtonBox.HelpRole The button can be clicked to request help.
+ \value DialogButtonBox.YesRole The button is a "Yes"-like button.
+ \value DialogButtonBox.NoRole The button is a "No"-like button.
+ \value DialogButtonBox.ResetRole The button resets the dialog's fields to default values.
+ \value DialogButtonBox.ApplyRole The button applies current changes.
+*/
+QPlatformDialogHelper::ButtonRole QQuickDialogButtonBoxAttached::buttonRole() const
+{
+ Q_D(const QQuickDialogButtonBoxAttached);
+ return d->buttonRole;
+}
+
+void QQuickDialogButtonBoxAttached::setButtonRole(QPlatformDialogHelper::ButtonRole role)
+{
+ Q_D(QQuickDialogButtonBoxAttached);
+ if (d->buttonRole == role)
+ return;
+
+ d->buttonRole = role;
+ emit buttonRoleChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickdialogbuttonbox_p.cpp"
diff --git a/src/quicktemplates2/qquickdialogbuttonbox_p.h b/src/quicktemplates2/qquickdialogbuttonbox_p.h
new file mode 100644
index 0000000000..48e721e5cd
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOGBUTTONBOX_P_H
+#define QQUICKDIALOGBUTTONBOX_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickDialogButtonBoxPrivate;
+class QQuickDialogButtonBoxAttached;
+class QQuickDialogButtonBoxAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogButtonBox : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment RESET resetAlignment NOTIFY alignmentChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged FINAL)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(QPlatformDialogHelper::ButtonLayout buttonLayout READ buttonLayout WRITE setButtonLayout RESET resetButtonLayout NOTIFY buttonLayoutChanged FINAL REVISION(2, 5))
+ Q_FLAGS(QPlatformDialogHelper::StandardButtons)
+ QML_NAMED_ELEMENT(DialogButtonBox)
+ QML_ATTACHED(QQuickDialogButtonBoxAttached)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickDialogButtonBox(QQuickItem *parent = nullptr);
+ ~QQuickDialogButtonBox();
+
+ enum Position {
+ Header,
+ Footer
+ };
+ Q_ENUM(Position)
+
+ Position position() const;
+ void setPosition(Position position);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment alignment);
+ void resetAlignment();
+
+ QPlatformDialogHelper::StandardButtons standardButtons() const;
+ void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons);
+ Q_INVOKABLE QQuickAbstractButton *standardButton(QPlatformDialogHelper::StandardButton button) const;
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ static QQuickDialogButtonBoxAttached *qmlAttachedProperties(QObject *object);
+
+ // 2.5 (Qt 5.12)
+ Q_ENUMS(QPlatformDialogHelper::ButtonLayout)
+
+ QPlatformDialogHelper::ButtonLayout buttonLayout() const;
+ void setButtonLayout(QPlatformDialogHelper::ButtonLayout layout);
+ void resetButtonLayout();
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+ void helpRequested();
+ void clicked(QQuickAbstractButton *button);
+ void positionChanged();
+ void alignmentChanged();
+ void standardButtonsChanged();
+ void delegateChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void applied();
+ Q_REVISION(2, 3) void reset();
+ Q_REVISION(2, 3) void discarded();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void buttonLayoutChanged();
+
+protected:
+ void updatePolish() override;
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ bool isContent(QQuickItem *item) const override;
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+ bool event(QEvent *e) override;
+
+private:
+ Q_DISABLE_COPY(QQuickDialogButtonBox)
+ Q_DECLARE_PRIVATE(QQuickDialogButtonBox)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogButtonBoxAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickDialogButtonBox *buttonBox READ buttonBox NOTIFY buttonBoxChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::ButtonRole buttonRole READ buttonRole WRITE setButtonRole NOTIFY buttonRoleChanged FINAL)
+ Q_ENUMS(QPlatformDialogHelper::ButtonRole)
+
+public:
+ explicit QQuickDialogButtonBoxAttached(QObject *parent = nullptr);
+
+ QQuickDialogButtonBox *buttonBox() const;
+
+ QPlatformDialogHelper::ButtonRole buttonRole() const;
+ void setButtonRole(QPlatformDialogHelper::ButtonRole role);
+
+Q_SIGNALS:
+ void buttonBoxChanged();
+ void buttonRoleChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickDialogButtonBoxAttached)
+ Q_DECLARE_PRIVATE(QQuickDialogButtonBoxAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDialogButtonBox)
+QML_DECLARE_TYPEINFO(QQuickDialogButtonBox, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKDIALOGBUTTONBOX_P_H
diff --git a/src/quicktemplates2/qquickdialogbuttonbox_p_p.h b/src/quicktemplates2/qquickdialogbuttonbox_p_p.h
new file mode 100644
index 0000000000..5e08b2adf1
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox_p_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOGBUTTONBOX_P_P_H
+#define QQUICKDIALOGBUTTONBOX_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 <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogButtonBoxPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialogButtonBox)
+
+public:
+ static QQuickDialogButtonBoxPrivate *get(QQuickDialogButtonBox *box)
+ {
+ return box->d_func();
+ }
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void resizeContent() override;
+
+ void updateLayout();
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ void handleClick();
+
+ static QString buttonText(QPlatformDialogHelper::StandardButton standardButton);
+
+ QQuickAbstractButton *createStandardButton(QPlatformDialogHelper::StandardButton button);
+ void removeStandardButtons();
+
+ void updateLanguage();
+
+ Qt::Alignment alignment;
+ QQuickDialogButtonBox::Position position = QQuickDialogButtonBox::Footer;
+ QPlatformDialogHelper::StandardButtons standardButtons = QPlatformDialogHelper::NoButton;
+ QPlatformDialogHelper::ButtonLayout buttonLayout = QPlatformDialogHelper::UnknownLayout;
+ QQmlComponent *delegate = nullptr;
+};
+
+class QQuickDialogButtonBoxAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialogButtonBoxAttached)
+
+public:
+ static QQuickDialogButtonBoxAttachedPrivate *get(QQuickDialogButtonBoxAttached *q)
+ {
+ return q->d_func();
+ }
+
+ void setButtonBox(QQuickDialogButtonBox *box);
+
+ QQuickDialogButtonBox *buttonBox = nullptr;
+ QPlatformDialogHelper::ButtonRole buttonRole = QPlatformDialogHelper::InvalidRole;
+ QPlatformDialogHelper::StandardButton standardButton = QPlatformDialogHelper::NoButton;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDIALOGBUTTONBOX_P_P_H
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp
new file mode 100644
index 0000000000..1d89948b4d
--- /dev/null
+++ b/src/quicktemplates2/qquickdrawer.cpp
@@ -0,0 +1,822 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdrawer_p.h"
+#include "qquickdrawer_p_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickpopuppositioner_p_p.h"
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qquickanimation_p.h>
+#include <QtQuick/private/qquicktransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Drawer
+ \inherits Popup
+//! \instantiates QQuickDrawer
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-navigation
+ \ingroup qtquickcontrols2-popups
+ \brief Side panel that can be opened and closed using a swipe gesture.
+
+ Drawer provides a swipe-based side panel, similar to those often used in
+ touch interfaces to provide a central location for navigation.
+
+ \image qtquickcontrols2-drawer.gif
+
+ Drawer can be positioned at any of the four edges of the content item.
+ The drawer above is positioned against the left edge of the window. The
+ drawer is then opened by \e "dragging" it out from the left edge of the
+ window.
+
+ \code
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ id: window
+ visible: true
+
+ Drawer {
+ id: drawer
+ width: 0.66 * window.width
+ height: window.height
+
+ Label {
+ text: "Content goes here!"
+ anchors.centerIn: parent
+ }
+ }
+ }
+ \endcode
+
+ Drawer is a special type of popup that resides at one of the window \l {edge}{edges}.
+ By default, Drawer re-parents itself to the window \c overlay, and therefore operates
+ on window coordinates. It is also possible to manually set the \l{Popup::}{parent} to
+ something else to make the drawer operate in a specific coordinate space.
+
+ Drawer can be configured to cover only part of its window edge. The following example
+ illustrates how Drawer can be positioned to appear below a window header:
+
+ \code
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ id: window
+ visible: true
+
+ header: ToolBar { }
+
+ Drawer {
+ y: header.height
+ width: window.width * 0.6
+ height: window.height - header.height
+ }
+ }
+ \endcode
+
+ The \l position property determines how much of the drawer is visible, as
+ a value between \c 0.0 and \c 1.0. It is not possible to set the x-coordinate
+ (or horizontal margins) of a drawer at the left or right window edge, or the
+ y-coordinate (or vertical margins) of a drawer at the top or bottom window edge.
+
+ In the image above, the application's contents are \e "pushed" across the
+ screen. This is achieved by applying a translation to the contents:
+
+ \code
+ import QtQuick
+ import QtQuick.Controls
+
+ ApplicationWindow {
+ id: window
+ width: 200
+ height: 228
+ visible: true
+
+ Drawer {
+ id: drawer
+ width: 0.66 * window.width
+ height: window.height
+ }
+
+ Label {
+ id: content
+
+ text: "Aa"
+ font.pixelSize: 96
+ anchors.fill: parent
+ verticalAlignment: Label.AlignVCenter
+ horizontalAlignment: Label.AlignHCenter
+
+ transform: Translate {
+ x: drawer.position * content.width * 0.33
+ }
+ }
+ }
+ \endcode
+
+ If you would like the application's contents to stay where they are when
+ the drawer is opened, don't apply a translation.
+
+ Drawer can be configured as a non-closable persistent side panel by
+ making the Drawer \l {Popup::modal}{non-modal} and \l {interactive}
+ {non-interactive}. See the \l {Qt Quick Controls 2 - Side Panel}{Side Panel}
+ example for more details.
+
+ \note On some platforms, certain edges may be reserved for system
+ gestures and therefore cannot be used with Drawer. For example, the
+ top and bottom edges may be reserved for system notifications and
+ control centers on Android and iOS.
+
+ \sa SwipeView, {Customizing Drawer}, {Navigation Controls}, {Popup Controls}
+*/
+
+class QQuickDrawerPositioner : public QQuickPopupPositioner
+{
+public:
+ QQuickDrawerPositioner(QQuickDrawer *drawer) : QQuickPopupPositioner(drawer) { }
+
+ void reposition() override;
+};
+
+qreal QQuickDrawerPrivate::offsetAt(const QPointF &point) const
+{
+ qreal offset = positionAt(point) - position;
+
+ // don't jump when dragged open
+ if (offset > 0 && position > 0 && !contains(point))
+ offset = 0;
+
+ return offset;
+}
+
+qreal QQuickDrawerPrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickDrawer);
+ QQuickWindow *window = q->window();
+ if (!window)
+ return 0;
+
+ switch (edge) {
+ case Qt::TopEdge:
+ return point.y() / q->height();
+ case Qt::LeftEdge:
+ return point.x() / q->width();
+ case Qt::RightEdge:
+ return (window->width() - point.x()) / q->width();
+ case Qt::BottomEdge:
+ return (window->height() - point.y()) / q->height();
+ default:
+ return 0;
+ }
+}
+
+QQuickPopupPositioner *QQuickDrawerPrivate::getPositioner()
+{
+ Q_Q(QQuickDrawer);
+ if (!positioner)
+ positioner = new QQuickDrawerPositioner(q);
+ return positioner;
+}
+
+void QQuickDrawerPositioner::reposition()
+{
+ if (m_positioning)
+ return;
+
+ QQuickDrawer *drawer = static_cast<QQuickDrawer*>(popup());
+ QQuickWindow *window = drawer->window();
+ if (!window)
+ return;
+
+ const qreal position = drawer->position();
+ QQuickItem *popupItem = drawer->popupItem();
+ switch (drawer->edge()) {
+ case Qt::LeftEdge:
+ popupItem->setX((position - 1.0) * popupItem->width());
+ break;
+ case Qt::RightEdge:
+ popupItem->setX(window->width() - position * popupItem->width());
+ break;
+ case Qt::TopEdge:
+ popupItem->setY((position - 1.0) * popupItem->height());
+ break;
+ case Qt::BottomEdge:
+ popupItem->setY(window->height() - position * popupItem->height());
+ break;
+ }
+
+ QQuickPopupPositioner::reposition();
+}
+
+void QQuickDrawerPrivate::showOverlay()
+{
+ // managed in setPosition()
+}
+
+void QQuickDrawerPrivate::hideOverlay()
+{
+ // managed in setPosition()
+}
+
+void QQuickDrawerPrivate::resizeOverlay()
+{
+ if (!dimmer || !window)
+ return;
+
+ QRectF geometry(0, 0, window->width(), window->height());
+
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge) {
+ geometry.setY(popupItem->y());
+ geometry.setHeight(popupItem->height());
+ } else {
+ geometry.setX(popupItem->x());
+ geometry.setWidth(popupItem->width());
+ }
+
+ dimmer->setPosition(geometry.topLeft());
+ dimmer->setSize(geometry.size());
+}
+
+static bool isWithinDragMargin(const QQuickDrawer *drawer, const QPointF &pos)
+{
+ switch (drawer->edge()) {
+ case Qt::LeftEdge:
+ return pos.x() <= drawer->dragMargin();
+ case Qt::RightEdge:
+ return pos.x() >= drawer->window()->width() - drawer->dragMargin();
+ case Qt::TopEdge:
+ return pos.y() <= drawer->dragMargin();
+ case Qt::BottomEdge:
+ return pos.y() >= drawer->window()->height() - drawer->dragMargin();
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ return false;
+}
+
+bool QQuickDrawerPrivate::startDrag(QEvent *event)
+{
+ Q_Q(QQuickDrawer);
+ if (!window || !interactive || dragMargin < 0.0 || qFuzzyIsNull(dragMargin))
+ return false;
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ if (isWithinDragMargin(q, static_cast<QMouseEvent *>(event)->scenePosition())) {
+ prepareEnterTransition();
+ reposition();
+ return handleMouseEvent(window->contentItem(), static_cast<QMouseEvent *>(event));
+ }
+ break;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->points()) {
+ if (point.state() == QEventPoint::Pressed && isWithinDragMargin(q, point.scenePosition())) {
+ prepareEnterTransition();
+ reposition();
+ return handleTouchEvent(window->contentItem(), static_cast<QTouchEvent *>(event));
+ }
+ }
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static inline bool keepGrab(QQuickItem *item)
+{
+ return item->keepMouseGrab() || item->keepTouchGrab();
+}
+
+bool QQuickDrawerPrivate::grabMouse(QQuickItem *item, QMouseEvent *event)
+{
+ Q_Q(QQuickDrawer);
+ handleMouseEvent(item, event);
+
+ if (!window || !interactive || keepGrab(popupItem) || keepGrab(item))
+ return false;
+
+ const QPointF movePoint = event->scenePosition();
+
+ // Flickable uses a hard-coded threshold of 15 for flicking, and
+ // QStyleHints::startDragDistance for dragging. Drawer uses a bit
+ // larger threshold to avoid being too eager to steal touch (QTBUG-50045)
+ const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
+ bool overThreshold = false;
+ if (position > 0 || dragMargin > 0) {
+ const bool xOverThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, event, threshold);
+ const bool yOverThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, event, threshold);
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = xOverThreshold && !yOverThreshold;
+ else
+ overThreshold = yOverThreshold && !xOverThreshold;
+ }
+
+ // Don't be too eager to steal presses outside the drawer (QTBUG-53929)
+ if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !contains(movePoint)) {
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin;
+ else
+ overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
+ }
+
+ if (overThreshold) {
+ popupItem->grabMouse();
+ popupItem->setKeepMouseGrab(true);
+ offset = offsetAt(movePoint);
+ }
+
+ return overThreshold;
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event)
+{
+ Q_Q(QQuickDrawer);
+ bool handled = handleTouchEvent(item, event);
+
+ if (!window || !interactive || keepGrab(popupItem) || keepGrab(item) || !event->touchPointStates().testFlag(QEventPoint::Updated))
+ return handled;
+
+ bool overThreshold = false;
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (!acceptTouch(point) || point.state() != QEventPoint::Updated)
+ continue;
+
+ const QPointF movePoint = point.scenePosition();
+
+ // Flickable uses a hard-coded threshold of 15 for flicking, and
+ // QStyleHints::startDragDistance for dragging. Drawer uses a bit
+ // larger threshold to avoid being too eager to steal touch (QTBUG-50045)
+ const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
+ if (position > 0 || dragMargin > 0) {
+ const bool xOverThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, &point, threshold);
+ const bool yOverThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, &point, threshold);
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = xOverThreshold && !yOverThreshold;
+ else
+ overThreshold = yOverThreshold && !xOverThreshold;
+ }
+
+ // Don't be too eager to steal presses outside the drawer (QTBUG-53929)
+ if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !contains(movePoint)) {
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin;
+ else
+ overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
+ }
+
+ if (overThreshold) {
+ popupItem->grabTouchPoints(QList<int>() << touchId);
+ popupItem->setKeepTouchGrab(true);
+ offset = offsetAt(movePoint);
+ }
+ }
+
+ return overThreshold;
+}
+#endif
+
+static const qreal openCloseVelocityThreshold = 300;
+
+// Overrides QQuickPopupPrivate::blockInput, which is called by
+// QQuickPopupPrivate::handlePress/Move/Release, which we call in our own
+// handlePress/Move/Release overrides.
+// This implementation conflates two things: should the event going to the item get
+// modally blocked by us? Or should we accept the event and become the grabber?
+// Those are two fundamentally different questions for the drawer as a (usually)
+// interactive control.
+bool QQuickDrawerPrivate::blockInput(QQuickItem *item, const QPointF &point) const
+{
+ Q_Q(const QQuickDrawer);
+
+ // We want all events, if mouse/touch is already grabbed.
+ if (popupItem->keepMouseGrab() || popupItem->keepTouchGrab())
+ return true;
+
+ // Don't block input to drawer's children/content.
+ if (popupItem->isAncestorOf(item))
+ return false;
+
+ // Don't block outside a drawer's background dimming
+ if (dimmer && !dimmer->contains(dimmer->mapFromScene(point)))
+ return false;
+
+ // Accept all events within drag area.
+ if (isWithinDragMargin(q, point))
+ return true;
+
+ // Accept all other events if drawer is modal.
+ return modal;
+}
+
+bool QQuickDrawerPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ offset = 0;
+ velocityCalculator.startMeasuring(point, timestamp);
+
+ if (!QQuickPopupPrivate::handlePress(item, point, timestamp))
+ return interactive && popupItem == item;
+
+ return true;
+}
+
+bool QQuickDrawerPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ Q_Q(QQuickDrawer);
+ if (!QQuickPopupPrivate::handleMove(item, point, timestamp))
+ return false;
+
+ // limit/reset the offset to the edge of the drawer when pushed from the outside
+ if (qFuzzyCompare(position, qreal(1.0)) && !contains(point))
+ offset = 0;
+
+ bool isGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
+ if (isGrabbed)
+ q->setPosition(positionAt(point) - offset);
+
+ return isGrabbed;
+}
+
+bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ auto cleanup = qScopeGuard([this] {
+ popupItem->setKeepMouseGrab(false);
+ popupItem->setKeepTouchGrab(false);
+ pressPoint = QPointF();
+ touchId = -1;
+ });
+ if (pressPoint.isNull())
+ return false;
+ if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) {
+ velocityCalculator.reset();
+ return QQuickPopupPrivate::handleRelease(item, point, timestamp);
+ }
+
+ velocityCalculator.stopMeasuring(point, timestamp);
+
+ qreal velocity = 0;
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ velocity = velocityCalculator.velocity().x();
+ else
+ velocity = velocityCalculator.velocity().y();
+
+ // the velocity is calculated so that swipes from left to right
+ // and top to bottom have positive velocity, and swipes from right
+ // to left and bottom to top have negative velocity.
+ //
+ // - top/left edge: positive velocity opens, negative velocity closes
+ // - bottom/right edge: negative velocity opens, positive velocity closes
+ //
+ // => invert the velocity for bottom and right edges, for the threshold comparison below
+ if (edge == Qt::RightEdge || edge == Qt::BottomEdge)
+ velocity = -velocity;
+
+ if (position > 0.7 || velocity > openCloseVelocityThreshold) {
+ transitionManager.transitionEnter();
+ } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) {
+ transitionManager.transitionExit();
+ } else {
+ switch (edge) {
+ case Qt::LeftEdge:
+ if (point.x() - pressPoint.x() > 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::RightEdge:
+ if (point.x() - pressPoint.x() < 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::TopEdge:
+ if (point.y() - pressPoint.y() > 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::BottomEdge:
+ if (point.y() - pressPoint.y() < 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ }
+ }
+
+ // the cleanup() lambda will run before return
+ return popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
+}
+
+void QQuickDrawerPrivate::handleUngrab()
+{
+ QQuickPopupPrivate::handleUngrab();
+
+ velocityCalculator.reset();
+}
+
+static QList<QQuickStateAction> prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to)
+{
+ QList<QQuickStateAction> actions;
+ if (!transition || !QQuickPopupPrivate::get(drawer)->window || !transition->enabled())
+ return actions;
+
+ qmlExecuteDeferred(transition);
+
+ QQmlProperty defaultTarget(drawer, QLatin1String("position"));
+ QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
+ int count = animations.count(&animations);
+ for (int i = 0; i < count; ++i) {
+ QQuickAbstractAnimation *anim = animations.at(&animations, i);
+ anim->setDefaultTarget(defaultTarget);
+ }
+
+ actions << QQuickStateAction(drawer, QLatin1String("position"), to);
+ return actions;
+}
+
+bool QQuickDrawerPrivate::prepareEnterTransition()
+{
+ Q_Q(QQuickDrawer);
+ enterActions = prepareTransition(q, enter, 1.0);
+ return QQuickPopupPrivate::prepareEnterTransition();
+}
+
+bool QQuickDrawerPrivate::prepareExitTransition()
+{
+ Q_Q(QQuickDrawer);
+ exitActions = prepareTransition(q, exit, 0.0);
+ return QQuickPopupPrivate::prepareExitTransition();
+}
+
+bool QQuickDrawerPrivate::setEdge(Qt::Edge e)
+{
+ Q_Q(QQuickDrawer);
+ switch (e) {
+ case Qt::LeftEdge:
+ case Qt::RightEdge:
+ allowVerticalMove = true;
+ allowVerticalResize = true;
+ allowHorizontalMove = false;
+ allowHorizontalResize = false;
+ break;
+ case Qt::TopEdge:
+ case Qt::BottomEdge:
+ allowVerticalMove = false;
+ allowVerticalResize = false;
+ allowHorizontalMove = true;
+ allowHorizontalResize = true;
+ break;
+ default:
+ qmlWarning(q) << "invalid edge value - valid values are: "
+ << "Qt.TopEdge, Qt.LeftEdge, Qt.RightEdge, Qt.BottomEdge";
+ return false;
+ }
+
+ edge = e;
+ return true;
+}
+
+QQuickDrawer::QQuickDrawer(QObject *parent)
+ : QQuickPopup(*(new QQuickDrawerPrivate), parent)
+{
+ Q_D(QQuickDrawer);
+ d->dragMargin = QGuiApplication::styleHints()->startDragDistance();
+ d->setEdge(Qt::LeftEdge);
+
+ setFocus(true);
+ setModal(true);
+ setFiltersChildMouseEvents(true);
+ setClosePolicy(CloseOnEscape | CloseOnReleaseOutside);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Drawer::edge
+
+ This property holds the edge of the window at which the drawer will
+ open from. The acceptable values are:
+
+ \value Qt.TopEdge The top edge of the window.
+ \value Qt.LeftEdge The left edge of the window (default).
+ \value Qt.RightEdge The right edge of the window.
+ \value Qt.BottomEdge The bottom edge of the window.
+*/
+Qt::Edge QQuickDrawer::edge() const
+{
+ Q_D(const QQuickDrawer);
+ return d->edge;
+}
+
+void QQuickDrawer::setEdge(Qt::Edge edge)
+{
+ Q_D(QQuickDrawer);
+ if (d->edge == edge)
+ return;
+
+ if (!d->setEdge(edge))
+ return;
+
+ if (isComponentComplete())
+ d->reposition();
+ emit edgeChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Drawer::position
+
+ This property holds the position of the drawer relative to its final
+ destination. That is, the position will be \c 0.0 when the drawer
+ is fully closed, and \c 1.0 when fully open.
+*/
+qreal QQuickDrawer::position() const
+{
+ Q_D(const QQuickDrawer);
+ return d->position;
+}
+
+void QQuickDrawer::setPosition(qreal position)
+{
+ Q_D(QQuickDrawer);
+ position = qBound<qreal>(0.0, position, 1.0);
+ if (qFuzzyCompare(d->position, position))
+ return;
+
+ d->position = position;
+ if (isComponentComplete())
+ d->reposition();
+ if (d->dimmer)
+ d->dimmer->setOpacity(position);
+ emit positionChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Drawer::dragMargin
+
+ This property holds the distance from the screen edge within which
+ drag actions will open the drawer. Setting the value to \c 0 or less
+ prevents opening the drawer by dragging.
+
+ The default value is \c Qt.styleHints.startDragDistance.
+
+ \sa interactive
+*/
+qreal QQuickDrawer::dragMargin() const
+{
+ Q_D(const QQuickDrawer);
+ return d->dragMargin;
+}
+
+void QQuickDrawer::setDragMargin(qreal margin)
+{
+ Q_D(QQuickDrawer);
+ if (qFuzzyCompare(d->dragMargin, margin))
+ return;
+
+ d->dragMargin = margin;
+ emit dragMarginChanged();
+}
+
+void QQuickDrawer::resetDragMargin()
+{
+ setDragMargin(QGuiApplication::styleHints()->startDragDistance());
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::Drawer::interactive
+
+ This property holds whether the drawer is interactive. A non-interactive
+ drawer does not react to swipes.
+
+ The default value is \c true.
+
+ \sa dragMargin
+*/
+bool QQuickDrawer::isInteractive() const
+{
+ Q_D(const QQuickDrawer);
+ return d->interactive;
+}
+
+void QQuickDrawer::setInteractive(bool interactive)
+{
+ Q_D(QQuickDrawer);
+ if (d->interactive == interactive)
+ return;
+
+ setFiltersChildMouseEvents(interactive);
+ d->interactive = interactive;
+ emit interactiveChanged();
+}
+
+bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event)
+{
+ Q_D(QQuickDrawer);
+ switch (event->type()) {
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchUpdate:
+ return d->grabTouch(child, static_cast<QTouchEvent *>(event));
+ case QEvent::TouchBegin:
+ case QEvent::TouchEnd:
+ return d->handleTouchEvent(child, static_cast<QTouchEvent *>(event));
+#endif
+ case QEvent::MouseMove:
+ return d->grabMouse(child, static_cast<QMouseEvent *>(event));
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ return d->handleMouseEvent(child, static_cast<QMouseEvent *>(event));
+ default:
+ break;
+ }
+ return false;
+}
+
+void QQuickDrawer::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickDrawer);
+ d->grabMouse(d->popupItem, event);
+}
+
+bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event)
+{
+ Q_D(QQuickDrawer);
+ switch (event->type()) {
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchUpdate:
+ return d->grabTouch(item, static_cast<QTouchEvent *>(event));
+#endif
+ case QEvent::MouseMove:
+ return d->grabMouse(item, static_cast<QMouseEvent *>(event));
+ default:
+ break;
+ }
+ return QQuickPopup::overlayEvent(item, event);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickDrawer::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickDrawer);
+ d->grabTouch(d->popupItem, event);
+}
+#endif
+
+void QQuickDrawer::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickDrawer);
+ QQuickPopup::geometryChange(newGeometry, oldGeometry);
+ d->resizeOverlay();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickdrawer_p.cpp"
diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h
new file mode 100644
index 0000000000..f16ae771bb
--- /dev/null
+++ b/src/quicktemplates2/qquickdrawer_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDRAWER_P_H
+#define QQUICKDRAWER_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 <QtQuickTemplates2/private/qquickpopup_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDrawerPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDrawer : public QQuickPopup
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Edge edge READ edge WRITE setEdge NOTIFY edgeChanged FINAL)
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal dragMargin READ dragMargin WRITE setDragMargin RESET resetDragMargin NOTIFY dragMarginChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged FINAL REVISION(2, 2))
+ QML_NAMED_ELEMENT(Drawer)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickDrawer(QObject *parent = nullptr);
+
+ Qt::Edge edge() const;
+ void setEdge(Qt::Edge edge);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ qreal dragMargin() const;
+ void setDragMargin(qreal margin);
+ void resetDragMargin();
+
+ // 2.2 (Qt 5.9)
+ bool isInteractive() const;
+ void setInteractive(bool interactive);
+
+Q_SIGNALS:
+ void edgeChanged();
+ void positionChanged();
+ void dragMarginChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void interactiveChanged();
+
+protected:
+ bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ bool overlayEvent(QQuickItem *item, QEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private:
+ Q_DISABLE_COPY(QQuickDrawer)
+ Q_DECLARE_PRIVATE(QQuickDrawer)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDrawer)
+
+#endif // QQUICKDRAWER_P_H
diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h
new file mode 100644
index 0000000000..5f1086de97
--- /dev/null
+++ b/src/quicktemplates2/qquickdrawer_p_p.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDRAWER_P_P_H
+#define QQUICKDRAWER_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 <QtQuickTemplates2/private/qquickdrawer_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquickvelocitycalculator_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDrawerPrivate : public QQuickPopupPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDrawer)
+
+public:
+ static QQuickDrawerPrivate *get(QQuickDrawer *drawer)
+ {
+ return drawer->d_func();
+ }
+
+ qreal offsetAt(const QPointF &point) const;
+ qreal positionAt(const QPointF &point) const;
+
+ QQuickPopupPositioner *getPositioner() override;
+ void showOverlay() override;
+ void hideOverlay() override;
+ void resizeOverlay() override;
+
+ bool startDrag(QEvent *event);
+ bool grabMouse(QQuickItem *item, QMouseEvent *event);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ bool grabTouch(QQuickItem *item, QTouchEvent *event);
+#endif
+ bool blockInput(QQuickItem *item, const QPointF &point) const override;
+
+ bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ bool handleRelease(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ void handleUngrab() override;
+
+ bool prepareEnterTransition() override;
+ bool prepareExitTransition() override;
+
+ bool setEdge(Qt::Edge edge);
+
+ Qt::Edge edge = Qt::LeftEdge;
+ qreal offset = 0;
+ qreal position = 0;
+ qreal dragMargin = 0;
+ QQuickVelocityCalculator velocityCalculator;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDRAWER_P_P_H
diff --git a/src/quicktemplates2/qquickframe.cpp b/src/quicktemplates2/qquickframe.cpp
new file mode 100644
index 0000000000..8110e048e4
--- /dev/null
+++ b/src/quicktemplates2/qquickframe.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickframe_p.h"
+#include "qquickframe_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Frame
+ \inherits Pane
+//! \instantiates QQuickFrame
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \brief Visual frame for a logical group of controls.
+
+ Frame is used to layout a logical group of controls together within a
+ visual frame. Frame 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.
+
+ Items declared as children of a Frame are automatically parented to the
+ Frame's \l {Control::}{contentItem}. Items created dynamically need to be
+ explicitly parented to the contentItem.
+
+ If only a single item is used within a Frame, it will resize to fit the
+ implicit size of its contained item. This makes it particularly suitable
+ for use together with layouts.
+
+ \image qtquickcontrols2-frame.png
+
+ \snippet qtquickcontrols2-frame.qml 1
+
+ \sa {Customizing Frame}, {Container Controls}
+*/
+
+QQuickFrame::QQuickFrame(QQuickItem *parent)
+ : QQuickPane(*(new QQuickFramePrivate), parent)
+{
+}
+
+QQuickFrame::QQuickFrame(QQuickFramePrivate &dd, QQuickItem *parent)
+ : QQuickPane(dd, parent)
+{
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickFrame::accessibleRole() const
+{
+ return QAccessible::Border;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickframe_p.cpp"
diff --git a/src/quicktemplates2/qquickframe_p.h b/src/quicktemplates2/qquickframe_p.h
new file mode 100644
index 0000000000..f65e281406
--- /dev/null
+++ b/src/quicktemplates2/qquickframe_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFRAME_P_H
+#define QQUICKFRAME_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 <QtQuickTemplates2/private/qquickpane_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFramePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickFrame : public QQuickPane
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(Frame)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickFrame(QQuickItem *parent = nullptr);
+
+protected:
+ QQuickFrame(QQuickFramePrivate &dd, QQuickItem *parent);
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickFrame)
+ Q_DECLARE_PRIVATE(QQuickFrame)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickFrame)
+
+#endif // QQUICKFRAME_P_H
diff --git a/src/quicktemplates2/qquickframe_p_p.h b/src/quicktemplates2/qquickframe_p_p.h
new file mode 100644
index 0000000000..ad392dc3a7
--- /dev/null
+++ b/src/quicktemplates2/qquickframe_p_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKFRAME_P_P_H
+#define QQUICKFRAME_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 <QtQuickTemplates2/private/qquickpane_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFrame;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickFramePrivate : public QQuickPanePrivate
+{
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKFRAME_P_P_H
diff --git a/src/quicktemplates2/qquickgroupbox.cpp b/src/quicktemplates2/qquickgroupbox.cpp
new file mode 100644
index 0000000000..3962e2e700
--- /dev/null
+++ b/src/quicktemplates2/qquickgroupbox.cpp
@@ -0,0 +1,289 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickgroupbox_p.h"
+#include "qquickframe_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype GroupBox
+ \inherits Frame
+//! \instantiates QQuickGroupBox
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \brief Visual frame and title for a logical group of controls.
+
+ GroupBox is used to layout a logical group of controls together, within
+ a \l {title}{titled} visual frame. GroupBox 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.
+
+ Items declared as children of a GroupBox are automatically parented to the
+ GroupBox's \l {Control::}{contentItem}. Items created dynamically need to be
+ explicitly parented to the contentItem.
+
+ If only a single item is used within a GroupBox, it will resize to fit the
+ implicit size of its contained item. This makes it particularly suitable
+ for use together with layouts.
+
+ \image qtquickcontrols2-groupbox.png
+
+ \snippet qtquickcontrols2-groupbox.qml 1
+
+ \section2 Checkable GroupBox
+
+ Even though GroupBox has no built-in check box, it is straightforward
+ to create a checkable GroupBox by pairing it with a CheckBox.
+
+ \image qtquickcontrols2-groupbox-checkable.png
+
+ It is a common pattern to enable or disable the groupbox's children when
+ its checkbox is toggled on or off, but it is up to the application to decide
+ on the behavior of the checkbox.
+
+ \snippet qtquickcontrols2-groupbox-checkable.qml 1
+
+ \sa CheckBox, {Customizing GroupBox}, {Container Controls}
+*/
+
+class QQuickGroupBoxPrivate : public QQuickFramePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickGroupBox)
+
+public:
+ void cancelLabel();
+ void executeLabel(bool complete = false);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::GroupBox); }
+
+ QString title;
+ QQuickDeferredPointer<QQuickItem> label;
+};
+
+static inline QString labelName() { return QStringLiteral("label"); }
+
+void QQuickGroupBoxPrivate::cancelLabel()
+{
+ Q_Q(QQuickGroupBox);
+ quickCancelDeferred(q, labelName());
+}
+
+void QQuickGroupBoxPrivate::executeLabel(bool complete)
+{
+ Q_Q(QQuickGroupBox);
+ if (label.wasExecuted())
+ return;
+
+ if (!label || complete)
+ quickBeginDeferred(q, labelName(), label);
+ if (complete)
+ quickCompleteDeferred(q, labelName(), label);
+}
+
+void QQuickGroupBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickGroupBox);
+ QQuickFramePrivate::itemImplicitWidthChanged(item);
+ if (item == label)
+ emit q->implicitLabelWidthChanged();
+}
+
+void QQuickGroupBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickGroupBox);
+ QQuickFramePrivate::itemImplicitHeightChanged(item);
+ if (item == label)
+ emit q->implicitLabelHeightChanged();
+}
+
+QQuickGroupBox::QQuickGroupBox(QQuickItem *parent)
+ : QQuickFrame(*(new QQuickGroupBoxPrivate), parent)
+{
+}
+
+QQuickGroupBox::~QQuickGroupBox()
+{
+ Q_D(QQuickGroupBox);
+ d->removeImplicitSizeListener(d->label);
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::GroupBox::title
+
+ This property holds the title.
+
+ The title is typically displayed above the groupbox to
+ summarize its contents.
+*/
+QString QQuickGroupBox::title() const
+{
+ Q_D(const QQuickGroupBox);
+ return d->title;
+}
+
+void QQuickGroupBox::setTitle(const QString &title)
+{
+ Q_D(QQuickGroupBox);
+ if (d->title == title)
+ return;
+
+ d->title = title;
+ maybeSetAccessibleName(title);
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::GroupBox::label
+
+ This property holds the label item that visualizes \l title.
+
+ \sa {Customizing GroupBox}
+*/
+QQuickItem *QQuickGroupBox::label() const
+{
+ QQuickGroupBoxPrivate *d = const_cast<QQuickGroupBoxPrivate *>(d_func());
+ if (!d->label)
+ d->executeLabel();
+ return d->label;
+}
+
+void QQuickGroupBox::setLabel(QQuickItem *label)
+{
+ Q_D(QQuickGroupBox);
+ if (d->label == label)
+ return;
+
+ if (!d->label.isExecuting())
+ d->cancelLabel();
+
+ const qreal oldImplicitLabelWidth = implicitLabelWidth();
+ const qreal oldImplicitLabelHeight = implicitLabelHeight();
+
+ d->removeImplicitSizeListener(d->label);
+ QQuickControlPrivate::hideOldItem(d->label);
+ d->label = label;
+
+ if (label) {
+ if (!label->parentItem())
+ label->setParentItem(this);
+ d->addImplicitSizeListener(label);
+ }
+
+ if (!qFuzzyCompare(oldImplicitLabelWidth, implicitLabelWidth()))
+ emit implicitLabelWidthChanged();
+ if (!qFuzzyCompare(oldImplicitLabelHeight, implicitLabelHeight()))
+ emit implicitLabelHeightChanged();
+ if (!d->label.isExecuting())
+ emit labelChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::GroupBox::implicitLabelWidth
+ \readonly
+
+ This property holds the implicit label width.
+
+ The value is equal to \c {label ? label.implicitWidth : 0}.
+
+ \sa implicitLabelHeight
+*/
+qreal QQuickGroupBox::implicitLabelWidth() const
+{
+ Q_D(const QQuickGroupBox);
+ if (!d->label)
+ return 0;
+ return d->label->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::GroupBox::implicitLabelHeight
+ \readonly
+
+ This property holds the implicit label height.
+
+ The value is equal to \c {label ? label.implicitHeight : 0}.
+
+ \sa implicitLabelWidth
+*/
+qreal QQuickGroupBox::implicitLabelHeight() const
+{
+ Q_D(const QQuickGroupBox);
+ if (!d->label)
+ return 0;
+ return d->label->implicitHeight();
+}
+
+void QQuickGroupBox::componentComplete()
+{
+ Q_D(QQuickGroupBox);
+ d->executeLabel(true);
+ QQuickFrame::componentComplete();
+}
+
+QFont QQuickGroupBox::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::GroupBox);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickGroupBox::accessibleRole() const
+{
+ return QAccessible::Grouping;
+}
+
+void QQuickGroupBox::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickGroupBox);
+ QQuickFrame::accessibilityActiveChanged(active);
+
+ if (active)
+ maybeSetAccessibleName(d->title);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickgroupbox_p.cpp"
diff --git a/src/quicktemplates2/qquickgroupbox_p.h b/src/quicktemplates2/qquickgroupbox_p.h
new file mode 100644
index 0000000000..39e20494e9
--- /dev/null
+++ b/src/quicktemplates2/qquickgroupbox_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGROUPBOX_P_H
+#define QQUICKGROUPBOX_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 <QtQuickTemplates2/private/qquickframe_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickGroupBoxPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickGroupBox : public QQuickFrame
+{
+ Q_OBJECT
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ Q_PROPERTY(QQuickItem *label READ label WRITE setLabel NOTIFY labelChanged FINAL)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitLabelWidth READ implicitLabelWidth NOTIFY implicitLabelWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitLabelHeight READ implicitLabelHeight NOTIFY implicitLabelHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "background,contentItem,label")
+ QML_NAMED_ELEMENT(GroupBox)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickGroupBox(QQuickItem *parent = nullptr);
+ ~QQuickGroupBox();
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QQuickItem *label() const;
+ void setLabel(QQuickItem *label);
+
+ // 2.5 (Qt 5.12)
+ qreal implicitLabelWidth() const;
+ qreal implicitLabelHeight() const;
+
+Q_SIGNALS:
+ void titleChanged();
+ void labelChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void implicitLabelWidthChanged();
+ Q_REVISION(2, 5) void implicitLabelHeightChanged();
+
+protected:
+ void componentComplete() override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickGroupBox)
+ Q_DECLARE_PRIVATE(QQuickGroupBox)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickGroupBox)
+
+#endif // QQUICKGROUPBOX_P_H
diff --git a/src/quicktemplates2/qquickheaderview.cpp b/src/quicktemplates2/qquickheaderview.cpp
new file mode 100644
index 0000000000..94d5635ad1
--- /dev/null
+++ b/src/quicktemplates2/qquickheaderview.cpp
@@ -0,0 +1,524 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQuickTemplates2/private/qquickheaderview_p_p.h>
+#include <algorithm>
+
+/*!
+ \qmltype HorizontalHeaderView
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-containers
+ \inherits TableView
+ \brief Provides a horizontal header view to accompany a \l TableView.
+
+ A HorizontalHeaderView provides labeling of the columns of a \l TableView.
+ To add a horizontal header to a TableView, bind the
+ \l {HorizontalHeaderView::syncView} {syncView} property to the TableView:
+
+ \snippet qtquickcontrols2-headerview-simple.qml horizontal
+
+ The header displays data from the {syncView}'s model by default, but can
+ also have its own model. If the model is a QAbstractTableModel, then
+ the header will display the model's horizontal headerData(); otherwise,
+ the model's data().
+*/
+
+/*!
+ \qmltype VerticalHeaderView
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-containers
+ \inherits TableView
+ \brief Provides a vertical header view to accompany a \l TableView.
+
+ A VerticalHeaderView provides labeling of the rows of a \l TableView.
+ To add a vertical header to a TableView, bind the
+ \l {VerticalHeaderView::syncView} {syncView} property to the TableView:
+
+ \snippet qtquickcontrols2-headerview-simple.qml vertical
+
+ The header displays data from the {syncView}'s model by default, but can
+ also have its own model. If the model is a QAbstractTableModel, then
+ the header will display the model's vertical headerData(); otherwise,
+ the model's data().
+*/
+
+/*!
+ \qmlproperty TableView QtQuick::HorizontalHeaderView::syncView
+
+ This property holds the TableView to synchronize with.
+
+ Once this property is bound to another TableView, both header and table
+ will synchronize with regard to column widths, column spacing, and flicking
+ horizontally.
+
+ If the \l model is not explicitly set, then the header will use the syncView's
+ model to label the columns.
+
+ \sa model TableView
+*/
+
+/*!
+ \qmlproperty TableView QtQuick::VerticalHeaderView::syncView
+
+ This property holds the TableView to synchronize with.
+
+ Once this property is bound to another TableView, both header and table
+ will synchronize with regard to row heights, row spacing, and flicking
+ vertically.
+
+ If the \l model is not explicitly set, then the header will use the syncView's
+ model to label the rows.
+
+ \sa model TableView
+*/
+
+/*!
+ \qmlproperty QVariant QtQuick::HorizontalHeaderView::model
+
+ This property holds the model providing data for the horizontal header view.
+
+ When model is not explicitly set, the header will use the syncView's
+ model once syncView is set.
+
+ If model is a QAbstractTableModel, its horizontal headerData() will
+ be accessed.
+
+ If model is a QAbstractItemModel other than QAbstractTableModel, model's data()
+ will be accessed.
+
+ Otherwise, the behavior is same as setting TableView::model.
+
+ \sa TableView {TableView::model} {model} QAbstractTableModel
+*/
+
+/*!
+ \qmlproperty QVariant QtQuick::VerticalHeaderView::model
+
+ This property holds the model providing data for the vertical header view.
+
+ When model is not explicitly set, it will be synchronized with syncView's model
+ once syncView is set.
+
+ If model is a QAbstractTableModel, its vertical headerData() will
+ be accessed.
+
+ If model is a QAbstractItemModel other than QAbstractTableModel, model's data()
+ will be accessed.
+
+ Otherwise, the behavior is same as setting TableView::model.
+
+ \sa TableView {TableView::model} {model} QAbstractTableModel
+*/
+
+/*!
+ \qmlproperty QString QtQuick::HorizontalHeaderView::textRole
+
+ This property holds the model role used to display text in each header cell.
+
+ When the model has multiple roles, textRole can be set to determine which
+ role should be displayed.
+
+ If model is a QAbstractItemModel then it will default to "display"; otherwise
+ it is empty.
+
+ \sa QAbstractItemModel::roleNames()
+*/
+
+/*!
+ \qmlproperty QString QtQuick::VerticalHeaderView::textRole
+
+ This property holds the model role used to display text in each header cell.
+
+ When the model has multiple roles, textRole can be set to determine which
+ role should be displayed.
+
+ If model is a QAbstractItemModel then it will default to "display"; otherwise
+ it is empty.
+
+ \sa QAbstractItemModel::roleNames()
+*/
+
+QT_BEGIN_NAMESPACE
+
+QQuickHeaderViewBasePrivate::QQuickHeaderViewBasePrivate()
+ : QQuickTableViewPrivate()
+{
+}
+
+QQuickHeaderViewBasePrivate::~QQuickHeaderViewBasePrivate()
+{
+}
+
+const QPointer<QQuickItem> QQuickHeaderViewBasePrivate::delegateItemAt(int row, int col) const
+{
+ return loadedTableItem(QPoint(col, row))->item;
+}
+
+QVariant QQuickHeaderViewBasePrivate::modelImpl() const
+{
+ if (auto model = m_headerDataProxyModel.sourceModel())
+ return QVariant::fromValue(model.data());
+ if (auto model = m_transposeProxyModel.sourceModel())
+ return QVariant::fromValue(model);
+ return QQuickTableViewPrivate::modelImpl();
+}
+
+template <typename P, typename M>
+inline bool proxyModelSetter(QQuickHeaderViewBase *const q, P &proxyModel, M *model)
+{
+ if (model) {
+ if (model == proxyModel.sourceModel())
+ return true;
+ proxyModel.setSourceModel(model);
+ const auto &modelVariant = QVariant::fromValue(std::addressof(proxyModel));
+ bool isProxyModelChanged = (modelVariant != QQuickTableViewPrivate::get(q)->QQuickTableViewPrivate::modelImpl());
+ QQuickTableViewPrivate::get(q)->QQuickTableViewPrivate::setModelImpl(modelVariant);
+ //Necessary, since TableView's assigned model not changed, but proxy's source changed
+ if (!isProxyModelChanged)
+ emit q->modelChanged();
+ return true;
+ }
+ proxyModel.setSourceModel(nullptr);
+ return false;
+}
+
+void QQuickHeaderViewBasePrivate::setModelImpl(const QVariant &newModel)
+{
+ Q_Q(QQuickHeaderViewBase);
+ m_modelExplicitlySetByUser = true;
+ // Case 1: newModel is QAbstractTableModel
+ if (proxyModelSetter(q, m_headerDataProxyModel, newModel.value<QAbstractTableModel *>()))
+ return;
+ // Case 2: newModel is QAbstractItemModel but not QAbstractTableModel
+ if (orientation() == Qt::Horizontal
+ && proxyModelSetter(q, m_transposeProxyModel, newModel.value<QAbstractItemModel *>()))
+ return;
+
+ QQuickTableViewPrivate::setModelImpl(newModel);
+}
+
+void QQuickHeaderViewBasePrivate::syncModel()
+{
+ Q_Q(QQuickHeaderViewBase);
+
+ if (assignedSyncView && !m_modelExplicitlySetByUser) {
+ auto newModel = assignedSyncView->model();
+ if (auto m = newModel.value<QAbstractItemModel *>())
+ proxyModelSetter(q, m_headerDataProxyModel, m);
+ }
+
+ QQuickTableViewPrivate::syncModel();
+
+ isTransposed = false;
+ const auto aim = model->abstractItemModel();
+ if (orientation() == Qt::Horizontal) {
+ // For models that are just a list or a number, and especially not a
+ // table, we transpose the view when the orientation is horizontal.
+ // The model (list) will then be laid out horizontally rather than
+ // vertically, which is the otherwise the default.
+ isTransposed = !aim || aim->columnCount() == 1;
+ }
+ if (m_textRole.isEmpty() && aim)
+ m_textRole = QLatin1String("display");
+}
+
+void QQuickHeaderViewBasePrivate::syncSyncView()
+{
+ Q_Q(QQuickHeaderViewBase);
+ if (assignedSyncDirection != orientation()) {
+ qmlWarning(q_func()) << "Setting syncDirection other than Qt::"
+ << QVariant::fromValue(orientation()).toString()
+ << " is invalid.";
+ assignedSyncDirection = orientation();
+ }
+ if (assignedSyncView) {
+ QBoolBlocker fixupGuard(inUpdateContentSize, true);
+ if (orientation() == Qt::Horizontal) {
+ q->setLeftMargin(assignedSyncView->leftMargin());
+ q->setRightMargin(assignedSyncView->rightMargin());
+ } else {
+ q->setTopMargin(assignedSyncView->topMargin());
+ q->setBottomMargin(assignedSyncView->bottomMargin());
+ }
+ }
+ QQuickTableViewPrivate::syncSyncView();
+}
+
+QQuickHeaderViewBase::QQuickHeaderViewBase(Qt::Orientation orient, QQuickItem *parent)
+ : QQuickTableView(*(new QQuickHeaderViewBasePrivate), parent)
+{
+ d_func()->setOrientation(orient);
+ setSyncDirection(orient);
+}
+
+QQuickHeaderViewBase::QQuickHeaderViewBase(QQuickHeaderViewBasePrivate &dd, QQuickItem *parent)
+ : QQuickTableView(dd, parent)
+{
+}
+
+QQuickHeaderViewBase::~QQuickHeaderViewBase()
+{
+}
+
+QString QQuickHeaderViewBase::textRole() const
+{
+ Q_D(const QQuickHeaderViewBase);
+ return d->m_textRole;
+}
+
+void QQuickHeaderViewBase::setTextRole(const QString &role)
+{
+ Q_D(QQuickHeaderViewBase);
+ if (d->m_textRole == role)
+ return;
+
+ d->m_textRole = role;
+ emit textRoleChanged();
+}
+
+Qt::Orientation QQuickHeaderViewBasePrivate::orientation() const
+{
+ return m_headerDataProxyModel.orientation();
+}
+
+void QQuickHeaderViewBasePrivate::setOrientation(Qt::Orientation orientation)
+{
+ if (QQuickHeaderViewBasePrivate::orientation() == orientation)
+ return;
+ m_headerDataProxyModel.setOrientation(orientation);
+}
+
+QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickVerticalHeaderViewPrivate &dd, QQuickItem *parent)
+ : QQuickHeaderViewBase(dd, parent)
+{
+}
+
+/*! \internal
+ \class QHeaderDataProxyModel
+ \brief
+ QHeaderDataProxyModel is a proxy AbstractItemModel type that maps
+ source model's headerData() to correspondent data()
+ */
+QHeaderDataProxyModel::QHeaderDataProxyModel(QObject *parent)
+ : QAbstractItemModel(parent)
+{
+}
+
+QHeaderDataProxyModel::~QHeaderDataProxyModel() = default;
+
+void QHeaderDataProxyModel::setSourceModel(QAbstractItemModel *newSourceModel)
+{
+ if (m_model == newSourceModel)
+ return;
+ beginResetModel();
+ disconnectFromModel();
+ m_model = newSourceModel;
+ connectToModel();
+ endResetModel();
+}
+
+QModelIndex QHeaderDataProxyModel::index(int row, int column, const QModelIndex &parent) const
+{
+ return hasIndex(row, column, parent) ? createIndex(row, column) : QModelIndex();
+}
+
+QModelIndex QHeaderDataProxyModel::parent(const QModelIndex &child) const
+{
+ Q_UNUSED(child);
+ return QModelIndex();
+}
+
+QModelIndex QHeaderDataProxyModel::sibling(int row, int column, const QModelIndex &) const
+{
+ return index(row, column);
+}
+
+int QHeaderDataProxyModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_model.isNull() ? -1 : (m_orientation == Qt::Horizontal ? 1 : m_model->rowCount(parent));
+}
+
+int QHeaderDataProxyModel::columnCount(const QModelIndex &parent) const
+{
+ if (parent.isValid())
+ return 0;
+ return m_model.isNull() ? -1 : (m_orientation == Qt::Vertical ? 1 : m_model->columnCount(parent));
+}
+
+QVariant QHeaderDataProxyModel::data(const QModelIndex &index, int role) const
+{
+ if (m_model.isNull())
+ return QVariant();
+ if (!hasIndex(index.row(), index.column()))
+ return QModelIndex();
+ auto section = m_orientation == Qt::Vertical ? index.row() : index.column();
+ return m_model->headerData(section, m_orientation, role);
+}
+
+bool QHeaderDataProxyModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!hasIndex(index.row(), index.column()))
+ return false;
+ auto section = m_orientation == Qt::Vertical ? index.row() : index.column();
+ auto ret = m_model->setHeaderData(section, m_orientation, value, role);
+ emit dataChanged(index, index, { role });
+ return ret;
+}
+
+bool QHeaderDataProxyModel::hasChildren(const QModelIndex &parent) const
+{
+ if (!parent.isValid())
+ return rowCount(parent) > 0 && columnCount(parent) > 0;
+ return false;
+}
+
+QVariant QHeaderDataProxyModel::variantValue() const
+{
+ return QVariant::fromValue(static_cast<QObject *>(const_cast<QHeaderDataProxyModel *>(this)));
+}
+
+void QHeaderDataProxyModel::setOrientation(Qt::Orientation o)
+{
+ if (o == m_orientation)
+ return;
+ beginResetModel();
+ m_orientation = o;
+ endResetModel();
+}
+
+Qt::Orientation QHeaderDataProxyModel::orientation() const
+{
+ return m_orientation;
+}
+
+QPointer<QAbstractItemModel> QHeaderDataProxyModel::sourceModel() const
+{
+ return m_model;
+}
+
+void QHeaderDataProxyModel::connectToModel()
+{
+ if (m_model.isNull())
+ return;
+ connect(m_model, &QAbstractItemModel::headerDataChanged,
+ this, [this](Qt::Orientation orient, int first, int last) {
+ if (orient != orientation())
+ return;
+ if (orient == Qt::Horizontal) {
+ emit dataChanged(createIndex(0, first), createIndex(0, last));
+ } else {
+ emit dataChanged(createIndex(first, 0), createIndex(last, 0));
+ }
+ });
+ connect(m_model, &QAbstractItemModel::modelAboutToBeReset,
+ this, &QHeaderDataProxyModel::modelAboutToBeReset, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::modelReset,
+ this, &QHeaderDataProxyModel::modelReset, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeMoved,
+ this, &QHeaderDataProxyModel::rowsAboutToBeMoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsMoved,
+ this, &QHeaderDataProxyModel::rowsMoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeInserted,
+ this, &QHeaderDataProxyModel::rowsAboutToBeInserted, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &QHeaderDataProxyModel::rowsInserted, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &QHeaderDataProxyModel::rowsAboutToBeRemoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::rowsRemoved,
+ this, &QHeaderDataProxyModel::rowsRemoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsAboutToBeMoved,
+ this, &QHeaderDataProxyModel::columnsAboutToBeMoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsMoved,
+ this, &QHeaderDataProxyModel::columnsMoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsAboutToBeInserted,
+ this, &QHeaderDataProxyModel::columnsAboutToBeInserted, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsInserted,
+ this, &QHeaderDataProxyModel::columnsInserted, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsAboutToBeRemoved,
+ this, &QHeaderDataProxyModel::columnsAboutToBeRemoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::columnsRemoved,
+ this, &QHeaderDataProxyModel::columnsRemoved, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::layoutAboutToBeChanged,
+ this, &QHeaderDataProxyModel::layoutAboutToBeChanged, Qt::UniqueConnection);
+ connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &QHeaderDataProxyModel::layoutChanged, Qt::UniqueConnection);
+}
+
+void QHeaderDataProxyModel::disconnectFromModel()
+{
+ if (m_model.isNull())
+ return;
+ m_model->disconnect(this);
+}
+
+QQuickHorizontalHeaderView::QQuickHorizontalHeaderView(QQuickItem *parent)
+ : QQuickHeaderViewBase(Qt::Horizontal, parent)
+{
+ setFlickableDirection(FlickableDirection::HorizontalFlick);
+}
+
+QQuickHorizontalHeaderView::~QQuickHorizontalHeaderView()
+{
+}
+
+QQuickVerticalHeaderView::QQuickVerticalHeaderView(QQuickItem *parent)
+ : QQuickHeaderViewBase(Qt::Vertical, parent)
+{
+ setFlickableDirection(FlickableDirection::VerticalFlick);
+}
+
+QQuickVerticalHeaderView::~QQuickVerticalHeaderView()
+{
+}
+
+QQuickHorizontalHeaderViewPrivate::QQuickHorizontalHeaderViewPrivate() = default;
+
+QQuickHorizontalHeaderViewPrivate::~QQuickHorizontalHeaderViewPrivate() = default;
+
+QQuickVerticalHeaderViewPrivate::QQuickVerticalHeaderViewPrivate() = default;
+
+QQuickVerticalHeaderViewPrivate::~QQuickVerticalHeaderViewPrivate() = default;
+
+QT_END_NAMESPACE
+
+#include "moc_qquickheaderview_p_p.cpp"
+
+#include "moc_qquickheaderview_p.cpp"
diff --git a/src/quicktemplates2/qquickheaderview_p.h b/src/quicktemplates2/qquickheaderview_p.h
new file mode 100644
index 0000000000..b8e8b77aa7
--- /dev/null
+++ b/src/quicktemplates2/qquickheaderview_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKHEADERVIEW_P_H
+#define QQUICKHEADERVIEW_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 <private/qquicktableview_p.h>
+#include <private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickHeaderViewBase;
+class QQuickHeaderViewBasePrivate;
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickHeaderViewBase : public QQuickTableView
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickHeaderViewBase)
+ Q_PROPERTY(QString textRole READ textRole WRITE setTextRole NOTIFY textRoleChanged FINAL)
+
+public:
+ explicit QQuickHeaderViewBase(Qt::Orientation orient, QQuickItem *parent = nullptr);
+ ~QQuickHeaderViewBase();
+
+ QString textRole() const;
+ void setTextRole(const QString &role);
+
+protected:
+ QQuickHeaderViewBase(QQuickHeaderViewBasePrivate &dd, QQuickItem *parent);
+
+Q_SIGNALS:
+ void textRoleChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickHeaderViewBase)
+ friend class QQuickHorizontalHeaderView;
+ friend class QQuickVerticalHeaderView;
+};
+
+class QQuickHorizontalHeaderViewPrivate;
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickHorizontalHeaderView : public QQuickHeaderViewBase
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickHorizontalHeaderView)
+ QML_NAMED_ELEMENT(HorizontalHeaderView)
+ QML_ADDED_IN_VERSION(2, 15)
+
+public:
+ QQuickHorizontalHeaderView(QQuickItem *parent = nullptr);
+ ~QQuickHorizontalHeaderView() override;
+
+protected:
+ QQuickHorizontalHeaderView(QQuickHorizontalHeaderViewPrivate &dd, QQuickItem *parent);
+
+private:
+ Q_DISABLE_COPY(QQuickHorizontalHeaderView)
+};
+
+class QQuickVerticalHeaderViewPrivate;
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickVerticalHeaderView : public QQuickHeaderViewBase
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QQuickVerticalHeaderView)
+ QML_NAMED_ELEMENT(VerticalHeaderView)
+ QML_ADDED_IN_VERSION(2, 15)
+
+public:
+ QQuickVerticalHeaderView(QQuickItem *parent = nullptr);
+ ~QQuickVerticalHeaderView() override;
+
+protected:
+ QQuickVerticalHeaderView(QQuickVerticalHeaderViewPrivate &dd, QQuickItem *parent);
+
+private:
+ Q_DISABLE_COPY(QQuickVerticalHeaderView)
+};
+
+struct QQuickTableViewForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickTableView)
+ QML_ADDED_IN_VERSION(2, 14)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickHorizontalHeaderView)
+QML_DECLARE_TYPE(QQuickVerticalHeaderView)
+
+#endif // QQUICKHEADERVIEW_P_H
diff --git a/src/quicktemplates2/qquickheaderview_p_p.h b/src/quicktemplates2/qquickheaderview_p_p.h
new file mode 100644
index 0000000000..655c2a58e6
--- /dev/null
+++ b/src/quicktemplates2/qquickheaderview_p_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKHEADERVIEW_P_P_H
+#define QQUICKHEADERVIEW_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 <QtCore/QAbstractItemModel>
+#include <QtCore/QPointer>
+#include <QtCore/QTransposeProxyModel>
+#include <QtQuick/private/qquicktableview_p_p.h>
+#include <private/qquickheaderview_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QHeaderDataProxyModel : public QAbstractItemModel
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(QHeaderDataProxyModel)
+ Q_PROPERTY(QAbstractItemModel *sourceModel READ sourceModel)
+public:
+ explicit QHeaderDataProxyModel(QObject *parent = nullptr);
+ ~QHeaderDataProxyModel();
+
+ void setSourceModel(QAbstractItemModel *newSourceModel);
+ QPointer<QAbstractItemModel> sourceModel() const;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &child) const override;
+ QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
+
+ inline QVariant variantValue() const;
+ inline Qt::Orientation orientation() const;
+ inline void setOrientation(Qt::Orientation o);
+
+private:
+ inline void connectToModel();
+ inline void disconnectFromModel();
+ QPointer<QAbstractItemModel> m_model = nullptr;
+ Qt::Orientation m_orientation = Qt::Horizontal;
+};
+
+class QQuickHeaderViewBasePrivate : public QQuickTableViewPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickHeaderViewBase)
+public:
+ QQuickHeaderViewBasePrivate();
+ ~QQuickHeaderViewBasePrivate();
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+ const QPointer<QQuickItem> delegateItemAt(int row, int col) const;
+ QVariant modelImpl() const override;
+ void setModelImpl(const QVariant &newModel) override;
+ void syncModel() override;
+ void syncSyncView() override;
+
+protected:
+ QHeaderDataProxyModel m_headerDataProxyModel;
+ QTransposeProxyModel m_transposeProxyModel;
+ struct SectionSize
+ {
+ int section;
+ qreal previousSize;
+ };
+ QStack<SectionSize> m_hiddenSectionSizes;
+ bool m_modelExplicitlySetByUser = false;
+ QString m_textRole;
+};
+
+class QQuickHorizontalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickHorizontalHeaderView)
+public:
+ QQuickHorizontalHeaderViewPrivate();
+ ~QQuickHorizontalHeaderViewPrivate();
+};
+
+class QQuickVerticalHeaderViewPrivate : public QQuickHeaderViewBasePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickVerticalHeaderView)
+public:
+ QQuickVerticalHeaderViewPrivate();
+ ~QQuickVerticalHeaderViewPrivate();
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKHEADERVIEW_P_P_H
diff --git a/src/quicktemplates2/qquickicon.cpp b/src/quicktemplates2/qquickicon.cpp
new file mode 100644
index 0000000000..88d957f40d
--- /dev/null
+++ b/src/quicktemplates2/qquickicon.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickicon_p.h"
+#include "qtaggedpointer.h"
+
+#include <private/qqmlcontextdata_p.h>
+#include <private/qqmldata_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIconPrivate : public QSharedData
+{
+public:
+ // This is based on QFont's resolve_mask.
+ enum ResolveProperties {
+ NameResolved = 0x0001,
+ SourceResolved = 0x0002,
+ WidthResolved = 0x0004,
+ HeightResolved = 0x0008,
+ ColorResolved = 0x0010,
+ CacheResolved = 0x0020,
+ AllPropertiesResolved = 0x1ffff
+ };
+ int resolveMask = 0;
+
+ QString name;
+ QUrl source;
+ QUrl resolvedSource;
+ int width = 0;
+ int height = 0;
+ QColor color = Qt::transparent;
+
+ // we want DoCache as the default, and thus as the zero value
+ // so that the tagged pointer can be zero initialized
+ enum CacheStatus : bool { DoCache, SkipCaching };
+ static_assert (DoCache == 0);
+ /* We use a QTaggedPointer here to save space:
+ - Without it, we would need an additional boolean, which due to
+ alignment would increase the class size by sizeof(void *)
+ - The pointer part stores the "owner" of the QQuickIcon, i.e.
+ an object which has an icon property. We need the owner to
+ access its context to resolve relative url's in the way users
+ expect.
+ - The tag bits are used to track whether caching is enabled.
+ */
+ QTaggedPointer<QObject, CacheStatus> ownerAndCache = nullptr;
+
+};
+
+QQuickIcon::QQuickIcon()
+ : d(new QQuickIconPrivate)
+{
+}
+
+QQuickIcon::QQuickIcon(const QQuickIcon &other)
+ : d(other.d)
+{
+}
+
+QQuickIcon::~QQuickIcon()
+{
+}
+
+QQuickIcon &QQuickIcon::operator=(const QQuickIcon &other)
+{
+ d = other.d;
+ return *this;
+}
+
+bool QQuickIcon::operator==(const QQuickIcon &other) const
+{
+ return d == other.d || (d->name == other.d->name
+ && d->source == other.d->source
+ && d->resolvedSource == other.d->resolvedSource
+ && d->width == other.d->width
+ && d->height == other.d->height
+ && d->color == other.d->color
+ && d->ownerAndCache == other.d->ownerAndCache);
+}
+
+bool QQuickIcon::operator!=(const QQuickIcon &other) const
+{
+ return !(*this == other);
+}
+
+bool QQuickIcon::isEmpty() const
+{
+ return d->name.isEmpty() && d->source.isEmpty();
+}
+
+QString QQuickIcon::name() const
+{
+ return d->name;
+}
+
+void QQuickIcon::setName(const QString &name)
+{
+ if ((d->resolveMask & QQuickIconPrivate::NameResolved) && d->name == name)
+ return;
+
+ d.detach();
+ d->name = name;
+ d->resolveMask |= QQuickIconPrivate::NameResolved;
+}
+
+void QQuickIcon::resetName()
+{
+ d.detach();
+ d->name = QString();
+ d->resolveMask &= ~QQuickIconPrivate::NameResolved;
+}
+
+QUrl QQuickIcon::source() const
+{
+ return d->source;
+}
+
+void QQuickIcon::setSource(const QUrl &source)
+{
+ if ((d->resolveMask & QQuickIconPrivate::SourceResolved) && d->source == source)
+ return;
+
+ d.detach();
+ d->source = source;
+ d->resolvedSource.clear();
+ d->resolveMask |= QQuickIconPrivate::SourceResolved;
+}
+
+void QQuickIcon::resetSource()
+{
+ d.detach();
+ d->source = QString();
+ d->resolvedSource.clear();
+ d->resolveMask &= ~QQuickIconPrivate::SourceResolved;
+}
+
+QUrl QQuickIcon::resolvedSource() const
+{
+ return d->resolvedSource.isEmpty() ? d->source : d->resolvedSource;
+}
+
+// must be called by the property owner (e.g. Button) prior to emitting changed signal.
+void QQuickIcon::ensureRelativeSourceResolved(const QObject *owner)
+{
+ if (d->source.isEmpty())
+ return;
+ if (!d->resolvedSource.isEmpty())
+ return; // already resolved relative to (possibly) different owner
+ const QQmlData *data = QQmlData::get(owner);
+ if (!data || !data->outerContext)
+ return;
+ d.detach();
+ d->resolvedSource = data->outerContext->resolvedUrl(d->source);
+}
+
+int QQuickIcon::width() const
+{
+ return d->width;
+}
+
+void QQuickIcon::setWidth(int width)
+{
+ if ((d->resolveMask & QQuickIconPrivate::WidthResolved) && d->width == width)
+ return;
+
+ d.detach();
+ d->width = width;
+ d->resolveMask |= QQuickIconPrivate::WidthResolved;
+}
+
+void QQuickIcon::resetWidth()
+{
+ d.detach();
+ d->width = 0;
+ d->resolveMask &= ~QQuickIconPrivate::WidthResolved;
+}
+
+int QQuickIcon::height() const
+{
+ return d->height;
+}
+
+void QQuickIcon::setHeight(int height)
+{
+ if ((d->resolveMask & QQuickIconPrivate::HeightResolved) && d->height == height)
+ return;
+
+ d.detach();
+ d->height = height;
+ d->resolveMask |= QQuickIconPrivate::HeightResolved;
+}
+
+void QQuickIcon::resetHeight()
+{
+ d.detach();
+ d->height = 0;
+ d->resolveMask &= ~QQuickIconPrivate::HeightResolved;
+}
+
+QColor QQuickIcon::color() const
+{
+ return d->color;
+}
+
+void QQuickIcon::setColor(const QColor &color)
+{
+ if ((d->resolveMask & QQuickIconPrivate::ColorResolved) && d->color == color)
+ return;
+
+ d.detach();
+ d->color = color;
+ d->resolveMask |= QQuickIconPrivate::ColorResolved;
+}
+
+void QQuickIcon::resetColor()
+{
+ d.detach();
+ d->color = Qt::transparent;
+ d->resolveMask &= ~QQuickIconPrivate::ColorResolved;
+}
+
+bool QQuickIcon::cache() const
+{
+ return d->ownerAndCache.tag() == QQuickIconPrivate::DoCache;
+}
+
+void QQuickIcon::setCache(bool cache)
+{
+ const auto cacheState = cache ? QQuickIconPrivate::DoCache : QQuickIconPrivate::SkipCaching;
+ if ((d->resolveMask & QQuickIconPrivate::CacheResolved) && d->ownerAndCache.tag() == cacheState)
+ return;
+
+ d.detach();
+ d->ownerAndCache.setTag(cacheState);
+ d->resolveMask |= QQuickIconPrivate::CacheResolved;
+}
+
+void QQuickIcon::resetCache()
+{
+ d.detach();
+ d->ownerAndCache.setTag(QQuickIconPrivate::DoCache);
+ d->resolveMask &= ~QQuickIconPrivate::CacheResolved;
+}
+
+QQuickIcon QQuickIcon::resolve(const QQuickIcon &other) const
+{
+ QQuickIcon resolved = *this;
+ resolved.d.detach();
+
+ if (!(d->resolveMask & QQuickIconPrivate::NameResolved))
+ resolved.d->name = other.d->name;
+
+ if (!(d->resolveMask & QQuickIconPrivate::SourceResolved)) {
+ resolved.d->source = other.d->source;
+ resolved.d->resolvedSource = other.d->resolvedSource;
+ }
+
+ if (!(d->resolveMask & QQuickIconPrivate::WidthResolved))
+ resolved.d->width = other.d->width;
+
+ if (!(d->resolveMask & QQuickIconPrivate::HeightResolved))
+ resolved.d->height = other.d->height;
+
+ if (!(d->resolveMask & QQuickIconPrivate::ColorResolved))
+ resolved.d->color = other.d->color;
+
+ if (!(d->resolveMask & QQuickIconPrivate::CacheResolved))
+ resolved.d->ownerAndCache.setTag(other.d->ownerAndCache.tag());
+
+ // owner does not change when resolving an icon
+
+ return resolved;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickicon_p.cpp"
diff --git a/src/quicktemplates2/qquickicon_p.h b/src/quicktemplates2/qquickicon_p.h
new file mode 100644
index 0000000000..0312812429
--- /dev/null
+++ b/src/quicktemplates2/qquickicon_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKICON_P_H
+#define QQUICKICON_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 <QtCore/qobjectdefs.h>
+#include <QtCore/qshareddata.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtGui/qcolor.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIconPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickIcon
+{
+ Q_GADGET
+ Q_PROPERTY(QString name READ name WRITE setName RESET resetName FINAL)
+ Q_PROPERTY(QUrl source READ source WRITE setSource RESET resetSource FINAL)
+ Q_PROPERTY(int width READ width WRITE setWidth RESET resetWidth FINAL)
+ Q_PROPERTY(int height READ height WRITE setHeight RESET resetHeight FINAL)
+ Q_PROPERTY(QColor color READ color WRITE setColor RESET resetColor FINAL)
+ Q_PROPERTY(bool cache READ cache WRITE setCache RESET resetCache FINAL)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ QQuickIcon();
+ QQuickIcon(const QQuickIcon &other);
+ ~QQuickIcon();
+
+ QQuickIcon& operator=(const QQuickIcon &other);
+ bool operator==(const QQuickIcon &other) const;
+ bool operator!=(const QQuickIcon &other) const;
+
+ bool isEmpty() const;
+
+ QString name() const;
+ void setName(const QString &name);
+ void resetName();
+
+ QUrl source() const;
+ void setSource(const QUrl &source);
+ void resetSource();
+ QUrl resolvedSource() const;
+ void ensureRelativeSourceResolved(const QObject *owner);
+
+ int width() const;
+ void setWidth(int width);
+ void resetWidth();
+
+ int height() const;
+ void setHeight(int height);
+ void resetHeight();
+
+ QColor color() const;
+ void setColor(const QColor &color);
+ void resetColor();
+
+ bool cache() const;
+ void setCache(bool cache);
+ void resetCache();
+
+ QQuickIcon resolve(const QQuickIcon &other) const;
+
+private:
+ QExplicitlySharedDataPointer<QQuickIconPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKICON_P_H
diff --git a/src/quicktemplates2/qquickindicatorbutton_p.cpp b/src/quicktemplates2/qquickindicatorbutton_p.cpp
new file mode 100644
index 0000000000..016d89a4c6
--- /dev/null
+++ b/src/quicktemplates2/qquickindicatorbutton_p.cpp
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qquickindicatorbutton_p.h"
+#include "qquickdeferredexecute_p_p.h"
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIndicatorButton;
+
+static inline QString indicatorName() { return QStringLiteral("indicator"); }
+
+void QQuickIndicatorButtonPrivate::cancelIndicator()
+{
+ Q_Q(QQuickIndicatorButton);
+ quickCancelDeferred(q, indicatorName());
+}
+
+void QQuickIndicatorButtonPrivate::executeIndicator(bool complete)
+{
+ Q_Q(QQuickIndicatorButton);
+ if (indicator.wasExecuted())
+ return;
+
+ if (!indicator || complete)
+ quickBeginDeferred(q, indicatorName(), indicator);
+ if (complete)
+ quickCompleteDeferred(q, indicatorName(), indicator);
+}
+
+QQuickIndicatorButton::QQuickIndicatorButton(QObject *parent)
+ : QObject(*(new QQuickIndicatorButtonPrivate), parent)
+{
+}
+
+bool QQuickIndicatorButton::isPressed() const
+{
+ Q_D(const QQuickIndicatorButton);
+ return d->pressed;
+}
+
+void QQuickIndicatorButton::setPressed(bool pressed)
+{
+ Q_D(QQuickIndicatorButton);
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ emit pressedChanged();
+}
+
+QQuickItem *QQuickIndicatorButton::indicator() const
+{
+ QQuickIndicatorButtonPrivate *d = const_cast<QQuickIndicatorButtonPrivate *>(d_func());
+ if (!d->indicator)
+ d->executeIndicator();
+ return d->indicator;
+}
+
+void QQuickIndicatorButton::setIndicator(QQuickItem *indicator)
+{
+ Q_D(QQuickIndicatorButton);
+ if (d->indicator == indicator)
+ return;
+
+ if (!d->indicator.isExecuting())
+ d->cancelIndicator();
+
+ const qreal oldImplicitIndicatorWidth = implicitIndicatorWidth();
+ const qreal oldImplicitIndicatorHeight = implicitIndicatorHeight();
+
+ QQuickControl *par = static_cast<QQuickControl *>(parent());
+
+ QQuickControlPrivate::get(par)->removeImplicitSizeListener(d->indicator);
+ QQuickControlPrivate::hideOldItem(d->indicator);
+ d->indicator = indicator;
+
+ if (indicator) {
+ if (!indicator->parentItem())
+ indicator->setParentItem(par);
+ QQuickControlPrivate::get(par)->addImplicitSizeListener(indicator);
+ }
+
+ if (!qFuzzyCompare(oldImplicitIndicatorWidth, implicitIndicatorWidth()))
+ emit implicitIndicatorWidthChanged();
+ if (!qFuzzyCompare(oldImplicitIndicatorHeight, implicitIndicatorHeight()))
+ emit implicitIndicatorHeightChanged();
+ if (!d->indicator.isExecuting())
+ emit indicatorChanged();
+}
+
+bool QQuickIndicatorButton::isHovered() const
+{
+ Q_D(const QQuickIndicatorButton);
+ return d->hovered;
+}
+
+void QQuickIndicatorButton::setHovered(bool hovered)
+{
+ Q_D(QQuickIndicatorButton);
+ if (d->hovered == hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
+qreal QQuickIndicatorButton::implicitIndicatorWidth() const
+{
+ Q_D(const QQuickIndicatorButton);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitWidth();
+}
+
+qreal QQuickIndicatorButton::implicitIndicatorHeight() const
+{
+ Q_D(const QQuickIndicatorButton);
+ if (!d->indicator)
+ return 0;
+ return d->indicator->implicitHeight();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickindicatorbutton_p.cpp"
diff --git a/src/quicktemplates2/qquickindicatorbutton_p.h b/src/quicktemplates2/qquickindicatorbutton_p.h
new file mode 100644
index 0000000000..44c5b0cfef
--- /dev/null
+++ b/src/quicktemplates2/qquickindicatorbutton_p.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QQUICKINDICATORBUTTON_H
+#define QQUICKINDICATORBUTTON_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQml/qjsvalue.h>
+#include "qquickdeferredpointer_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickIndicatorButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickIndicatorButton : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool hovered READ isHovered WRITE setHovered NOTIFY hoveredChanged FINAL REVISION(2, 1))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitIndicatorWidth READ implicitIndicatorWidth NOTIFY implicitIndicatorWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitIndicatorHeight READ implicitIndicatorHeight NOTIFY implicitIndicatorHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "indicator")
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickIndicatorButton(QObject *parent);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ QQuickItem *indicator() const;
+ void setIndicator(QQuickItem *indicator);
+
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ qreal implicitIndicatorWidth() const;
+ qreal implicitIndicatorHeight() const;
+
+Q_SIGNALS:
+ void pressedChanged();
+ void indicatorChanged();
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void hoveredChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void implicitIndicatorWidthChanged();
+ Q_REVISION(2, 5) void implicitIndicatorHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickIndicatorButton)
+ Q_DECLARE_PRIVATE(QQuickIndicatorButton)
+};
+
+class QQuickIndicatorButtonPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickIndicatorButton)
+
+public:
+ static QQuickIndicatorButtonPrivate *get(QQuickIndicatorButton *button)
+ {
+ return button->d_func();
+ }
+
+ void cancelIndicator();
+ void executeIndicator(bool complete = false);
+
+ bool pressed = false;
+ bool hovered = false;
+ QQuickDeferredPointer<QQuickItem> indicator;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKINDICATORBUTTON_H
diff --git a/src/quicktemplates2/qquickitemdelegate.cpp b/src/quicktemplates2/qquickitemdelegate.cpp
new file mode 100644
index 0000000000..466bd0c25e
--- /dev/null
+++ b/src/quicktemplates2/qquickitemdelegate.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickitemdelegate_p.h"
+#include "qquickitemdelegate_p_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ItemDelegate
+ \inherits AbstractButton
+//! \instantiates QQuickItemDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-delegates
+ \brief Basic item delegate that can be used in various views and controls.
+
+ \image qtquickcontrols2-itemdelegate.gif
+
+ ItemDelegate presents a standard view item. It can be used as a delegate
+ in various views and controls, such as \l ListView and \l ComboBox.
+
+ ItemDelegate inherits its API from AbstractButton. For instance, you can set
+ \l {AbstractButton::text}{text}, display an \l {Icons in Qt Quick Controls}{icon},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton API.
+
+ \snippet qtquickcontrols2-itemdelegate.qml 1
+
+ \sa {Customizing ItemDelegate}, {Delegate Controls}
+*/
+
+QQuickItemDelegate::QQuickItemDelegate(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickItemDelegatePrivate), parent)
+{
+ setFocusPolicy(Qt::NoFocus);
+}
+
+QQuickItemDelegate::QQuickItemDelegate(QQuickItemDelegatePrivate &dd, QQuickItem *parent)
+ : QQuickAbstractButton(dd, parent)
+{
+ setFocusPolicy(Qt::NoFocus);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ItemDelegate::highlighted
+
+ This property holds whether the delegate is highlighted.
+
+ A delegate can be highlighted in order to draw the user's attention towards
+ it. It has no effect on keyboard interaction. For example, you can
+ highlight the current item in a ListView using the following code:
+
+ \code
+ ListView {
+ id: listView
+ model: 10
+ delegate: ItemDelegate {
+ text: modelData
+ highlighted: ListView.isCurrentItem
+ onClicked: listView.currentIndex = index
+ }
+ }
+ \endcode
+
+ The default value is \c false.
+*/
+bool QQuickItemDelegate::isHighlighted() const
+{
+ Q_D(const QQuickItemDelegate);
+ return d->highlighted;
+}
+
+void QQuickItemDelegate::setHighlighted(bool highlighted)
+{
+ Q_D(QQuickItemDelegate);
+ if (highlighted == d->highlighted)
+ return;
+
+ d->highlighted = highlighted;
+ emit highlightedChanged();
+}
+
+QFont QQuickItemDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ItemView);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickItemDelegate::accessibleRole() const
+{
+ return QAccessible::ListItem;
+}
+#endif
+
+QPalette QQuickItemDelegatePrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::ItemView);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickitemdelegate_p.cpp"
diff --git a/src/quicktemplates2/qquickitemdelegate_p.h b/src/quicktemplates2/qquickitemdelegate_p.h
new file mode 100644
index 0000000000..2568a0bf91
--- /dev/null
+++ b/src/quicktemplates2/qquickitemdelegate_p.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKITEMDELEGATE_P_H
+#define QQUICKITEMDELEGATE_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItemDelegatePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickItemDelegate : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL)
+ QML_NAMED_ELEMENT(ItemDelegate)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickItemDelegate(QQuickItem *parent = nullptr);
+
+ bool isHighlighted() const;
+ void setHighlighted(bool highlighted);
+
+Q_SIGNALS:
+ void highlightedChanged();
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+protected:
+ QQuickItemDelegate(QQuickItemDelegatePrivate &dd, QQuickItem *parent);
+
+private:
+ Q_DISABLE_COPY(QQuickItemDelegate)
+ Q_DECLARE_PRIVATE(QQuickItemDelegate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickItemDelegate)
+
+#endif // QQUICKITEMDELEGATE_P_H
diff --git a/src/quicktemplates2/qquickitemdelegate_p_p.h b/src/quicktemplates2/qquickitemdelegate_p_p.h
new file mode 100644
index 0000000000..d7604fbe5d
--- /dev/null
+++ b/src/quicktemplates2/qquickitemdelegate_p_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKITEMDELEGATE_P_P_H
+#define QQUICKITEMDELEGATE_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 <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickItemDelegatePrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickItemDelegate)
+
+public:
+ QPalette defaultPalette() const override;
+
+ bool highlighted = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKITEMDELEGATE_P_P_H
diff --git a/src/quicktemplates2/qquicklabel.cpp b/src/quicktemplates2/qquicklabel.cpp
new file mode 100644
index 0000000000..9aa501d110
--- /dev/null
+++ b/src/quicktemplates2/qquicklabel.cpp
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicklabel_p.h"
+#include "qquicklabel_p_p.h"
+#include "qquickcontrol_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquicktext_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Label
+ \inherits Text
+//! \instantiates QQuickLabel
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup text
+ \brief Styled text label with inherited font.
+
+ Label extends \l Text with styling and \l {Control::font}{font}
+ inheritance. The default colors and font are style specific. Label
+ can also have a visual \l background item.
+
+ \image qtquickcontrols2-label.png
+
+ \snippet qtquickcontrols2-label.qml 1
+
+ You can use the properties of \l Text to change the appearance of the text as desired:
+
+ \qml
+ Label {
+ text: "Hello world"
+ font.pixelSize: 22
+ font.italic: true
+ }
+ \endqml
+
+ \sa {Customizing Label}
+*/
+
+QQuickLabelPrivate::QQuickLabelPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installActivationObserver(this);
+#endif
+}
+
+QQuickLabelPrivate::~QQuickLabelPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void QQuickLabelPrivate::setTopInset(qreal value, bool reset)
+{
+ Q_Q(QQuickLabel);
+ const QMarginsF oldInset = getInset();
+ extra.value().topInset = value;
+ extra.value().hasTopInset = !reset;
+ if (!qFuzzyCompare(oldInset.top(), value)) {
+ emit q->topInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickLabelPrivate::setLeftInset(qreal value, bool reset)
+{
+ Q_Q(QQuickLabel);
+ const QMarginsF oldInset = getInset();
+ extra.value().leftInset = value;
+ extra.value().hasLeftInset = !reset;
+ if (!qFuzzyCompare(oldInset.left(), value)) {
+ emit q->leftInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickLabelPrivate::setRightInset(qreal value, bool reset)
+{
+ Q_Q(QQuickLabel);
+ const QMarginsF oldInset = getInset();
+ extra.value().rightInset = value;
+ extra.value().hasRightInset = !reset;
+ if (!qFuzzyCompare(oldInset.right(), value)) {
+ emit q->rightInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickLabelPrivate::setBottomInset(qreal value, bool reset)
+{
+ Q_Q(QQuickLabel);
+ const QMarginsF oldInset = getInset();
+ extra.value().bottomInset = value;
+ extra.value().hasBottomInset = !reset;
+ if (!qFuzzyCompare(oldInset.bottom(), value)) {
+ emit q->bottomInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickLabelPrivate::resizeBackground()
+{
+ if (!background)
+ return;
+
+ resizingBackground = true;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
+ || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
+ background->setX(getLeftInset());
+ background->setWidth(width - getLeftInset() - getRightInset());
+ }
+ if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
+ || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
+ background->setY(getTopInset());
+ background->setHeight(height - getTopInset() - getBottomInset());
+ }
+
+ resizingBackground = false;
+}
+
+/*!
+ \internal
+
+ Determine which font is implicitly imposed on this control by its ancestors
+ and QGuiApplication::font, resolve this against its own font (attributes from
+ the implicit font are copied over). Then propagate this font to this
+ control's children.
+*/
+void QQuickLabelPrivate::resolveFont()
+{
+ Q_Q(QQuickLabel);
+ inheritFont(QQuickControlPrivate::parentFont(q));
+}
+
+void QQuickLabelPrivate::inheritFont(const QFont &font)
+{
+ QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
+ parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
+
+ const QFont defaultFont = QQuickTheme::font(QQuickTheme::Label);
+ QFont resolvedFont = parentFont.resolve(defaultFont);
+
+ setFont_helper(resolvedFont);
+}
+
+/*!
+ \internal
+
+ Assign \a font to this control, and propagate it to all children.
+*/
+void QQuickLabelPrivate::updateFont(const QFont &font)
+{
+ Q_Q(QQuickLabel);
+ QFont oldFont = sourceFont;
+ q->QQuickText::setFont(font);
+
+ QQuickControlPrivate::updateFontRecur(q, font);
+
+ if (oldFont != font)
+ emit q->fontChanged();
+}
+
+void QQuickLabelPrivate::textChanged(const QString &text)
+{
+#if QT_CONFIG(accessibility)
+ maybeSetAccessibleName(text);
+#else
+ Q_UNUSED(text);
+#endif
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickLabelPrivate::accessibilityActiveChanged(bool active)
+{
+ if (!active)
+ return;
+
+ Q_Q(QQuickLabel);
+ QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
+ Q_ASSERT(accessibleAttached);
+ accessibleAttached->setRole(accessibleRole());
+ maybeSetAccessibleName(text);
+}
+
+QAccessible::Role QQuickLabelPrivate::accessibleRole() const
+{
+ return QAccessible::StaticText;
+}
+
+void QQuickLabelPrivate::maybeSetAccessibleName(const QString &name)
+{
+ Q_Q(QQuickLabel);
+ auto accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(
+ qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
+ if (accessibleAttached) {
+ if (!accessibleAttached->wasNameExplicitlySet())
+ accessibleAttached->setNameImplicitly(name);
+ }
+}
+#endif
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickLabelPrivate::cancelBackground()
+{
+ Q_Q(QQuickLabel);
+ quickCancelDeferred(q, backgroundName());
+}
+
+void QQuickLabelPrivate::executeBackground(bool complete)
+{
+ Q_Q(QQuickLabel);
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
+}
+
+void QQuickLabelPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(diff);
+ if (resizingBackground || item != background || !change.sizeChange())
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ extra.value().hasBackgroundWidth = p->widthValid();
+ extra.value().hasBackgroundHeight = p->heightValid();
+ resizeBackground();
+}
+
+void QQuickLabelPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickLabel);
+ if (item == background)
+ emit q->implicitBackgroundWidthChanged();
+}
+
+void QQuickLabelPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickLabel);
+ if (item == background)
+ emit q->implicitBackgroundHeightChanged();
+}
+
+void QQuickLabelPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickLabel);
+ if (item == background) {
+ background = nullptr;
+ emit q->implicitBackgroundWidthChanged();
+ emit q->implicitBackgroundHeightChanged();
+ }
+}
+
+QPalette QQuickLabelPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::Label);
+}
+
+QQuickLabel::QQuickLabel(QQuickItem *parent)
+ : QQuickText(*(new QQuickLabelPrivate), parent)
+{
+ Q_D(QQuickLabel);
+ QObjectPrivate::connect(this, &QQuickText::textChanged, d, &QQuickLabelPrivate::textChanged);
+}
+
+QQuickLabel::~QQuickLabel()
+{
+ Q_D(QQuickLabel);
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+}
+
+QFont QQuickLabel::font() const
+{
+ return QQuickText::font();
+}
+
+void QQuickLabel::setFont(const QFont &font)
+{
+ Q_D(QQuickLabel);
+ if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
+ return;
+
+ d->extra.value().requestedFont = font;
+ d->resolveFont();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Label::background
+
+ This property holds the background item.
+
+ \note If the background item has no explicit size specified, it automatically
+ follows the control's size. In most cases, there is no need to specify
+ width or height for a background item.
+
+ \sa {Customizing Label}
+*/
+QQuickItem *QQuickLabel::background() const
+{
+ QQuickLabelPrivate *d = const_cast<QQuickLabelPrivate *>(d_func());
+ if (!d->background)
+ d->executeBackground();
+ return d->background;
+}
+
+void QQuickLabel::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickLabel);
+ if (d->background == background)
+ return;
+
+ if (!d->background.isExecuting())
+ d->cancelBackground();
+
+ const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
+ const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
+
+ if (d->extra.isAllocated()) {
+ d->extra.value().hasBackgroundWidth = false;
+ d->extra.value().hasBackgroundHeight = false;
+ }
+
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ QQuickControlPrivate::hideOldItem(d->background);
+ d->background = background;
+
+ if (background) {
+ background->setParentItem(this);
+ if (qFuzzyIsNull(background->z()))
+ background->setZ(-1);
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (p->widthValid() || p->heightValid()) {
+ d->extra.value().hasBackgroundWidth = p->widthValid();
+ d->extra.value().hasBackgroundHeight = p->heightValid();
+ }
+ if (isComponentComplete())
+ d->resizeBackground();
+ QQuickControlPrivate::addImplicitSizeListener(background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ }
+
+ if (!qFuzzyCompare(oldImplicitBackgroundWidth, implicitBackgroundWidth()))
+ emit implicitBackgroundWidthChanged();
+ if (!qFuzzyCompare(oldImplicitBackgroundHeight, implicitBackgroundHeight()))
+ emit implicitBackgroundHeightChanged();
+ if (!d->background.isExecuting())
+ emit backgroundChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::implicitBackgroundWidth
+ \readonly
+
+ This property holds the implicit background width.
+
+ The value is equal to \c {background ? background.implicitWidth : 0}.
+
+ \sa implicitBackgroundHeight
+*/
+qreal QQuickLabel::implicitBackgroundWidth() const
+{
+ Q_D(const QQuickLabel);
+ if (!d->background)
+ return 0;
+ return d->background->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::implicitBackgroundHeight
+ \readonly
+
+ This property holds the implicit background height.
+
+ The value is equal to \c {background ? background.implicitHeight : 0}.
+
+ \sa implicitBackgroundWidth
+*/
+qreal QQuickLabel::implicitBackgroundHeight() const
+{
+ Q_D(const QQuickLabel);
+ if (!d->background)
+ return 0;
+ return d->background->implicitHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::topInset
+
+ This property holds the top inset for the background.
+
+ \sa {Control Layout}, bottomInset
+*/
+qreal QQuickLabel::topInset() const
+{
+ Q_D(const QQuickLabel);
+ return d->getTopInset();
+}
+
+void QQuickLabel::setTopInset(qreal inset)
+{
+ Q_D(QQuickLabel);
+ d->setTopInset(inset);
+}
+
+void QQuickLabel::resetTopInset()
+{
+ Q_D(QQuickLabel);
+ d->setTopInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::leftInset
+
+ This property holds the left inset for the background.
+
+ \sa {Control Layout}, rightInset
+*/
+qreal QQuickLabel::leftInset() const
+{
+ Q_D(const QQuickLabel);
+ return d->getLeftInset();
+}
+
+void QQuickLabel::setLeftInset(qreal inset)
+{
+ Q_D(QQuickLabel);
+ d->setLeftInset(inset);
+}
+
+void QQuickLabel::resetLeftInset()
+{
+ Q_D(QQuickLabel);
+ d->setLeftInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::rightInset
+
+ This property holds the right inset for the background.
+
+ \sa {Control Layout}, leftInset
+*/
+qreal QQuickLabel::rightInset() const
+{
+ Q_D(const QQuickLabel);
+ return d->getRightInset();
+}
+
+void QQuickLabel::setRightInset(qreal inset)
+{
+ Q_D(QQuickLabel);
+ d->setRightInset(inset);
+}
+
+void QQuickLabel::resetRightInset()
+{
+ Q_D(QQuickLabel);
+ d->setRightInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Label::bottomInset
+
+ This property holds the bottom inset for the background.
+
+ \sa {Control Layout}, topInset
+*/
+qreal QQuickLabel::bottomInset() const
+{
+ Q_D(const QQuickLabel);
+ return d->getBottomInset();
+}
+
+void QQuickLabel::setBottomInset(qreal inset)
+{
+ Q_D(QQuickLabel);
+ d->setBottomInset(inset);
+}
+
+void QQuickLabel::resetBottomInset()
+{
+ Q_D(QQuickLabel);
+ d->setBottomInset(0, true);
+}
+
+void QQuickLabel::classBegin()
+{
+ Q_D(QQuickLabel);
+ QQuickText::classBegin();
+ d->resolveFont();
+}
+
+void QQuickLabel::componentComplete()
+{
+ Q_D(QQuickLabel);
+ d->executeBackground(true);
+ QQuickText::componentComplete();
+ d->resizeBackground();
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ d->accessibilityActiveChanged(true);
+#endif
+}
+
+void QQuickLabel::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ Q_D(QQuickLabel);
+ QQuickText::itemChange(change, value);
+ switch (change) {
+ case ItemEnabledHasChanged:
+ break;
+ case ItemSceneChange:
+ case ItemParentHasChanged:
+ if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
+ d->resolveFont();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickLabel::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickLabel);
+ QQuickText::geometryChange(newGeometry, oldGeometry);
+ d->resizeBackground();
+}
+
+void QQuickLabel::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
+{
+ Q_D(QQuickLabel);
+ Q_UNUSED(newInset);
+ Q_UNUSED(oldInset);
+ d->resizeBackground();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicklabel_p.cpp"
diff --git a/src/quicktemplates2/qquicklabel_p.h b/src/quicktemplates2/qquicklabel_p.h
new file mode 100644
index 0000000000..6ef60be96e
--- /dev/null
+++ b/src/quicktemplates2/qquicklabel_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABEL_P_H
+#define QQUICKLABEL_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/qpalette.h>
+#include <QtQuick/private/qquicktext_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickLabelPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickLabel : public QQuickText
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitBackgroundWidth READ implicitBackgroundWidth NOTIFY implicitBackgroundWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundHeight READ implicitBackgroundHeight NOTIFY implicitBackgroundHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal topInset READ topInset WRITE setTopInset RESET resetTopInset NOTIFY topInsetChanged FINAL REVISION(2, 5))
+ 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_CLASSINFO("DeferredPropertyNames", "background")
+ QML_NAMED_ELEMENT(Label)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickLabel(QQuickItem *parent = nullptr);
+ ~QQuickLabel();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ // 2.5 (Qt 5.12)
+ qreal implicitBackgroundWidth() const;
+ qreal implicitBackgroundHeight() const;
+
+ qreal topInset() const;
+ void setTopInset(qreal inset);
+ void resetTopInset();
+
+ qreal leftInset() const;
+ void setLeftInset(qreal inset);
+ void resetLeftInset();
+
+ qreal rightInset() const;
+ void setRightInset(qreal inset);
+ void resetRightInset();
+
+ qreal bottomInset() const;
+ void setBottomInset(qreal inset);
+ void resetBottomInset();
+
+Q_SIGNALS:
+ void fontChanged();
+ void backgroundChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void implicitBackgroundWidthChanged();
+ Q_REVISION(2, 5) void implicitBackgroundHeightChanged();
+ Q_REVISION(2, 5) void topInsetChanged();
+ Q_REVISION(2, 5) void leftInsetChanged();
+ Q_REVISION(2, 5) void rightInsetChanged();
+ Q_REVISION(2, 5) void bottomInsetChanged();
+
+protected:
+ void classBegin() override;
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ virtual void insetChange(const QMarginsF &newInset, const QMarginsF &oldInset);
+
+private:
+ Q_DISABLE_COPY(QQuickLabel)
+ Q_DECLARE_PRIVATE(QQuickLabel)
+};
+
+struct QQuickTemplatesTextForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickText)
+ QML_ADDED_IN_VERSION(2, 3)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickLabel)
+
+#endif // QQUICKLABEL_P_H
diff --git a/src/quicktemplates2/qquicklabel_p_p.h b/src/quicktemplates2/qquicklabel_p_p.h
new file mode 100644
index 0000000000..3171e2f7e4
--- /dev/null
+++ b/src/quicktemplates2/qquicklabel_p_p.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKLABEL_P_P_H
+#define QQUICKLABEL_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 <QtQml/private/qlazilyallocated_p.h>
+#include <QtQuick/private/qquicktext_p_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickdeferredpointer_p_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QQuickLabelPrivate : public QQuickTextPrivate, public QQuickItemChangeListener
+#if QT_CONFIG(accessibility)
+ , public QAccessible::ActivationObserver
+#endif
+{
+ Q_DECLARE_PUBLIC(QQuickLabel)
+
+public:
+ QQuickLabelPrivate();
+ ~QQuickLabelPrivate();
+
+ static QQuickLabelPrivate *get(QQuickLabel *item)
+ {
+ return static_cast<QQuickLabelPrivate *>(QObjectPrivate::get(item));
+ }
+
+ inline QMarginsF getInset() const { return QMarginsF(getLeftInset(), getTopInset(), getRightInset(), getBottomInset()); }
+ inline qreal getTopInset() const { return extra.isAllocated() ? extra->topInset : 0; }
+ inline qreal getLeftInset() const { return extra.isAllocated() ? extra->leftInset : 0; }
+ inline qreal getRightInset() const { return extra.isAllocated() ? extra->rightInset : 0; }
+ inline qreal getBottomInset() const { return extra.isAllocated() ? extra->bottomInset : 0; }
+
+ void setTopInset(qreal value, bool reset = false);
+ void setLeftInset(qreal value, bool reset = false);
+ void setRightInset(qreal value, bool reset = false);
+ void setBottomInset(qreal value, bool reset = false);
+
+ void resizeBackground();
+
+ void resolveFont();
+ void inheritFont(const QFont &font);
+ void updateFont(const QFont &font);
+ inline void setFont_helper(const QFont &font) {
+ if (sourceFont.resolveMask() == font.resolveMask() && sourceFont == font)
+ return;
+ updateFont(font);
+ }
+
+ void textChanged(const QString &text);
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+ void maybeSetAccessibleName(const QString &name);
+#endif
+
+ void cancelBackground();
+ void executeBackground(bool complete = false);
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override;
+
+ struct ExtraData {
+ bool hasTopInset = false;
+ bool hasLeftInset = false;
+ bool hasRightInset = false;
+ bool hasBottomInset = false;
+ bool hasBackgroundWidth = false;
+ bool hasBackgroundHeight = false;
+ qreal topInset = 0;
+ qreal leftInset = 0;
+ qreal rightInset = 0;
+ qreal bottomInset = 0;
+ QFont requestedFont;
+ };
+ QLazilyAllocated<ExtraData> extra;
+
+ bool resizingBackground = false;
+ QPalette resolvedPalette;
+ QQuickDeferredPointer<QQuickItem> background;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKLABEL_P_P_H
diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp
new file mode 100644
index 0000000000..e045375f89
--- /dev/null
+++ b/src/quicktemplates2/qquickmenu.cpp
@@ -0,0 +1,1533 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenu_p.h"
+#include "qquickmenu_p_p.h"
+#include "qquickmenuitem_p_p.h"
+#include "qquickmenubaritem_p.h"
+#include "qquickmenubar_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickpopuppositioner_p_p.h"
+#include "qquickaction_p.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/private/qguiapplication_p.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qv4scopedvalue_p.h>
+#include <QtQml/private/qv4variantobject_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <private/qqmlobjectmodel_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuick/private/qquickitemview_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// copied from qfusionstyle.cpp
+static const int SUBMENU_DELAY = 225;
+
+/*!
+ \qmltype Menu
+ \inherits Popup
+//! \instantiates QQuickMenu
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-menus
+ \ingroup qtquickcontrols2-popups
+ \brief Menu popup that can be used as a context menu or popup menu.
+
+ \image qtquickcontrols2-menu.png
+
+ Menu has two main use cases:
+ \list
+ \li Context menus; for example, a menu that is shown after right clicking
+ \li Popup menus; for example, a menu that is shown after clicking a button
+ \endlist
+
+ When used as a context menu, the recommended way of opening the menu is to call
+ \l popup(). Unless a position is explicitly specified, the menu is positioned at
+ the mouse cursor on desktop platforms that have a mouse cursor available, and
+ otherwise centered over its parent item.
+
+ \code
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onClicked: {
+ if (mouse.button === Qt.RightButton)
+ contextMenu.popup()
+ }
+ onPressAndHold: {
+ if (mouse.source === Qt.MouseEventNotSynthesized)
+ contextMenu.popup()
+ }
+
+ Menu {
+ id: contextMenu
+ MenuItem { text: "Cut" }
+ MenuItem { text: "Copy" }
+ MenuItem { text: "Paste" }
+ }
+ }
+ \endcode
+
+ When used as a popup menu, it is easiest to specify the position by specifying
+ the desired \l {Popup::}{x} and \l {Popup::}{y} coordinates using the respective
+ properties, and call \l {Popup::}{open()} to open the menu.
+
+ \code
+ Button {
+ id: fileButton
+ text: "File"
+ onClicked: menu.open()
+
+ Menu {
+ id: menu
+ y: fileButton.height
+
+ MenuItem {
+ text: "New..."
+ }
+ MenuItem {
+ text: "Open..."
+ }
+ MenuItem {
+ text: "Save"
+ }
+ }
+ }
+ \endcode
+
+ Since QtQuick.Controls 2.3 (Qt 5.10), it is also possible to create sub-menus
+ and declare Action objects inside Menu:
+
+ \code
+ Menu {
+ Action { text: "Cut" }
+ Action { text: "Copy" }
+ Action { text: "Paste" }
+
+ MenuSeparator { }
+
+ Menu {
+ title: "Find/Replace"
+ Action { text: "Find Next" }
+ Action { text: "Find Previous" }
+ Action { text: "Replace" }
+ }
+ }
+ \endcode
+
+ Sub-menus are \l {cascade}{cascading} by default on desktop platforms
+ that have a mouse cursor available. Non-cascading menus are shown one
+ menu at a time, and centered over the parent menu.
+
+ Typically, menu items are statically declared as children of the menu, but
+ Menu also provides API to \l {addItem}{add}, \l {insertItem}{insert},
+ \l {moveItem}{move} and \l {removeItem}{remove} items dynamically. The
+ items in a menu can be accessed using \l itemAt() or
+ \l {Popup::}{contentChildren}.
+
+ Although \l {MenuItem}{MenuItems} are most commonly used with Menu, it can
+ contain any type of item.
+
+ \section1 Margins
+
+ As it is inherited from Popup, Menu supports \l {Popup::}{margins}. By
+ default, all of the built-in styles specify \c 0 for Menu's margins to
+ ensure that the menu is kept within the bounds of the window. To allow a
+ menu to go outside of the window (to animate it moving into view, for
+ example), set the margins property to \c -1.
+
+ \sa {Customizing Menu}, MenuItem, {Menu Controls}, {Popup Controls}
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Menu::focus
+
+ This property holds whether the popup wants focus.
+
+ When the popup actually receives focus, \l{Popup::}{activeFocus}
+ will be \c true. For more information, see
+ \l {Keyboard Focus in Qt Quick}.
+
+ The default value is \c false.
+
+ \sa {Popup::}{activeFocus}
+*/
+
+static const QQuickPopup::ClosePolicy cascadingSubMenuClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent;
+
+static bool shouldCascade()
+{
+#if QT_CONFIG(cursor)
+ return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows);
+#else
+ return false;
+#endif
+}
+
+class QQuickMenuPositioner : public QQuickPopupPositioner
+{
+public:
+ QQuickMenuPositioner(QQuickMenu *menu) : QQuickPopupPositioner(menu) { }
+
+ void reposition() override;
+};
+
+QQuickMenuPrivate::QQuickMenuPrivate()
+{
+ cascade = shouldCascade();
+}
+
+void QQuickMenuPrivate::init()
+{
+ Q_Q(QQuickMenu);
+ contentModel = new QQmlObjectModel(q);
+}
+
+QQuickItem *QQuickMenuPrivate::itemAt(int index) const
+{
+ return qobject_cast<QQuickItem *>(contentModel->get(index));
+}
+
+void QQuickMenuPrivate::insertItem(int index, QQuickItem *item)
+{
+ contentData.append(item);
+ item->setParentItem(contentItem);
+ if (qobject_cast<QQuickItemView *>(contentItem))
+ QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-53262
+ if (complete)
+ resizeItem(item);
+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
+ QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Width);
+ contentModel->insert(index, 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, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
+ QObjectPrivate::connect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
+ }
+}
+
+void QQuickMenuPrivate::moveItem(int from, int to)
+{
+ contentModel->move(from, to);
+}
+
+void QQuickMenuPrivate::removeItem(int index, QQuickItem *item)
+{
+ contentData.removeOne(item);
+
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed | QQuickItemPrivate::Parent);
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ item->setParentItem(nullptr);
+ contentModel->remove(index);
+
+ QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
+ if (menuItem) {
+ QQuickMenuItemPrivate::get(menuItem)->setMenu(nullptr);
+ if (QQuickMenu *subMenu = menuItem->subMenu())
+ QQuickMenuPrivate::get(subMenu)->setParentMenu(nullptr);
+ QObjectPrivate::disconnect(menuItem, &QQuickMenuItem::triggered, this, &QQuickMenuPrivate::onItemTriggered);
+ QObjectPrivate::disconnect(menuItem, &QQuickItem::activeFocusChanged, this, &QQuickMenuPrivate::onItemActiveFocusChanged);
+ QObjectPrivate::disconnect(menuItem, &QQuickControl::hoveredChanged, this, &QQuickMenuPrivate::onItemHovered);
+ }
+}
+
+QQuickItem *QQuickMenuPrivate::beginCreateItem()
+{
+ Q_Q(QQuickMenu);
+ if (!delegate)
+ return nullptr;
+
+ QQmlContext *creationContext = delegate->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext, q);
+ context->setContextObject(q);
+
+ QObject *object = delegate->beginCreate(context);
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item)
+ delete object;
+ else
+ QQml_setParent_noEvent(item, q);
+
+ return item;
+}
+
+void QQuickMenuPrivate::completeCreateItem()
+{
+ if (!delegate)
+ return;
+
+ delegate->completeCreate();
+}
+
+QQuickItem *QQuickMenuPrivate::createItem(QQuickMenu *menu)
+{
+ QQuickItem *item = beginCreateItem();
+ if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item))
+ QQuickMenuItemPrivate::get(menuItem)->setSubMenu(menu);
+ completeCreateItem();
+ return item;
+}
+
+QQuickItem *QQuickMenuPrivate::createItem(QQuickAction *action)
+{
+ QQuickItem *item = beginCreateItem();
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
+ button->setAction(action);
+ completeCreateItem();
+ return item;
+}
+
+void QQuickMenuPrivate::resizeItem(QQuickItem *item)
+{
+ if (!item || !contentItem)
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid()) {
+ item->setWidth(contentItem->width());
+ p->widthValidFlag = false;
+ }
+}
+
+void QQuickMenuPrivate::resizeItems()
+{
+ if (!contentModel)
+ return;
+
+ for (int i = 0; i < contentModel->count(); ++i)
+ resizeItem(itemAt(i));
+}
+
+void QQuickMenuPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
+{
+ // add dynamically reparented items (eg. by a Repeater)
+ if (!QQuickItemPrivate::get(child)->isTransparentForPositioner() && !contentData.contains(child))
+ insertItem(contentModel->count(), child);
+}
+
+void QQuickMenuPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ // remove dynamically unparented items (eg. by a Repeater)
+ if (!parent)
+ removeItem(contentModel->indexOf(item, nullptr), item);
+}
+
+void QQuickMenuPrivate::itemSiblingOrderChanged(QQuickItem *)
+{
+ // reorder the restacked items (eg. by a Repeater)
+ Q_Q(QQuickMenu);
+ QList<QQuickItem *> siblings = contentItem->childItems();
+
+ int to = 0;
+ for (int i = 0; i < siblings.count(); ++i) {
+ QQuickItem* sibling = siblings.at(i);
+ if (QQuickItemPrivate::get(sibling)->isTransparentForPositioner())
+ continue;
+ int index = contentModel->indexOf(sibling, nullptr);
+ q->moveItem(index, to++);
+ }
+}
+
+void QQuickMenuPrivate::itemDestroyed(QQuickItem *item)
+{
+ QQuickPopupPrivate::itemDestroyed(item);
+ int index = contentModel->indexOf(item, nullptr);
+ if (index != -1)
+ removeItem(index, item);
+}
+
+void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange, const QRectF &)
+{
+ if (!complete)
+ return;
+
+ if (item == contentItem) {
+ // The contentItem's geometry changed, so resize any items
+ // that don't have explicit widths set so that they fill the width of the menu.
+ resizeItems();
+ } else {
+ // The geometry of an item in the menu changed. If the item
+ // doesn't have an explicit width set, make it fill the width of the menu.
+ resizeItem(item);
+ }
+}
+
+QQuickPopupPositioner *QQuickMenuPrivate::getPositioner()
+{
+ Q_Q(QQuickMenu);
+ if (!positioner)
+ positioner = new QQuickMenuPositioner(q);
+ return positioner;
+}
+
+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()));
+ } else {
+ menu->setPosition(QPointF(p->parentMenu->x() + (p->parentMenu->width() - menu->width()) / 2,
+ p->parentMenu->y() + (p->parentMenu->height() - menu->height()) / 2));
+ }
+ }
+ QQuickPopupPositioner::reposition();
+}
+
+bool QQuickMenuPrivate::prepareEnterTransition()
+{
+ Q_Q(QQuickMenu);
+ if (parentMenu && !cascade)
+ parentMenu->close();
+
+ // If a cascading sub-menu doesn't have enough space to open on
+ // the right, it flips on the other side of the parent menu.
+ allowHorizontalFlip = cascade && parentMenu;
+
+ if (!QQuickPopupPrivate::prepareEnterTransition())
+ return false;
+
+ if (!hasClosePolicy) {
+ if (cascade && parentMenu)
+ closePolicy = cascadingSubMenuClosePolicy;
+ else
+ q->resetClosePolicy();
+ }
+ return true;
+}
+
+bool QQuickMenuPrivate::prepareExitTransition()
+{
+ if (!QQuickPopupPrivate::prepareExitTransition())
+ return false;
+
+ stopHoverTimer();
+
+ QQuickMenu *subMenu = currentSubMenu();
+ while (subMenu) {
+ QPointer<QQuickMenuItem> currentSubMenuItem = QQuickMenuPrivate::get(subMenu)->currentItem;
+ subMenu->close();
+ subMenu = currentSubMenuItem ? currentSubMenuItem->subMenu() : nullptr;
+ }
+ return true;
+}
+
+bool QQuickMenuPrivate::blockInput(QQuickItem *item, const QPointF &point) const
+{
+ // keep the parent menu open when a cascading sub-menu (this menu) is interacted with
+ return (cascade && parentMenu && contains(point)) || QQuickPopupPrivate::blockInput(item, point);
+}
+
+void QQuickMenuPrivate::onItemHovered()
+{
+ Q_Q(QQuickMenu);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
+ if (!button || !button->isHovered() || !button->isEnabled() || QQuickAbstractButtonPrivate::get(button)->touchId != -1)
+ return;
+
+ QQuickMenuItem *oldCurrentItem = currentItem;
+
+ int index = contentModel->indexOf(button, nullptr);
+ if (index != -1) {
+ setCurrentIndex(index, Qt::OtherFocusReason);
+ if (oldCurrentItem != currentItem) {
+ if (oldCurrentItem) {
+ QQuickMenu *subMenu = oldCurrentItem->subMenu();
+ if (subMenu)
+ subMenu->close();
+ }
+ if (currentItem) {
+ QQuickMenu *subMenu = currentItem->menu();
+ if (subMenu && subMenu->cascade())
+ startHoverTimer();
+ }
+ }
+ }
+}
+
+void QQuickMenuPrivate::onItemTriggered()
+{
+ Q_Q(QQuickMenu);
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(q->sender());
+ if (!item)
+ return;
+
+ if (QQuickMenu *subMenu = item->subMenu()) {
+ auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
+ } else {
+ q->dismiss();
+ }
+}
+
+void QQuickMenuPrivate::onItemActiveFocusChanged()
+{
+ Q_Q(QQuickMenu);
+ QQuickItem *item = qobject_cast<QQuickItem*>(q->sender());
+ if (!item->hasActiveFocus())
+ return;
+
+ int indexOfItem = contentModel->indexOf(item, nullptr);
+ QQuickControl *control = qobject_cast<QQuickControl *>(item);
+ setCurrentIndex(indexOfItem, control ? control->focusReason() : Qt::OtherFocusReason);
+}
+
+QQuickMenu *QQuickMenuPrivate::currentSubMenu() const
+{
+ if (!currentItem)
+ return nullptr;
+
+ return currentItem->subMenu();
+}
+
+void QQuickMenuPrivate::setParentMenu(QQuickMenu *parent)
+{
+ Q_Q(QQuickMenu);
+ if (parentMenu == parent)
+ return;
+
+ if (parentMenu) {
+ QObject::disconnect(parentMenu.data(), &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
+ disconnect(parentMenu.data(), &QQuickMenu::parentChanged, this, &QQuickMenuPrivate::resolveParentItem);
+ }
+ if (parent) {
+ QObject::connect(parent, &QQuickMenu::cascadeChanged, q, &QQuickMenu::setCascade);
+ connect(parent, &QQuickMenu::parentChanged, this, &QQuickMenuPrivate::resolveParentItem);
+ }
+
+ parentMenu = parent;
+ q->resetCascade();
+ resolveParentItem();
+}
+
+static QQuickItem *findParentMenuItem(QQuickMenu *subMenu)
+{
+ QQuickMenu *menu = QQuickMenuPrivate::get(subMenu)->parentMenu;
+ for (int i = 0; i < QQuickMenuPrivate::get(menu)->contentModel->count(); ++i) {
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(menu->itemAt(i));
+ if (item && item->subMenu() == subMenu)
+ return item;
+ }
+ return nullptr;
+}
+
+void QQuickMenuPrivate::resolveParentItem()
+{
+ Q_Q(QQuickMenu);
+ if (!parentMenu)
+ q->resetParentItem();
+ else if (!cascade)
+ q->setParentItem(parentMenu->parentItem());
+ else
+ q->setParentItem(findParentMenuItem(q));
+}
+
+void QQuickMenuPrivate::propagateKeyEvent(QKeyEvent *event)
+{
+ if (QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(parentItem)) {
+ if (QQuickMenu *menu = menuItem->menu())
+ QQuickMenuPrivate::get(menu)->propagateKeyEvent(event);
+ } else if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(parentItem)) {
+ if (QQuickMenuBar *menuBar = menuBarItem->menuBar()) {
+ event->accept();
+ QCoreApplication::sendEvent(menuBar, event);
+ }
+ }
+}
+
+void QQuickMenuPrivate::startHoverTimer()
+{
+ Q_Q(QQuickMenu);
+ stopHoverTimer();
+ hoverTimer = q->startTimer(SUBMENU_DELAY);
+}
+
+void QQuickMenuPrivate::stopHoverTimer()
+{
+ Q_Q(QQuickMenu);
+ if (!hoverTimer)
+ return;
+
+ q->killTimer(hoverTimer);
+ hoverTimer = 0;
+}
+
+void QQuickMenuPrivate::setCurrentIndex(int index, Qt::FocusReason reason)
+{
+ Q_Q(QQuickMenu);
+ if (currentIndex == index)
+ return;
+
+ QQuickMenuItem *newCurrentItem = qobject_cast<QQuickMenuItem *>(itemAt(index));
+ if (currentItem != newCurrentItem) {
+ stopHoverTimer();
+ if (currentItem) {
+ currentItem->setHighlighted(false);
+ if (!newCurrentItem && window) {
+ QQuickItem *focusItem = QQuickItemPrivate::get(contentItem)->subFocusItem;
+ if (focusItem)
+ QQuickWindowPrivate::get(window)->clearFocusInScope(contentItem, focusItem, Qt::OtherFocusReason);
+ }
+ }
+ if (newCurrentItem) {
+ newCurrentItem->setHighlighted(true);
+ newCurrentItem->forceActiveFocus(reason);
+ }
+ currentItem = newCurrentItem;
+ }
+
+ currentIndex = index;
+ emit q->currentIndexChanged();
+}
+
+bool QQuickMenuPrivate::activateNextItem()
+{
+ int index = currentIndex;
+ int count = contentModel->count();
+ while (++index < count) {
+ QQuickItem *item = itemAt(index);
+ if (!item || !item->activeFocusOnTab() || !item->isEnabled())
+ continue;
+ setCurrentIndex(index, Qt::TabFocusReason);
+ return true;
+ }
+ return false;
+}
+
+bool QQuickMenuPrivate::activatePreviousItem()
+{
+ int index = currentIndex;
+ while (--index >= 0) {
+ QQuickItem *item = itemAt(index);
+ if (!item || !item->activeFocusOnTab() || !item->isEnabled())
+ continue;
+ setCurrentIndex(index, Qt::BacktabFocusReason);
+ return true;
+ }
+ return false;
+}
+
+QQuickMenuItem *QQuickMenuPrivate::firstEnabledMenuItem() const
+{
+ for (int i = 0; i < contentModel->count(); ++i) {
+ QQuickItem *item = itemAt(i);
+ if (!item || !item->isEnabled())
+ continue;
+
+ QQuickMenuItem *menuItem = qobject_cast<QQuickMenuItem *>(item);
+ if (!menuItem)
+ continue;
+
+ return menuItem;
+ }
+ return nullptr;
+}
+
+void QQuickMenuPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
+{
+ QQuickMenu *q = qobject_cast<QQuickMenu *>(prop->object);
+ QQuickMenuPrivate *p = QQuickMenuPrivate::get(q);
+
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj);
+ if (!item) {
+ if (QQuickAction *action = qobject_cast<QQuickAction *>(obj))
+ item = p->createItem(action);
+ else if (QQuickMenu *menu = qobject_cast<QQuickMenu *>(obj))
+ item = p->createItem(menu);
+ }
+
+ if (item) {
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner()) {
+ QQuickItemPrivate::get(item)->addItemChangeListener(p, QQuickItemPrivate::SiblingOrder);
+ item->setParentItem(p->contentItem);
+ } else if (p->contentModel->indexOf(item, nullptr) == -1) {
+ q->addItem(item);
+ }
+ } else {
+ p->contentData.append(obj);
+ }
+}
+
+qsizetype QQuickMenuPrivate::contentData_count(QQmlListProperty<QObject> *prop)
+{
+ QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
+ return QQuickMenuPrivate::get(q)->contentData.count();
+}
+
+QObject *QQuickMenuPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
+{
+ QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
+ return QQuickMenuPrivate::get(q)->contentData.value(index);
+}
+
+QPalette QQuickMenuPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::Menu);
+}
+
+void QQuickMenuPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
+{
+ QQuickMenu *q = static_cast<QQuickMenu *>(prop->object);
+ QQuickMenuPrivate::get(q)->contentData.clear();
+}
+
+QQuickMenu::QQuickMenu(QObject *parent)
+ : QQuickPopup(*(new QQuickMenuPrivate), parent)
+{
+ Q_D(QQuickMenu);
+ setFocus(true);
+ d->init();
+ connect(d->contentModel, &QQmlObjectModel::countChanged, this, &QQuickMenu::countChanged);
+}
+
+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.
+ while (d->contentModel->count() > 0)
+ d->removeItem(0, d->itemAt(0));
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::Menu::itemAt(int index)
+
+ Returns the item at \a index, or \c null if it does not exist.
+*/
+QQuickItem *QQuickMenu::itemAt(int index) const
+{
+ Q_D(const QQuickMenu);
+ return d->itemAt(index);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Menu::addItem(Item item)
+
+ Adds \a item to the end of the list of items.
+*/
+void QQuickMenu::addItem(QQuickItem *item)
+{
+ Q_D(QQuickMenu);
+ insertItem(d->contentModel->count(), item);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Menu::insertItem(int index, Item item)
+
+ Inserts \a item at \a index.
+*/
+void QQuickMenu::insertItem(int index, QQuickItem *item)
+{
+ Q_D(QQuickMenu);
+ if (!item)
+ return;
+ const int count = d->contentModel->count();
+ if (index < 0 || index > count)
+ index = count;
+
+ int oldIndex = d->contentModel->indexOf(item, nullptr);
+ if (oldIndex != -1) {
+ if (oldIndex < index)
+ --index;
+ if (oldIndex != index)
+ d->moveItem(oldIndex, index);
+ } else {
+ d->insertItem(index, item);
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Menu::moveItem(int from, int to)
+
+ Moves an item \a from one index \a to another.
+*/
+void QQuickMenu::moveItem(int from, int to)
+{
+ Q_D(QQuickMenu);
+ const int count = d->contentModel->count();
+ if (from < 0 || from > count - 1)
+ return;
+ if (to < 0 || to > count - 1)
+ to = count - 1;
+
+ if (from != to)
+ d->moveItem(from, to);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::removeItem(Item item)
+
+ Removes and destroys the specified \a item.
+*/
+void QQuickMenu::removeItem(QQuickItem *item)
+{
+ Q_D(QQuickMenu);
+ if (!item)
+ return;
+
+ const int index = d->contentModel->indexOf(item, nullptr);
+ if (index == -1)
+ return;
+
+ d->removeItem(index, item);
+ item->deleteLater();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod MenuItem QtQuick.Controls::Menu::takeItem(int index)
+
+ Removes and returns the item at \a index.
+
+ \note The ownership of the item is transferred to the caller.
+*/
+QQuickItem *QQuickMenu::takeItem(int index)
+{
+ Q_D(QQuickMenu);
+ const int count = d->contentModel->count();
+ if (index < 0 || index >= count)
+ return nullptr;
+
+ QQuickItem *item = itemAt(index);
+ if (item)
+ d->removeItem(index, item);
+ return item;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod Menu QtQuick.Controls::Menu::menuAt(int index)
+
+ Returns the sub-menu at \a index, or \c null if the index is not valid or
+ there is no sub-menu at the specified index.
+*/
+QQuickMenu *QQuickMenu::menuAt(int index) const
+{
+ Q_D(const QQuickMenu);
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
+
+ return item->subMenu();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::addMenu(Menu menu)
+
+ Adds \a menu as a sub-menu to the end of this menu.
+*/
+void QQuickMenu::addMenu(QQuickMenu *menu)
+{
+ Q_D(QQuickMenu);
+ insertMenu(d->contentModel->count(), menu);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::insertMenu(int index, Menu menu)
+
+ Inserts \a menu as a sub-menu at \a index. The index is within all items in the menu.
+*/
+void QQuickMenu::insertMenu(int index, QQuickMenu *menu)
+{
+ Q_D(QQuickMenu);
+ if (!menu)
+ return;
+
+ insertItem(index, d->createItem(menu));
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::removeMenu(Menu menu)
+
+ Removes and destroys the specified \a menu.
+*/
+void QQuickMenu::removeMenu(QQuickMenu *menu)
+{
+ Q_D(QQuickMenu);
+ if (!menu)
+ return;
+
+ const int count = d->contentModel->count();
+ for (int i = 0; i < count; ++i) {
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
+ if (!item || item->subMenu() != menu)
+ continue;
+
+ removeItem(item);
+ break;
+ }
+
+ menu->deleteLater();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod Menu QtQuick.Controls::Menu::takeMenu(int index)
+
+ Removes and returns the menu at \a index. The index is within all items in the menu.
+
+ \note The ownership of the menu is transferred to the caller.
+*/
+QQuickMenu *QQuickMenu::takeMenu(int index)
+{
+ Q_D(QQuickMenu);
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
+
+ QQuickMenu *subMenu = item->subMenu();
+ if (!subMenu)
+ return nullptr;
+
+ d->removeItem(index, item);
+ item->deleteLater();
+ return subMenu;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod Action QtQuick.Controls::Menu::actionAt(int index)
+
+ Returns the action at \a index, or \c null if the index is not valid or
+ there is no action at the specified index.
+*/
+QQuickAction *QQuickMenu::actionAt(int index) const
+{
+ Q_D(const QQuickMenu);
+ QQuickAbstractButton *item = qobject_cast<QQuickAbstractButton *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
+
+ return item->action();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::addAction(Action action)
+
+ Adds \a action to the end of this menu.
+*/
+void QQuickMenu::addAction(QQuickAction *action)
+{
+ Q_D(QQuickMenu);
+ insertAction(d->contentModel->count(), action);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::insertAction(int index, Action action)
+
+ Inserts \a action at \a index. The index is within all items in the menu.
+*/
+void QQuickMenu::insertAction(int index, QQuickAction *action)
+{
+ Q_D(QQuickMenu);
+ if (!action)
+ return;
+
+ insertItem(index, d->createItem(action));
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::removeAction(Action action)
+
+ Removes and destroys the specified \a action.
+*/
+void QQuickMenu::removeAction(QQuickAction *action)
+{
+ Q_D(QQuickMenu);
+ if (!action)
+ return;
+
+ const int count = d->contentModel->count();
+ for (int i = 0; i < count; ++i) {
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(i));
+ if (!item || item->action() != action)
+ continue;
+
+ removeItem(item);
+ break;
+ }
+
+ action->deleteLater();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod Action QtQuick.Controls::Menu::takeAction(int index)
+
+ Removes and returns the action at \a index. The index is within all items in the menu.
+
+ \note The ownership of the action is transferred to the caller.
+*/
+QQuickAction *QQuickMenu::takeAction(int index)
+{
+ Q_D(QQuickMenu);
+ QQuickMenuItem *item = qobject_cast<QQuickMenuItem *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
+
+ QQuickAction *action = item->action();
+ if (!action)
+ return nullptr;
+
+ d->removeItem(index, item);
+ item->deleteLater();
+ return action;
+}
+
+/*!
+ \qmlproperty model QtQuick.Controls::Menu::contentModel
+ \readonly
+
+ This property holds the model used to display menu items.
+
+ The content model is provided for visualization purposes. It can be assigned
+ as a model to a content item that presents the contents of the menu.
+
+ \code
+ Menu {
+ id: menu
+ contentItem: ListView {
+ model: menu.contentModel
+ }
+ }
+ \endcode
+
+ The model allows menu items to be statically declared as children of the
+ menu.
+*/
+QVariant QQuickMenu::contentModel() const
+{
+ Q_D(const QQuickMenu);
+ return QVariant::fromValue(d->contentModel);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::Menu::contentData
+ \qmldefault
+
+ This property holds the list of content data.
+
+ The list contains all objects that have been declared in QML as children
+ of the menu, and also items that have been dynamically added or
+ inserted using the \l addItem() and \l insertItem() methods, respectively.
+
+ \note Unlike \c contentChildren, \c contentData does include non-visual QML
+ objects. It is not re-ordered when items are inserted or moved.
+
+ \sa Item::data, {Popup::}{contentChildren}
+*/
+QQmlListProperty<QObject> QQuickMenu::contentData()
+{
+ Q_D(QQuickMenu);
+ if (!d->contentItem)
+ QQuickControlPrivate::get(d->popupItem)->executeContentItem();
+ return QQmlListProperty<QObject>(this, nullptr,
+ QQuickMenuPrivate::contentData_append,
+ QQuickMenuPrivate::contentData_count,
+ QQuickMenuPrivate::contentData_at,
+ QQuickMenuPrivate::contentData_clear);
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::Menu::title
+
+ This property holds the title for the menu.
+
+ The title of a menu is often displayed in the text of a menu item when the
+ menu is a submenu, and in the text of a tool button when it is in a
+ menubar.
+*/
+QString QQuickMenu::title() const
+{
+ Q_D(const QQuickMenu);
+ return d->title;
+}
+
+void QQuickMenu::setTitle(QString &title)
+{
+ Q_D(QQuickMenu);
+ if (title == d->title)
+ return;
+ d->title = title;
+ emit titleChanged(title);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Menu::cascade
+
+ This property holds whether the menu cascades its sub-menus.
+
+ The default value is platform-specific. Menus are cascading by default on
+ desktop platforms that have a mouse cursor available. Non-cascading menus
+ are shown one menu at a time, and centered over the parent menu.
+
+ \note Changing the value of the property has no effect while the menu is open.
+
+ \sa overlap
+*/
+bool QQuickMenu::cascade() const
+{
+ Q_D(const QQuickMenu);
+ return d->cascade;
+}
+
+void QQuickMenu::setCascade(bool cascade)
+{
+ Q_D(QQuickMenu);
+ if (d->cascade == cascade)
+ return;
+ d->cascade = cascade;
+ if (d->parentMenu)
+ d->resolveParentItem();
+ emit cascadeChanged(cascade);
+}
+
+void QQuickMenu::resetCascade()
+{
+ Q_D(QQuickMenu);
+ if (d->parentMenu)
+ setCascade(d->parentMenu->cascade());
+ else
+ setCascade(shouldCascade());
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty real QtQuick.Controls::Menu::overlap
+
+ This property holds the amount of pixels by which the menu horizontally overlaps its parent menu.
+
+ The property only has effect when the menu is used as a cascading sub-menu.
+
+ The default value is style-specific.
+
+ \note Changing the value of the property has no effect while the menu is open.
+
+ \sa cascade
+*/
+qreal QQuickMenu::overlap() const
+{
+ Q_D(const QQuickMenu);
+ return d->overlap;
+}
+
+void QQuickMenu::setOverlap(qreal overlap)
+{
+ Q_D(QQuickMenu);
+ if (d->overlap == overlap)
+ return;
+ d->overlap = overlap;
+ emit overlapChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Component QtQuick.Controls::Menu::delegate
+
+ This property holds the component that is used to create items
+ to present actions.
+
+ \code
+ Menu {
+ Action { text: "Cut" }
+ Action { text: "Copy" }
+ Action { text: "Paste" }
+ }
+ \endcode
+
+ \sa Action
+*/
+QQmlComponent *QQuickMenu::delegate() const
+{
+ Q_D(const QQuickMenu);
+ return d->delegate;
+}
+
+void QQuickMenu::setDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickMenu);
+ if (d->delegate == delegate)
+ return;
+
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty int QtQuick.Controls::Menu::currentIndex
+
+ This property holds the index of the currently highlighted item.
+
+ Menu items can be highlighted by mouse hover or keyboard navigation.
+
+ \sa MenuItem::highlighted
+*/
+int QQuickMenu::currentIndex() const
+{
+ Q_D(const QQuickMenu);
+ return d->currentIndex;
+}
+
+void QQuickMenu::setCurrentIndex(int index)
+{
+ Q_D(QQuickMenu);
+ d->setCurrentIndex(index, Qt::OtherFocusReason);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty int QtQuick.Controls::Menu::count
+ \readonly
+
+ This property holds the number of items.
+*/
+int QQuickMenu::count() const
+{
+ Q_D(const QQuickMenu);
+ return d->contentModel->count();
+}
+
+void QQuickMenu::popup(QQuickItem *menuItem)
+{
+ Q_D(QQuickMenu);
+ // No position has been explicitly specified, so position the menu at the mouse cursor
+ // on desktop platforms that have a mouse cursor available and support multiple windows.
+ QQmlNullableValue<QPointF> pos;
+#if QT_CONFIG(cursor)
+ if (d->parentItem && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows))
+ pos = d->parentItem->mapFromGlobal(QCursor::pos());
+#endif
+
+ // As a fallback, center the menu over its parent item.
+ if (pos.isNull && d->parentItem)
+ pos = QPointF((d->parentItem->width() - width()) / 2, (d->parentItem->height() - height()) / 2);
+
+ popup(pos.isNull ? QPointF() : pos.value, menuItem);
+}
+
+void QQuickMenu::popup(const QPointF &pos, QQuickItem *menuItem)
+{
+ Q_D(QQuickMenu);
+ qreal offset = 0;
+#if QT_CONFIG(cursor)
+ if (menuItem)
+ offset = d->popupItem->mapFromItem(menuItem, QPointF(0, 0)).y();
+#endif
+ setPosition(pos - QPointF(0, offset));
+
+ if (menuItem)
+ d->setCurrentIndex(d->contentModel->indexOf(menuItem, nullptr), Qt::PopupFocusReason);
+ open();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::popup(MenuItem item = null)
+ \qmlmethod void QtQuick.Controls::Menu::popup(Item parent, MenuItem item = null)
+
+ Opens the menu at the mouse cursor on desktop platforms that have a mouse cursor
+ available, and otherwise centers the menu over its \a parent item.
+
+ The menu can be optionally aligned to a specific menu \a item.
+
+ \sa Popup::open()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::popup(point pos, MenuItem item = null)
+ \qmlmethod void QtQuick.Controls::Menu::popup(Item parent, point pos, MenuItem item = null)
+
+ Opens the menu at the specified position \a pos in the popups coordinate system,
+ that is, a coordinate relative to its \a parent item.
+
+ The menu can be optionally aligned to a specific menu \a item.
+
+ \sa Popup::open()
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::popup(real x, real y, MenuItem item = null)
+ \qmlmethod void QtQuick.Controls::Menu::popup(Item parent, real x, real y, MenuItem item = null)
+
+ Opens the menu at the specified position \a x, \a y in the popups coordinate system,
+ that is, a coordinate relative to its \a parent item.
+
+ The menu can be optionally aligned to a specific menu \a item.
+
+ \sa dismiss(), Popup::open()
+*/
+void QQuickMenu::popup(QQmlV4Function *args)
+{
+ Q_D(QQuickMenu);
+ const int len = args->length();
+ if (len > 4) {
+ args->v4engine()->throwTypeError();
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ QQmlNullableValue<QPointF> pos;
+ QQuickItem *menuItem = nullptr;
+ QQuickItem *parentItem = nullptr;
+
+ if (len > 0) {
+ // Item parent
+ QV4::ScopedValue firstArg(scope, (*args)[0]);
+ if (const QV4::QObjectWrapper *obj = firstArg->as<QV4::QObjectWrapper>()) {
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj->object());
+ if (item && !d->popupItem->isAncestorOf(item))
+ parentItem = item;
+ } else if (firstArg->isUndefined()) {
+ resetParentItem();
+ parentItem = d->parentItem;
+ }
+
+ // MenuItem item
+ QV4::ScopedValue lastArg(scope, (*args)[len - 1]);
+ if (const QV4::QObjectWrapper *obj = lastArg->as<QV4::QObjectWrapper>()) {
+ QQuickItem *item = qobject_cast<QQuickItem *>(obj->object());
+ if (item && d->popupItem->isAncestorOf(item))
+ menuItem = item;
+ }
+ }
+
+ if (len >= 3 || (!parentItem && len >= 2)) {
+ // real x, real y
+ QV4::ScopedValue xArg(scope, (*args)[parentItem ? 1 : 0]);
+ QV4::ScopedValue yArg(scope, (*args)[parentItem ? 2 : 1]);
+ if (xArg->isNumber() && yArg->isNumber())
+ pos = QPointF(xArg->asDouble(), yArg->asDouble());
+ }
+
+ if (pos.isNull && (len >= 2 || (!parentItem && len >= 1))) {
+ // point pos
+ QV4::ScopedValue posArg(scope, (*args)[parentItem ? 1 : 0]);
+ const QVariant var = v4->toVariant(posArg, QMetaType {});
+ if (var.userType() == QMetaType::QPointF)
+ pos = var.toPointF();
+ }
+
+ if (parentItem)
+ setParentItem(parentItem);
+
+ if (pos.isNull)
+ popup(menuItem);
+ else
+ popup(pos, menuItem);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlmethod void QtQuick.Controls::Menu::dismiss()
+
+ 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
+ hierarchy of menus, and \c dismiss() is the appropriate method for closing
+ the whole hierarchy of menus.
+
+ \sa popup(), Popup::close()
+*/
+void QQuickMenu::dismiss()
+{
+ QQuickMenu *menu = this;
+ while (menu) {
+ menu->close();
+ menu = QQuickMenuPrivate::get(menu)->parentMenu;
+ }
+}
+
+void QQuickMenu::componentComplete()
+{
+ Q_D(QQuickMenu);
+ QQuickPopup::componentComplete();
+ d->resizeItems();
+}
+
+void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickMenu);
+ QQuickPopup::contentItemChange(newItem, oldItem);
+
+ if (oldItem) {
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ }
+ if (newItem) {
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
+ QQuickItemPrivate::get(newItem)->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Width);
+ }
+
+ d->contentItem = newItem;
+}
+
+void QQuickMenu::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ Q_D(QQuickMenu);
+ QQuickPopup::itemChange(change, data);
+
+ if (change == 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);
+ }
+ }
+}
+
+void QQuickMenu::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickMenu);
+ QQuickPopup::keyPressEvent(event);
+
+ // QTBUG-17051
+ // Work around the fact that ListView has no way of distinguishing between
+ // mouse and keyboard interaction, thanks to the "interactive" bool in Flickable.
+ // What we actually want is to have a way to always allow keyboard interaction but
+ // only allow flicking with the mouse when there are too many menu items to be
+ // shown at once.
+ switch (event->key()) {
+ case Qt::Key_Up:
+ if (!d->activatePreviousItem())
+ d->propagateKeyEvent(event);
+ break;
+
+ case Qt::Key_Down:
+ d->activateNextItem();
+ break;
+
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ event->ignore();
+ if (d->popupItem->isMirrored() == (event->key() == Qt::Key_Right)) {
+ if (d->parentMenu && d->currentItem) {
+ if (!d->cascade)
+ d->parentMenu->open();
+ close();
+ event->accept();
+ }
+ } else {
+ if (QQuickMenu *subMenu = d->currentSubMenu()) {
+ auto subMenuPrivate = QQuickMenuPrivate::get(subMenu);
+ subMenu->popup(subMenuPrivate->firstEnabledMenuItem());
+ event->accept();
+ }
+ }
+ if (!event->isAccepted())
+ d->propagateKeyEvent(event);
+ break;
+
+#if QT_CONFIG(shortcut)
+ case Qt::Key_Alt:
+ // If &mnemonic shortcut is enabled, go back to (possibly) the parent
+ // menu bar so the shortcut key will be processed by the menu bar.
+ if (!QKeySequence::mnemonic(QStringLiteral("&A")).isEmpty())
+ close();
+ break;
+#endif
+
+ default:
+ break;
+ }
+}
+
+void QQuickMenu::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickMenu);
+ if (event->timerId() == d->hoverTimer) {
+ if (QQuickMenu *subMenu = d->currentSubMenu())
+ subMenu->open();
+ d->stopHoverTimer();
+ return;
+ }
+ QQuickPopup::timerEvent(event);
+}
+
+QFont QQuickMenu::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Menu);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickMenu::accessibleRole() const
+{
+ return QAccessible::PopupMenu;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmenu_p.cpp"
diff --git a/src/quicktemplates2/qquickmenu_p.h b/src/quicktemplates2/qquickmenu_p.h
new file mode 100644
index 0000000000..4a690f9c8c
--- /dev/null
+++ b/src/quicktemplates2/qquickmenu_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENU_P_H
+#define QQUICKMENU_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/qqmllist.h>
+#include <QtQml/qqml.h>
+
+#include "qquickpopup_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQmlComponent;
+class QQuickMenuItem;
+class QQuickMenuPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenu : public QQuickPopup
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant contentModel READ contentModel CONSTANT FINAL)
+ Q_PROPERTY(QQmlListProperty<QObject> contentData READ contentData FINAL)
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(int count READ count NOTIFY countChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool cascade READ cascade WRITE setCascade RESET resetCascade NOTIFY cascadeChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(qreal overlap READ overlap WRITE setOverlap NOTIFY overlapChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL REVISION(2, 3))
+ Q_CLASSINFO("DefaultProperty", "contentData")
+ QML_NAMED_ELEMENT(Menu)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickMenu(QObject *parent = nullptr);
+ ~QQuickMenu();
+
+ Q_INVOKABLE QQuickItem *itemAt(int index) const;
+ Q_INVOKABLE void addItem(QQuickItem *item);
+ Q_INVOKABLE void insertItem(int index, QQuickItem *item);
+ Q_INVOKABLE void moveItem(int from, int to);
+ Q_INVOKABLE void removeItem(QQuickItem *item);
+
+ QVariant contentModel() const;
+ QQmlListProperty<QObject> contentData();
+
+ QString title() const;
+ void setTitle(QString &title);
+
+ bool cascade() const;
+ void setCascade(bool cascade);
+ void resetCascade();
+
+ qreal overlap() const;
+ void setOverlap(qreal overlap);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ int currentIndex() const;
+ void setCurrentIndex(int index);
+
+ // 2.3 (Qt 5.10)
+ int count() const;
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickItem *takeItem(int index);
+
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickMenu *menuAt(int index) const;
+ Q_REVISION(2, 3) Q_INVOKABLE void addMenu(QQuickMenu *menu);
+ Q_REVISION(2, 3) Q_INVOKABLE void insertMenu(int index, QQuickMenu *menu);
+ Q_REVISION(2, 3) Q_INVOKABLE void removeMenu(QQuickMenu *menu);
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickMenu *takeMenu(int index);
+
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickAction *actionAt(int index) const;
+ Q_REVISION(2, 3) Q_INVOKABLE void addAction(QQuickAction *action);
+ Q_REVISION(2, 3) Q_INVOKABLE void insertAction(int index, QQuickAction *action);
+ Q_REVISION(2, 3) Q_INVOKABLE void removeAction(QQuickAction *action);
+ Q_REVISION(2, 3) Q_INVOKABLE QQuickAction *takeAction(int index);
+
+ void popup(QQuickItem *menuItem = nullptr);
+ void popup(const QPointF &pos, QQuickItem *menuItem = nullptr);
+
+ Q_REVISION(2, 3) Q_INVOKABLE void popup(QQmlV4Function *args);
+ Q_REVISION(2, 3) Q_INVOKABLE void dismiss();
+
+protected:
+ void componentComplete() override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override;
+ void keyPressEvent(QKeyEvent *event) override;
+
+Q_SIGNALS:
+ void titleChanged(const QString &title);
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void countChanged();
+ Q_REVISION(2, 3) void cascadeChanged(bool cascade);
+ Q_REVISION(2, 3) void overlapChanged();
+ Q_REVISION(2, 3) void delegateChanged();
+ Q_REVISION(2, 3) void currentIndexChanged();
+
+protected:
+ void timerEvent(QTimerEvent *event) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenu)
+ Q_DECLARE_PRIVATE(QQuickMenu)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenu)
+
+#endif // QQUICKMENU_P_H
diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h
new file mode 100644
index 0000000000..86701d9bef
--- /dev/null
+++ b/src/quicktemplates2/qquickmenu_p_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENU_P_P_H
+#define QQUICKMENU_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 <QtCore/qlist.h>
+#include <QtCore/qpointer.h>
+
+#include <QtQuickTemplates2/private/qquickmenu_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickAction;
+class QQmlComponent;
+class QQmlObjectModel;
+class QQuickMenuItem;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuPrivate : public QQuickPopupPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickMenu)
+
+public:
+ QQuickMenuPrivate();
+
+ static QQuickMenuPrivate *get(QQuickMenu *menu)
+ {
+ return menu->d_func();
+ }
+
+ void init();
+
+ QQuickItem *itemAt(int index) const;
+ void insertItem(int index, QQuickItem *item);
+ void moveItem(int from, int to);
+ void removeItem(int index, QQuickItem *item);
+
+ QQuickItem *beginCreateItem();
+ void completeCreateItem();
+
+ QQuickItem *createItem(QQuickMenu *menu);
+ QQuickItem *createItem(QQuickAction *action);
+
+ void resizeItem(QQuickItem *item);
+ void resizeItems();
+
+ void itemChildAdded(QQuickItem *item, QQuickItem *child) override;
+ void itemSiblingOrderChanged(QQuickItem *item) override;
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
+ void itemDestroyed(QQuickItem *item) override;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &diff) override;
+
+ QQuickPopupPositioner *getPositioner() override;
+ bool prepareEnterTransition() override;
+ bool prepareExitTransition() override;
+ bool blockInput(QQuickItem *item, const QPointF &point) const override;
+
+ void onItemHovered();
+ void onItemTriggered();
+ void onItemActiveFocusChanged();
+
+ QQuickMenu *currentSubMenu() const;
+ void setParentMenu(QQuickMenu *parent);
+ void resolveParentItem();
+
+ void propagateKeyEvent(QKeyEvent *event);
+
+ void startHoverTimer();
+ void stopHoverTimer();
+
+ void setCurrentIndex(int index, Qt::FocusReason reason);
+ bool activateNextItem();
+ bool activatePreviousItem();
+
+ QQuickMenuItem *firstEnabledMenuItem() const;
+
+ static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+ static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
+ static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
+ static void contentData_clear(QQmlListProperty<QObject> *prop);
+
+ QPalette defaultPalette() const override;
+
+ bool cascade = false;
+ int hoverTimer = 0;
+ int currentIndex = -1;
+ qreal overlap = 0;
+ QPointer<QQuickMenu> parentMenu;
+ QPointer<QQuickMenuItem> currentItem;
+ QQuickItem *contentItem = nullptr; // TODO: cleanup
+ QList<QObject *> contentData;
+ QQmlObjectModel *contentModel;
+ QQmlComponent *delegate = nullptr;
+ QString title;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMENU_P_P_H
diff --git a/src/quicktemplates2/qquickmenubar.cpp b/src/quicktemplates2/qquickmenubar.cpp
new file mode 100644
index 0000000000..a732d88931
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubar.cpp
@@ -0,0 +1,581 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenubar_p.h"
+#include "qquickmenubar_p_p.h"
+#include "qquickmenubaritem_p_p.h"
+#include "qquickmenu_p.h"
+#include "qquickmenu_p_p.h"
+
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuBar
+ \inherits Container
+//! \instantiates QQuickMenuBar
+ \inqmlmodule QtQuick.Controls
+ \since 5.10
+ \ingroup qtquickcontrols2-menus
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Provides a window menu bar.
+
+ \image qtquickcontrols2-menubar.png
+
+ MenuBar consists of drop-down menus, and is normally located at the top
+ edge of the window.
+
+ \quotefromfile qtquickcontrols2-menubar.qml
+ \skipuntil begin
+ \printto skipfrom
+ \skipuntil skipto
+ \printto end
+
+ Typically, menus are statically declared as children of the menu bar, but
+ MenuBar also provides API to \l {addMenu}{add}, \l {insertMenu}{insert},
+ \l {removeMenu}{remove}, and \l {takeMenu}{take} menus dynamically. The
+ menus in a menu bar can be accessed using \l menuAt().
+
+ \sa {Customizing MenuBar}, Menu, MenuBarItem, {Menu Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+QQuickItem *QQuickMenuBarPrivate::beginCreateItem(QQuickMenu *menu)
+{
+ Q_Q(QQuickMenuBar);
+ if (!delegate)
+ return nullptr;
+
+ QQmlContext *creationContext = delegate->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext, q);
+ context->setContextObject(q);
+
+ QObject *object = delegate->beginCreate(context);
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item) {
+ delete object;
+ delete context;
+ return nullptr;
+ }
+
+ if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item))
+ menuBarItem->setMenu(menu);
+ item->setParentItem(q);
+ QQml_setParent_noEvent(item, q);
+
+ return item;
+}
+
+void QQuickMenuBarPrivate::completeCreateItem()
+{
+ if (!delegate)
+ return;
+
+ delegate->completeCreate();
+}
+
+QQuickItem *QQuickMenuBarPrivate::createItem(QQuickMenu *menu)
+{
+ QQuickItem *item = beginCreateItem(menu);
+ completeCreateItem();
+ return item;
+}
+
+void QQuickMenuBarPrivate::toggleCurrentMenu(bool visible, bool activate)
+{
+ if (!currentItem || visible == popupMode)
+ return;
+
+ QQuickMenu *menu = currentItem->menu();
+
+ triggering = true;
+ popupMode = visible;
+ if (menu)
+ menu->setVisible(visible);
+ if (!visible)
+ currentItem->forceActiveFocus();
+ else if (menu && activate)
+ menu->setCurrentIndex(0);
+ triggering = false;
+}
+
+void QQuickMenuBarPrivate::activateItem(QQuickMenuBarItem *item)
+{
+ if (currentItem == item)
+ return;
+
+ 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();
+ }
+ }
+
+ currentItem = item;
+}
+
+void QQuickMenuBarPrivate::activateNextItem()
+{
+ int index = currentItem ? contentModel->indexOf(currentItem, nullptr) : -1;
+ if (index >= contentModel->count() - 1)
+ index = -1;
+ activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(++index)));
+}
+
+void QQuickMenuBarPrivate::activatePreviousItem()
+{
+ int index = currentItem ? contentModel->indexOf(currentItem, nullptr) : contentModel->count();
+ if (index <= 0)
+ index = contentModel->count();
+ activateItem(qobject_cast<QQuickMenuBarItem *>(itemAt(--index)));
+}
+
+void QQuickMenuBarPrivate::onItemHovered()
+{
+ Q_Q(QQuickMenuBar);
+ QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(q->sender());
+ if (!item || item == currentItem || !item->isHovered() || !item->isEnabled() || QQuickMenuBarItemPrivate::get(item)->touchId != -1)
+ return;
+
+ activateItem(item);
+}
+
+void QQuickMenuBarPrivate::onItemTriggered()
+{
+ Q_Q(QQuickMenuBar);
+ QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(q->sender());
+ if (!item)
+ return;
+
+ if (item == currentItem) {
+ toggleCurrentMenu(!popupMode, false);
+ } else {
+ popupMode = true;
+ activateItem(item);
+ }
+}
+
+void QQuickMenuBarPrivate::onMenuAboutToHide()
+{
+ if (triggering || !currentItem || (currentItem->isHovered() && currentItem->isEnabled()) || !currentItem->isHighlighted())
+ return;
+
+ popupMode = false;
+ activateItem(nullptr);
+}
+
+qreal QQuickMenuBarPrivate::getContentWidth() const
+{
+ Q_Q(const QQuickMenuBar);
+ const int count = contentModel->count();
+ qreal totalWidth = qMax(0, count - 1) * spacing;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item)
+ totalWidth += item->implicitWidth();
+ }
+ return totalWidth;
+}
+
+qreal QQuickMenuBarPrivate::getContentHeight() const
+{
+ Q_Q(const QQuickMenuBar);
+ const int count = contentModel->count();
+ qreal maxHeight = 0;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item)
+ maxHeight = qMax(maxHeight, item->implicitHeight());
+ }
+ return maxHeight;
+}
+
+void QQuickMenuBarPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitWidthChanged(item);
+ if (item != contentItem)
+ updateImplicitContentWidth();
+}
+
+void QQuickMenuBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitHeightChanged(item);
+ if (item != contentItem)
+ updateImplicitContentHeight();
+}
+
+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);
+ QQuickContainerPrivate::contentData_append(prop, obj);
+}
+
+void QQuickMenuBarPrivate::menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj)
+{
+ QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ menuBar->addMenu(obj);
+}
+
+qsizetype QQuickMenuBarPrivate::menus_count(QQmlListProperty<QQuickMenu> *prop)
+{
+ QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ return menuBar->count();
+}
+
+QQuickMenu *QQuickMenuBarPrivate::menus_at(QQmlListProperty<QQuickMenu> *prop, qsizetype index)
+{
+ QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ return menuBar->menuAt(index);
+}
+
+void QQuickMenuBarPrivate::menus_clear(QQmlListProperty<QQuickMenu> *prop)
+{
+ QQuickMenuBar *menuBar = static_cast<QQuickMenuBar *>(prop->object);
+ QQuickMenuBarPrivate::get(menuBar)->contentModel->clear();
+}
+
+QPalette QQuickMenuBarPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::MenuBar);
+}
+
+QQuickMenuBar::QQuickMenuBar(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickMenuBarPrivate), parent)
+{
+ Q_D(QQuickMenuBar);
+ d->changeTypes |= QQuickItemPrivate::Geometry;
+ setFlag(ItemIsFocusScope);
+ setFocusPolicy(Qt::ClickFocus);
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::MenuBar::delegate
+
+ This property holds the component that is used to create menu bar
+ items to present menus in the menu bar.
+
+ \sa MenuBarItem
+*/
+QQmlComponent *QQuickMenuBar::delegate() const
+{
+ Q_D(const QQuickMenuBar);
+ return d->delegate;
+}
+
+void QQuickMenuBar::setDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickMenuBar);
+ if (d->delegate == delegate)
+ return;
+
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+/*!
+ \qmlmethod Menu QtQuick.Controls::MenuBar::menuAt(int index)
+
+ Returns the menu at \a index, or \c null if it does not exist.
+*/
+QQuickMenu *QQuickMenuBar::menuAt(int index) const
+{
+ Q_D(const QQuickMenuBar);
+ QQuickMenuBarItem *item = qobject_cast<QQuickMenuBarItem *>(d->itemAt(index));
+ if (!item)
+ return nullptr;
+ return item->menu();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::MenuBar::addMenu(Menu menu)
+
+ Adds \a menu to the end of the list of menus.
+*/
+void QQuickMenuBar::addMenu(QQuickMenu *menu)
+{
+ Q_D(QQuickMenuBar);
+ addItem(d->createItem(menu));
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::MenuBar::insertMenu(int index, Menu menu)
+
+ Inserts \a menu at \a index.
+*/
+void QQuickMenuBar::insertMenu(int index, QQuickMenu *menu)
+{
+ Q_D(QQuickMenuBar);
+ insertItem(index, d->createItem(menu));
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::MenuBar::removeMenu(Menu menu)
+
+ Removes and destroys the specified \a menu.
+*/
+void QQuickMenuBar::removeMenu(QQuickMenu *menu)
+{
+ Q_D(QQuickMenuBar);
+ if (!menu)
+ 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();
+}
+
+/*!
+ \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.
+*/
+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)
+ return nullptr;
+
+ d->removeItem(index, item);
+ item->deleteLater();
+ return menu;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty real QtQuick.Controls::MenuBar::contentWidth
+
+ This property holds the content width. It is used for calculating the total
+ implicit width of the menu bar.
+
+ \note This property is available in MenuBar since QtQuick.Controls 2.3 (Qt 5.10),
+ but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
+
+ \sa Container::contentWidth
+*/
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty real QtQuick.Controls::MenuBar::contentHeight
+
+ This property holds the content height. It is used for calculating the total
+ implicit height of the menu bar.
+
+ \note This property is available in MenuBar since QtQuick.Controls 2.3 (Qt 5.10),
+ but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
+
+ \sa Container::contentHeight
+*/
+
+/*!
+ \qmlproperty list<Menu> QtQuick.Controls::MenuBar::menus
+
+ This property holds the list of menus.
+
+ The list contains all menus that have been declared in QML as children
+ of the menu bar, and also menus that have been dynamically added or
+ inserted using the \l addMenu() and \l insertMenu() methods, respectively.
+*/
+QQmlListProperty<QQuickMenu> QQuickMenuBarPrivate::menus()
+{
+ Q_Q(QQuickMenuBar);
+ return QQmlListProperty<QQuickMenu>(q, nullptr,
+ QQuickMenuBarPrivate::menus_append,
+ QQuickMenuBarPrivate::menus_count,
+ QQuickMenuBarPrivate::menus_at,
+ QQuickMenuBarPrivate::menus_clear);
+}
+
+QQmlListProperty<QObject> QQuickMenuBarPrivate::contentData()
+{
+ Q_Q(QQuickMenuBar);
+ return QQmlListProperty<QObject>(q, nullptr,
+ QQuickMenuBarPrivate::contentData_append,
+ QQuickContainerPrivate::contentData_count,
+ QQuickContainerPrivate::contentData_at,
+ QQuickContainerPrivate::contentData_clear);
+}
+
+bool QQuickMenuBar::eventFilter(QObject *object, QEvent *event)
+{
+ return QObject::eventFilter(object, event);
+}
+
+void QQuickMenuBar::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::keyReleaseEvent(event);
+
+ switch (event->key()) {
+ case Qt::Key_Up:
+ d->toggleCurrentMenu(false, false);
+ break;
+
+ case Qt::Key_Down:
+ d->toggleCurrentMenu(true, true);
+ break;
+
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ if (isMirrored() == (event->key() == Qt::Key_Left))
+ d->activateNextItem();
+ else
+ d->activatePreviousItem();
+ break;
+ case Qt::Key_Escape:
+ if (d->currentItem) {
+ d->activateItem(nullptr);
+ setFocus(false);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickMenuBar::keyReleaseEvent(QKeyEvent *event)
+{
+ QQuickContainer::keyReleaseEvent(event);
+
+ switch (event->key()) {
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Left:
+ case Qt::Key_Right:
+ case Qt::Key_Escape:
+ event->accept();
+ break;
+
+ default:
+ event->ignore();
+ break;
+ }
+}
+
+void QQuickMenuBar::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::hoverLeaveEvent(event);
+ if (!d->popupMode && d->currentItem)
+ d->activateItem(nullptr);
+}
+
+bool QQuickMenuBar::isContent(QQuickItem *item) const
+{
+ return qobject_cast<QQuickMenuBarItem *>(item);
+}
+
+void QQuickMenuBar::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::itemAdded(index, item);
+ if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
+ QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(this);
+ 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);
+ }
+ d->updateImplicitContentSize();
+ emit menusChanged();
+}
+
+void QQuickMenuBar::itemMoved(int index, QQuickItem *item)
+{
+ QQuickContainer::itemMoved(index, item);
+ emit menusChanged();
+}
+
+void QQuickMenuBar::itemRemoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickMenuBar);
+ QQuickContainer::itemRemoved(index, item);
+ if (QQuickMenuBarItem *menuBarItem = qobject_cast<QQuickMenuBarItem *>(item)) {
+ QQuickMenuBarItemPrivate::get(menuBarItem)->setMenuBar(nullptr);
+ 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);
+ }
+ d->updateImplicitContentSize();
+ emit menusChanged();
+}
+
+QFont QQuickMenuBar::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::MenuBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickMenuBar::accessibleRole() const
+{
+ return QAccessible::MenuBar;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmenubar_p.cpp"
diff --git a/src/quicktemplates2/qquickmenubar_p.h b/src/quicktemplates2/qquickmenubar_p.h
new file mode 100644
index 0000000000..5eb5dabfdd
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubar_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUBAR_P_H
+#define QQUICKMENUBAR_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenu;
+class QQuickMenuBarPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBar : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ Q_PRIVATE_PROPERTY(QQuickMenuBar::d_func(), QQmlListProperty<QQuickMenu> menus READ menus NOTIFY menusChanged FINAL)
+ Q_PRIVATE_PROPERTY(QQuickMenuBar::d_func(), QQmlListProperty<QObject> contentData READ contentData FINAL)
+ QML_NAMED_ELEMENT(MenuBar)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickMenuBar(QQuickItem *parent = nullptr);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ Q_INVOKABLE QQuickMenu *menuAt(int index) const;
+ Q_INVOKABLE void addMenu(QQuickMenu *menu);
+ Q_INVOKABLE void insertMenu(int index, QQuickMenu *menu);
+ Q_INVOKABLE void removeMenu(QQuickMenu *menu);
+ Q_INVOKABLE QQuickMenu *takeMenu(int index);
+
+Q_SIGNALS:
+ void delegateChanged();
+ void menusChanged();
+
+protected:
+ bool eventFilter(QObject *object, QEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+
+ bool isContent(QQuickItem *item) const override;
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemMoved(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenuBar)
+ Q_DECLARE_PRIVATE(QQuickMenuBar)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenuBar)
+
+#endif // QQUICKMENUBAR_P_H
diff --git a/src/quicktemplates2/qquickmenubar_p_p.h b/src/quicktemplates2/qquickmenubar_p_p.h
new file mode 100644
index 0000000000..0562d7e5dc
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubar_p_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUBAR_P_P_H
+#define QQUICKMENUBAR_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 <QtQuickTemplates2/private/qquickmenubar_p.h>
+#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickMenuBarItem;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBarPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickMenuBar)
+
+public:
+ static QQuickMenuBarPrivate *get(QQuickMenuBar *menuBar)
+ {
+ return menuBar->d_func();
+ }
+
+ QQmlListProperty<QQuickMenu> menus();
+ QQmlListProperty<QObject> contentData();
+
+ QQuickItem *beginCreateItem(QQuickMenu *menu);
+ void completeCreateItem();
+
+ QQuickItem *createItem(QQuickMenu *menu);
+
+ void toggleCurrentMenu(bool visible, bool activate);
+ void activateItem(QQuickMenuBarItem *item);
+ void activateNextItem();
+ void activatePreviousItem();
+
+ void onItemHovered();
+ void onItemTriggered();
+ void onMenuAboutToHide();
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+
+ static void menus_append(QQmlListProperty<QQuickMenu> *prop, QQuickMenu *obj);
+ static qsizetype menus_count(QQmlListProperty<QQuickMenu> *prop);
+ static QQuickMenu *menus_at(QQmlListProperty<QQuickMenu> *prop, qsizetype index);
+ static void menus_clear(QQmlListProperty<QQuickMenu> *prop);
+
+ QPalette defaultPalette() const override;
+
+ bool popupMode = false;
+ bool triggering = false;
+ QQmlComponent *delegate = nullptr;
+ QPointer<QQuickMenuBarItem> currentItem;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMENUBAR_P_P_H
diff --git a/src/quicktemplates2/qquickmenubaritem.cpp b/src/quicktemplates2/qquickmenubaritem.cpp
new file mode 100644
index 0000000000..de43adb6a3
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubaritem.cpp
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenubaritem_p.h"
+#include "qquickmenubaritem_p_p.h"
+#include "qquickmenubar_p.h"
+#include "qquickmenu_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuBarItem
+ \inherits AbstractButton
+//! \instantiates QQuickMenuBarItem
+ \inqmlmodule QtQuick.Controls
+ \since 5.10
+ \ingroup qtquickcontrols2-menus
+ \brief Presents a drop-down menu within a MenuBar.
+
+ MenuBarItem presents a Menu within a MenuBar. The respective drop-down menu
+ is shown when a MenuBarItem is \l triggered via keyboard, mouse, or touch.
+
+ \image qtquickcontrols2-menubar.png
+
+ MenuBarItem is used as a default \l {MenuBar::}{delegate} type for MenuBar.
+ Notice that it is not necessary to declare MenuBarItem instances by hand when
+ using MenuBar. It is sufficient to declare Menu instances as children of the
+ MenuBar and the respective items are created automatically.
+
+ \sa {Customizing MenuBar}, MenuBar, {Menu Controls}
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::MenuBarItem::triggered()
+
+ This signal is emitted when the menu bar item is triggered by the user.
+*/
+
+void QQuickMenuBarItemPrivate::setMenuBar(QQuickMenuBar *newMenuBar)
+{
+ Q_Q(QQuickMenuBarItem);
+ if (menuBar == newMenuBar)
+ return;
+
+ menuBar = newMenuBar;
+ emit q->menuBarChanged();
+}
+
+QPalette QQuickMenuBarItemPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::MenuBar);
+}
+
+QQuickMenuBarItem::QQuickMenuBarItem(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickMenuBarItemPrivate), parent)
+{
+ setFocusPolicy(Qt::NoFocus);
+ connect(this, &QQuickAbstractButton::clicked, this, &QQuickMenuBarItem::triggered);
+}
+
+/*!
+ \qmlproperty Menu QtQuick.Controls::MenuBarItem::menuBar
+ \readonly
+
+ This property holds the menu bar that contains this item,
+ or \c null if the item is not in a menu bar.
+*/
+QQuickMenuBar *QQuickMenuBarItem::menuBar() const
+{
+ Q_D(const QQuickMenuBarItem);
+ return d->menuBar;
+}
+
+/*!
+ \qmlproperty Menu QtQuick.Controls::MenuBarItem::menu
+
+ This property holds the menu that this item presents in a
+ menu bar, or \c null if this item does not have a menu.
+*/
+QQuickMenu *QQuickMenuBarItem::menu() const
+{
+ Q_D(const QQuickMenuBarItem);
+ return d->menu;
+}
+
+void QQuickMenuBarItem::setMenu(QQuickMenu *menu)
+{
+ Q_D(QQuickMenuBarItem);
+ if (d->menu == menu)
+ return;
+
+ if (d->menu)
+ disconnect(d->menu, &QQuickMenu::titleChanged, this, &QQuickAbstractButton::setText);
+
+ if (menu) {
+ setText(menu->title());
+ menu->setY(height());
+ menu->setParentItem(this);
+ menu->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent);
+ connect(menu, &QQuickMenu::titleChanged, this, &QQuickAbstractButton::setText);
+ }
+
+ d->menu = menu;
+ emit menuChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuBarItem::highlighted
+
+ This property holds whether the menu bar item is highlighted by the user.
+
+ A menu bar item can be highlighted by mouse hover or keyboard navigation.
+
+ The default value is \c false.
+*/
+bool QQuickMenuBarItem::isHighlighted() const
+{
+ Q_D(const QQuickMenuBarItem);
+ return d->highlighted;
+}
+
+void QQuickMenuBarItem::setHighlighted(bool highlighted)
+{
+ Q_D(QQuickMenuBarItem);
+ if (highlighted == d->highlighted)
+ return;
+
+ d->highlighted = highlighted;
+ emit highlightedChanged();
+}
+
+void QQuickMenuBarItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickMenuBarItem);
+ QQuickAbstractButton::geometryChange(newGeometry, oldGeometry);
+ if (d->menu)
+ d->menu->setY(newGeometry.height());
+}
+
+QFont QQuickMenuBarItem::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::MenuBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickMenuBarItem::accessibleRole() const
+{
+ return QAccessible::MenuBar;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmenubaritem_p.cpp"
diff --git a/src/quicktemplates2/qquickmenubaritem_p.h b/src/quicktemplates2/qquickmenubaritem_p.h
new file mode 100644
index 0000000000..a913f242bb
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubaritem_p.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUBARITEM_P_H
+#define QQUICKMENUBARITEM_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenu;
+class QQuickMenuBar;
+class QQuickMenuBarItemPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuBarItem : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickMenuBar *menuBar READ menuBar NOTIFY menuBarChanged FINAL)
+ Q_PROPERTY(QQuickMenu *menu READ menu WRITE setMenu NOTIFY menuChanged FINAL)
+ Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL)
+ QML_NAMED_ELEMENT(MenuBarItem)
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickMenuBarItem(QQuickItem *parent = nullptr);
+
+ QQuickMenuBar *menuBar() const;
+
+ QQuickMenu *menu() const;
+ void setMenu(QQuickMenu *menu);
+
+ bool isHighlighted() const;
+ void setHighlighted(bool highlighted);
+
+Q_SIGNALS:
+ void triggered();
+ void menuBarChanged();
+ void menuChanged();
+ void highlightedChanged();
+
+protected:
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenuBarItem)
+ Q_DECLARE_PRIVATE(QQuickMenuBarItem)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenuBarItem)
+
+#endif // QQUICKMENUBARITEM_P_H
diff --git a/src/quicktemplates2/qquickmenubaritem_p_p.h b/src/quicktemplates2/qquickmenubaritem_p_p.h
new file mode 100644
index 0000000000..22c509dcfb
--- /dev/null
+++ b/src/quicktemplates2/qquickmenubaritem_p_p.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUBARITEM_P_P_H
+#define QQUICKMENUBARITEM_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 <QtQuickTemplates2/private/qquickmenubaritem_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenu;
+class QQuickMenuBar;
+
+class QQuickMenuBarItemPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickMenuBarItem)
+
+public:
+ static QQuickMenuBarItemPrivate *get(QQuickMenuBarItem *item)
+ {
+ return item->d_func();
+ }
+
+ void setMenuBar(QQuickMenuBar *menuBar);
+
+ QPalette defaultPalette() const override;
+
+ bool highlighted = false;
+ QQuickMenu *menu = nullptr;
+ QQuickMenuBar *menuBar = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMENUBARITEM_P_P_H
diff --git a/src/quicktemplates2/qquickmenuitem.cpp b/src/quicktemplates2/qquickmenuitem.cpp
new file mode 100644
index 0000000000..559024416b
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuitem.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenuitem_p.h"
+#include "qquickmenuitem_p_p.h"
+#include "qquickmenu_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuItem
+ \inherits AbstractButton
+//! \instantiates QQuickMenuItem
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-menus
+ \brief Presents an item within a Menu.
+
+ MenuItem is a convenience type that implements the AbstractButton API,
+ providing a familiar way to respond to menu items being \l triggered, for
+ example.
+
+ MenuItem inherits its API from AbstractButton. For instance, you can set
+ \l {AbstractButton::text}{text} and \l {Icons in Qt Quick Controls}{icon}
+ using the AbstractButton API.
+
+ \code
+ Button {
+ id: fileButton
+ text: "File"
+ onClicked: menu.open()
+
+ Menu {
+ id: menu
+
+ MenuItem {
+ text: "New..."
+ onTriggered: document.reset()
+ }
+ MenuItem {
+ text: "Open..."
+ onTriggered: openDialog.open()
+ }
+ MenuItem {
+ text: "Save"
+ onTriggered: saveDialog.open()
+ }
+ }
+ }
+ \endcode
+
+ \sa {Customizing Menu}, Menu, {Menu Controls}
+*/
+
+void QQuickMenuItemPrivate::setMenu(QQuickMenu *newMenu)
+{
+ Q_Q(QQuickMenuItem);
+ if (menu == newMenu)
+ return;
+
+ menu = newMenu;
+ emit q->menuChanged();
+}
+
+void QQuickMenuItemPrivate::setSubMenu(QQuickMenu *newSubMenu)
+{
+ Q_Q(QQuickMenuItem);
+ if (subMenu == newSubMenu)
+ return;
+
+ if (subMenu) {
+ QObject::disconnect(subMenu, &QQuickMenu::titleChanged, q, &QQuickAbstractButton::setText);
+ QObjectPrivate::disconnect(subMenu, &QQuickPopup::enabledChanged, this, &QQuickMenuItemPrivate::updateEnabled);
+ }
+
+ if (newSubMenu) {
+ QObject::connect(newSubMenu, &QQuickMenu::titleChanged, q, &QQuickAbstractButton::setText);
+ QObjectPrivate::connect(newSubMenu, &QQuickPopup::enabledChanged, this, &QQuickMenuItemPrivate::updateEnabled);
+ q->setText(newSubMenu->title());
+ }
+
+ subMenu = newSubMenu;
+ updateEnabled();
+ emit q->subMenuChanged();
+}
+
+void QQuickMenuItemPrivate::updateEnabled()
+{
+ Q_Q(QQuickMenuItem);
+ q->setEnabled(subMenu && subMenu->isEnabled());
+}
+
+static inline QString arrowName() { return QStringLiteral("arrow"); }
+
+void QQuickMenuItemPrivate::cancelArrow()
+{
+ Q_Q(QQuickAbstractButton);
+ quickCancelDeferred(q, arrowName());
+}
+
+void QQuickMenuItemPrivate::executeArrow(bool complete)
+{
+ Q_Q(QQuickMenuItem);
+ if (arrow.wasExecuted())
+ return;
+
+ if (!arrow || complete)
+ quickBeginDeferred(q, arrowName(), arrow);
+ if (complete)
+ quickCompleteDeferred(q, arrowName(), arrow);
+}
+
+bool QQuickMenuItemPrivate::acceptKeyClick(Qt::Key key) const
+{
+ return key == Qt::Key_Space || key == Qt::Key_Return || key == Qt::Key_Enter;
+}
+
+QPalette QQuickMenuItemPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::Menu);
+}
+
+/*!
+ \qmlsignal void QtQuick.Controls::MenuItem::triggered()
+
+ This signal is emitted when the menu item is triggered by the user.
+*/
+
+QQuickMenuItem::QQuickMenuItem(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickMenuItemPrivate), parent)
+{
+ connect(this, &QQuickAbstractButton::clicked, this, &QQuickMenuItem::triggered);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::MenuItem::highlighted
+
+ This property holds whether the menu item is highlighted by the user.
+
+ A menu item can be highlighted by mouse hover or keyboard navigation.
+
+ The default value is \c false.
+
+ \sa Menu::currentIndex
+*/
+bool QQuickMenuItem::isHighlighted() const
+{
+ Q_D(const QQuickMenuItem);
+ return d->highlighted;
+}
+
+void QQuickMenuItem::setHighlighted(bool highlighted)
+{
+ Q_D(QQuickMenuItem);
+ if (highlighted == d->highlighted)
+ return;
+
+ d->highlighted = highlighted;
+ emit highlightedChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Item QtQuick.Controls::MenuItem::arrow
+
+ This property holds the sub-menu arrow item.
+
+ \sa {Customizing Menu}
+*/
+QQuickItem *QQuickMenuItem::arrow() const
+{
+ QQuickMenuItemPrivate *d = const_cast<QQuickMenuItemPrivate *>(d_func());
+ if (!d->arrow)
+ d->executeArrow();
+ return d->arrow;
+}
+
+void QQuickMenuItem::setArrow(QQuickItem *arrow)
+{
+ Q_D(QQuickMenuItem);
+ if (d->arrow == arrow)
+ return;
+
+ if (!d->arrow.isExecuting())
+ d->cancelArrow();
+
+ QQuickControlPrivate::hideOldItem(d->arrow);
+ d->arrow = arrow;
+ if (arrow && !arrow->parentItem())
+ arrow->setParentItem(this);
+ if (!d->arrow.isExecuting())
+ emit arrowChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Menu QtQuick.Controls::MenuItem::menu
+ \readonly
+
+ This property holds the menu that contains this menu item,
+ or \c null if the item is not in a menu.
+*/
+QQuickMenu *QQuickMenuItem::menu() const
+{
+ Q_D(const QQuickMenuItem);
+ return d->menu;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty Menu QtQuick.Controls::MenuItem::subMenu
+ \readonly
+
+ This property holds the sub-menu that this item presents in
+ the parent menu, or \c null if this item is not a sub-menu item.
+*/
+QQuickMenu *QQuickMenuItem::subMenu() const
+{
+ Q_D(const QQuickMenuItem);
+ return d->subMenu;
+}
+
+void QQuickMenuItem::componentComplete()
+{
+ Q_D(QQuickMenuItem);
+ d->executeArrow(true);
+ QQuickAbstractButton::componentComplete();
+}
+
+QFont QQuickMenuItem::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Menu);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickMenuItem::accessibleRole() const
+{
+ return QAccessible::MenuItem;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmenuitem_p.cpp"
diff --git a/src/quicktemplates2/qquickmenuitem_p.h b/src/quicktemplates2/qquickmenuitem_p.h
new file mode 100644
index 0000000000..817da76bba
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuitem_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUITEM_P_H
+#define QQUICKMENUITEM_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenu;
+class QQuickMenuItemPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuItem : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(bool highlighted READ isHighlighted WRITE setHighlighted NOTIFY highlightedChanged FINAL)
+ // 2.3 (Qt 5.10)
+ 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_CLASSINFO("DeferredPropertyNames", "arrow,background,contentItem,indicator")
+ QML_NAMED_ELEMENT(MenuItem)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickMenuItem(QQuickItem *parent = nullptr);
+
+ bool isHighlighted() const;
+ void setHighlighted(bool highlighted);
+
+ // 2.3 (Qt 5.10)
+ QQuickItem *arrow() const;
+ void setArrow(QQuickItem *arrow);
+
+ QQuickMenu *menu() const;
+ QQuickMenu *subMenu() const;
+
+Q_SIGNALS:
+ void triggered();
+ void highlightedChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void arrowChanged();
+ Q_REVISION(2, 3) void menuChanged();
+ Q_REVISION(2, 3) void subMenuChanged();
+
+protected:
+ void componentComplete() override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenuItem)
+ Q_DECLARE_PRIVATE(QQuickMenuItem)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenuItem)
+
+#endif // QQUICKMENUITEM_P_H
diff --git a/src/quicktemplates2/qquickmenuitem_p_p.h b/src/quicktemplates2/qquickmenuitem_p_p.h
new file mode 100644
index 0000000000..966e14e7e9
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuitem_p_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUITEM_P_P_H
+#define QQUICKMENUITEM_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 <QtQuickTemplates2/private/qquickmenuitem_p.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenu;
+
+class QQuickMenuItemPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickMenuItem)
+
+public:
+ static QQuickMenuItemPrivate *get(QQuickMenuItem *item)
+ {
+ return item->d_func();
+ }
+
+ void setMenu(QQuickMenu *menu);
+ void setSubMenu(QQuickMenu *subMenu);
+
+ void updateEnabled();
+
+ void cancelArrow();
+ void executeArrow(bool complete = false);
+
+ bool acceptKeyClick(Qt::Key key) const override;
+
+ QPalette defaultPalette() const override;
+
+ bool highlighted = false;
+ QQuickDeferredPointer<QQuickItem> arrow;
+ QQuickMenu *menu = nullptr;
+ QQuickMenu *subMenu = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKMENUITEM_P_P_H
diff --git a/src/quicktemplates2/qquickmenuseparator.cpp b/src/quicktemplates2/qquickmenuseparator.cpp
new file mode 100644
index 0000000000..d646ed437d
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuseparator.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenuseparator_p.h"
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuSeparator
+ \inherits Control
+//! \instantiates QQuickMenuSeparator
+ \inqmlmodule QtQuick.Controls
+ \since 5.8
+ \ingroup qtquickcontrols2-separators
+ \brief Separates a group of items in a menu from adjacent items.
+
+ MenuSeparator is used to visually distinguish between groups of items in a
+ menu by separating them with a line.
+
+ \image qtquickcontrols2-menuseparator.png
+
+ \quotefromfile qtquickcontrols2-menuseparator-custom.qml
+ \skipto import QtQuick
+ \printuntil import QtQuick.Controls
+ \skipto Menu
+ \printto contentItem.parent: window
+ \skipline contentItem.parent: window
+ \printuntil text: qsTr("Exit")
+ \printuntil }
+ \printuntil }
+
+ \sa {Customizing Menu}, Menu, {Separator Controls}
+*/
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuSeparatorPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickMenuSeparator)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::Menu); }
+};
+
+QQuickMenuSeparator::QQuickMenuSeparator(QQuickItem *parent)
+ : QQuickControl(*(new QQuickMenuSeparatorPrivate), parent)
+{
+}
+
+QFont QQuickMenuSeparator::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Menu);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickMenuSeparator::accessibleRole() const
+{
+ return QAccessible::Separator;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickmenuseparator_p.cpp"
diff --git a/src/quicktemplates2/qquickmenuseparator_p.h b/src/quicktemplates2/qquickmenuseparator_p.h
new file mode 100644
index 0000000000..330aaac40b
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuseparator_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUSEPARATOR_P_H
+#define QQUICKMENUSEPARATOR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickMenuSeparator;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuSeparator : public QQuickControl
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(MenuSeparator)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickMenuSeparator(QQuickItem *parent = nullptr);
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenuSeparator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenuSeparator)
+
+#endif // QQUICKMENUSEPARATOR_P_H
diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp
new file mode 100644
index 0000000000..1829f9a30e
--- /dev/null
+++ b/src/quicktemplates2/qquickoverlay.cpp
@@ -0,0 +1,763 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickcontrol_p_p.h"
+#include "qquickoverlay_p.h"
+#include "qquickoverlay_p_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickdrawer_p.h"
+#include "qquickdrawer_p_p.h"
+#include "qquickapplicationwindow_p.h"
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlproperty.h>
+#include <QtQml/qqmlcomponent.h>
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Overlay
+ \inherits Item
+//! \instantiates QQuickOverlay
+ \inqmlmodule QtQuick.Controls
+ \since 5.10
+ \brief A window overlay for popups.
+
+ Overlay provides a layer for popups, ensuring that popups are displayed above
+ other content and that the background is dimmed when a \l {Popup::}{modal} or
+ \l {Popup::dim}{dimmed} popup is visible.
+
+ The overlay is an ordinary Item that covers the entire window. It can be used
+ as a visual parent to position a popup in scene coordinates.
+
+ \include qquickoverlay-popup-parent.qdocinc
+
+ \sa ApplicationWindow
+*/
+
+QList<QQuickPopup *> QQuickOverlayPrivate::stackingOrderPopups() const
+{
+ const QList<QQuickItem *> children = paintOrderChildItems();
+
+ QList<QQuickPopup *> popups;
+ popups.reserve(children.count());
+
+ for (auto it = children.crbegin(), end = children.crend(); it != end; ++it) {
+ QQuickPopup *popup = qobject_cast<QQuickPopup *>((*it)->parent());
+ if (popup)
+ popups += popup;
+ }
+
+ return popups;
+}
+
+QList<QQuickDrawer *> QQuickOverlayPrivate::stackingOrderDrawers() const
+{
+ QList<QQuickDrawer *> sorted(allDrawers);
+ std::sort(sorted.begin(), sorted.end(), [](const QQuickDrawer *one, const QQuickDrawer *another) {
+ return one->z() > another->z();
+ });
+ return sorted;
+}
+
+void QQuickOverlayPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
+{
+ updateGeometry();
+}
+
+bool QQuickOverlayPrivate::startDrag(QEvent *event, const QPointF &pos)
+{
+ Q_Q(QQuickOverlay);
+ if (allDrawers.isEmpty())
+ return false;
+
+ // don't start dragging a drawer if a modal popup overlay is blocking (QTBUG-60602)
+ QQuickItem *item = q->childAt(pos.x(), pos.y());
+ if (item) {
+ const auto popups = stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
+ if (p->dimmer == item && popup->isVisible() && popup->isModal())
+ return false;
+ }
+ }
+
+ const QList<QQuickDrawer *> drawers = stackingOrderDrawers();
+ for (QQuickDrawer *drawer : drawers) {
+ QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer);
+ if (p->startDrag(event)) {
+ setMouseGrabberPopup(drawer);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
+{
+ if (target) {
+ if (target->overlayEvent(source, event)) {
+ setMouseGrabberPopup(target);
+ return true;
+ }
+ return false;
+ }
+
+ switch (event->type()) {
+ default: {
+ if (mouseGrabberPopup)
+ break;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ Q_FALLTHROUGH();
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+#endif
+ // allow non-modal popups to close themselves,
+ // and non-dimming modal popups to block the event
+ const auto popups = stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ if (popup->overlayEvent(source, event)) {
+ setMouseGrabberPopup(popup);
+ return true;
+ }
+ }
+ break;
+ }
+ }
+
+ event->ignore();
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target)
+{
+ if (target)
+ return target->overlayEvent(source, event);
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
+{
+ if (target) {
+ setMouseGrabberPopup(nullptr);
+ if (target->overlayEvent(source, event)) {
+ setMouseGrabberPopup(nullptr);
+ return true;
+ }
+ } else {
+ const auto popups = stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ if (popup->overlayEvent(source, event))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ if (!target && startDrag(event, event->scenePosition()))
+ return true;
+ return handlePress(source, event, target);
+ case QEvent::MouseMove:
+ return handleMove(source, event, target ? target : mouseGrabberPopup.data());
+ case QEvent::MouseButtonRelease:
+ return handleRelease(source, event, target ? target : mouseGrabberPopup.data());
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleHoverEvent(QQuickItem *source, QHoverEvent *event, QQuickPopup *target)
+{
+ switch (event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ case QEvent::HoverLeave:
+ if (target)
+ return target->overlayEvent(source, event);
+ return false;
+ default:
+ Q_UNREACHABLE(); // function must only be called on hover events
+ break;
+ }
+ return false;
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickOverlayPrivate::handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target)
+{
+ bool handled = false;
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ switch (point.state()) {
+ case QEventPoint::Pressed:
+ if (!target && startDrag(event, point.scenePosition()))
+ handled = true;
+ else
+ handled |= handlePress(source, event, target);
+ break;
+ case QEventPoint::Updated:
+ handled |= handleMove(source, event, target ? target : mouseGrabberPopup.data());
+ break;
+ case QEventPoint::Released:
+ handled |= handleRelease(source, event, target ? target : mouseGrabberPopup.data());
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return handled;
+}
+#endif
+
+void QQuickOverlayPrivate::addPopup(QQuickPopup *popup)
+{
+ Q_Q(QQuickOverlay);
+ allPopups += popup;
+ if (QQuickDrawer *drawer = qobject_cast<QQuickDrawer *>(popup)) {
+ allDrawers += drawer;
+ q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty());
+ }
+}
+
+void QQuickOverlayPrivate::removePopup(QQuickPopup *popup)
+{
+ Q_Q(QQuickOverlay);
+ allPopups.removeOne(popup);
+ if (allDrawers.removeOne(qobject_cast<QQuickDrawer *>(popup)))
+ q->setVisible(!allDrawers.isEmpty() || !q->childItems().isEmpty());
+}
+
+void QQuickOverlayPrivate::setMouseGrabberPopup(QQuickPopup *popup)
+{
+ if (popup && !popup->isVisible())
+ popup = nullptr;
+ mouseGrabberPopup = popup;
+}
+
+void QQuickOverlayPrivate::updateGeometry()
+{
+ Q_Q(QQuickOverlay);
+ if (!window)
+ return;
+
+ QPointF pos;
+ QSizeF size = window->size();
+ qreal rotation = 0;
+
+ switch (window->contentOrientation()) {
+ case Qt::PrimaryOrientation:
+ case Qt::PortraitOrientation:
+ size = window->size();
+ break;
+ case Qt::LandscapeOrientation:
+ rotation = 90;
+ pos = QPointF((size.width() - size.height()) / 2, -(size.width() - size.height()) / 2);
+ size.transpose();
+ break;
+ case Qt::InvertedPortraitOrientation:
+ rotation = 180;
+ break;
+ case Qt::InvertedLandscapeOrientation:
+ rotation = 270;
+ pos = QPointF((size.width() - size.height()) / 2, -(size.width() - size.height()) / 2);
+ size.transpose();
+ break;
+ default:
+ break;
+ }
+
+ q->setSize(size);
+ q->setPosition(pos);
+ q->setRotation(rotation);
+}
+
+QQuickOverlay::QQuickOverlay(QQuickItem *parent)
+ : QQuickItem(*(new QQuickOverlayPrivate), parent)
+{
+ Q_D(QQuickOverlay);
+ setZ(1000001); // DefaultWindowDecoration+1
+ setAcceptedMouseButtons(Qt::AllButtons);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+ setFiltersChildMouseEvents(true);
+ setVisible(false);
+
+ if (parent) {
+ d->updateGeometry();
+ QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Geometry);
+ if (QQuickWindow *window = parent->window()) {
+ window->installEventFilter(this);
+ QObjectPrivate::connect(window, &QWindow::contentOrientationChanged, d, &QQuickOverlayPrivate::updateGeometry);
+ }
+ }
+}
+
+QQuickOverlay::~QQuickOverlay()
+{
+ Q_D(QQuickOverlay);
+ if (QQuickItem *parent = parentItem())
+ QQuickItemPrivate::get(parent)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+}
+
+QQmlComponent *QQuickOverlay::modal() const
+{
+ Q_D(const QQuickOverlay);
+ return d->modal;
+}
+
+void QQuickOverlay::setModal(QQmlComponent *modal)
+{
+ Q_D(QQuickOverlay);
+ if (d->modal == modal)
+ return;
+
+ d->modal = modal;
+ emit modalChanged();
+}
+
+QQmlComponent *QQuickOverlay::modeless() const
+{
+ Q_D(const QQuickOverlay);
+ return d->modeless;
+}
+
+void QQuickOverlay::setModeless(QQmlComponent *modeless)
+{
+ Q_D(QQuickOverlay);
+ if (d->modeless == modeless)
+ return;
+
+ d->modeless = modeless;
+ emit modelessChanged();
+}
+
+QQuickOverlay *QQuickOverlay::overlay(QQuickWindow *window)
+{
+ if (!window)
+ return nullptr;
+
+ const char *name = "_q_QQuickOverlay";
+ QQuickOverlay *overlay = window->property(name).value<QQuickOverlay *>();
+ if (!overlay) {
+ QQuickItem *content = window->contentItem();
+ // Do not re-create the overlay if the window is being destroyed
+ // and thus, its content item no longer has a window associated.
+ if (content && content->window()) {
+ overlay = new QQuickOverlay(window->contentItem());
+ window->setProperty(name, QVariant::fromValue(overlay));
+ }
+ }
+ return overlay;
+}
+
+QQuickOverlayAttached *QQuickOverlay::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickOverlayAttached(object);
+}
+
+void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ Q_D(QQuickOverlay);
+ QQuickItem::itemChange(change, data);
+
+ if (change == ItemChildAddedChange || change == ItemChildRemovedChange) {
+ setVisible(!d->allDrawers.isEmpty() || !childItems().isEmpty());
+ if (data.item->parent() == d->mouseGrabberPopup)
+ d->setMouseGrabberPopup(nullptr);
+ }
+}
+
+void QQuickOverlay::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickOverlay);
+ QQuickItem::geometryChange(newGeometry, oldGeometry);
+ for (QQuickPopup *popup : qAsConst(d->allPopups))
+ QQuickPopupPrivate::get(popup)->resizeOverlay();
+}
+
+void QQuickOverlay::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickOverlay);
+ d->handleMouseEvent(this, event);
+}
+
+void QQuickOverlay::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickOverlay);
+ d->handleMouseEvent(this, event);
+}
+
+void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickOverlay);
+ d->handleMouseEvent(this, event);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickOverlay::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickOverlay);
+ d->handleTouchEvent(this, event);
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickOverlay::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickOverlay);
+ if (d->mouseGrabberPopup) {
+ d->mouseGrabberPopup->overlayEvent(this, event);
+ return;
+ } else {
+ const auto popups = d->stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ if (popup->overlayEvent(this, event))
+ return;
+ }
+ }
+ event->ignore();
+}
+#endif
+
+bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_D(QQuickOverlay);
+ const auto popups = d->stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ QQuickPopupPrivate *p = QQuickPopupPrivate::get(popup);
+
+ // Stop filtering overlay events when reaching a popup item or an item
+ // that is inside the popup. Let the popup content handle its events.
+ if (item == p->popupItem || p->popupItem->isAncestorOf(item))
+ break;
+
+ // Let the popup try closing itself when pressing or releasing over its
+ // background dimming OR over another popup underneath, in case the popup
+ // does not have background dimming.
+ if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
+ bool handled = false;
+ switch (event->type()) {
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ handled = d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup);
+ break;
+#endif
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ case QEvent::HoverLeave:
+ handled = d->handleHoverEvent(item, static_cast<QHoverEvent *>(event), popup);
+ break;
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ handled = d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup);
+ break;
+
+ default:
+ break;
+ }
+ if (handled)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QQuickOverlay::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QQuickOverlay);
+ if (!isVisible() || object != d->window)
+ return false;
+
+ switch (event->type()) {
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Pressed)
+ emit pressed();
+ if (static_cast<QTouchEvent *>(event)->touchPointStates() & QEventPoint::Released)
+ emit released();
+
+ // allow non-modal popups to close on touch release outside
+ if (!d->mouseGrabberPopup) {
+ for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->points()) {
+ if (point.state() == QEventPoint::Released) {
+ if (d->handleRelease(d->window->contentItem(), event, nullptr))
+ break;
+ }
+ }
+ }
+
+ QQuickWindowPrivate::get(d->window)->handleTouchEvent(static_cast<QTouchEvent *>(event));
+
+ // If a touch event hasn't been accepted after being delivered, there
+ // were no items interested in touch events at any of the touch points.
+ // Make sure to accept the touch event in order to receive the consequent
+ // touch events, to be able to close non-modal popups on release outside.
+ event->accept();
+ return true;
+#endif
+
+ case QEvent::MouseButtonPress:
+#if QT_CONFIG(quicktemplates2_multitouch)
+ // do not emit pressed() twice when mouse events have been synthesized from touch events
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
+#endif
+ emit pressed();
+
+ QQuickWindowPrivate::get(d->window)->handleMouseEvent(static_cast<QMouseEvent *>(event));
+
+ // If a mouse event hasn't been accepted after being delivered, there
+ // was no item interested in mouse events at the mouse point. Make sure
+ // to accept the mouse event in order to receive the consequent mouse
+ // events, to be able to close non-modal popups on release outside.
+ event->accept();
+ return true;
+
+ case QEvent::MouseButtonRelease:
+#if QT_CONFIG(quicktemplates2_multitouch)
+ // do not emit released() twice when mouse events have been synthesized from touch events
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
+#endif
+ emit released();
+
+ // allow non-modal popups to close on mouse release outside
+ if (!d->mouseGrabberPopup)
+ d->handleRelease(d->window->contentItem(), event, nullptr);
+ break;
+
+ case QEvent::Wheel: {
+ // If the top item in the drawing-order is blocked by a modal popup, then
+ // eat the event. There is no scenario where the top most item is blocked
+ // by a popup, but an item further down in the drawing order is not.
+ QWheelEvent *we = static_cast<QWheelEvent *>(event);
+ const QVector<QQuickItem *> targetItems = d->deliveryAgentPrivate()->pointerTargets(
+ d->window->contentItem(), we, we->point(0), false, false);
+ if (targetItems.isEmpty())
+ break;
+
+ QQuickItem * const topItem = targetItems.first();
+ const auto popups = d->stackingOrderPopups();
+ for (const auto &popup : popups) {
+ if (!popup->overlayEvent(topItem, we))
+ continue;
+ const QQuickItem *popupItem = popup->popupItem();
+ if (!popupItem)
+ continue;
+ if (!popupItem->isAncestorOf(topItem))
+ return true;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+class QQuickOverlayAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickOverlayAttached)
+
+public:
+ void setWindow(QQuickWindow *newWindow);
+
+ QQuickWindow *window = nullptr;
+ QQmlComponent *modal = nullptr;
+ QQmlComponent *modeless = nullptr;
+};
+
+void QQuickOverlayAttachedPrivate::setWindow(QQuickWindow *newWindow)
+{
+ Q_Q(QQuickOverlayAttached);
+ if (window == newWindow)
+ return;
+
+ if (QQuickOverlay *oldOverlay = QQuickOverlay::overlay(window)) {
+ QObject::disconnect(oldOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
+ QObject::disconnect(oldOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
+ }
+
+ if (QQuickOverlay *newOverlay = QQuickOverlay::overlay(newWindow)) {
+ QObject::connect(newOverlay, &QQuickOverlay::pressed, q, &QQuickOverlayAttached::pressed);
+ QObject::connect(newOverlay, &QQuickOverlay::released, q, &QQuickOverlayAttached::released);
+ }
+
+ window = newWindow;
+ emit q->overlayChanged();
+}
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::Overlay::pressed()
+
+ This attached signal is emitted when the overlay is pressed by the user while
+ a popup is visible.
+
+ The signal can be attached to any item, popup, or window. When attached to an
+ item or a popup, the signal is only emitted if the item or popup is in a window.
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::Overlay::released()
+
+ This attached signal is emitted when the overlay is released by the user while
+ a popup is visible.
+
+ The signal can be attached to any item, popup, or window. When attached to an
+ item or a popup, the signal is only emitted if the item or popup is in a window.
+*/
+
+QQuickOverlayAttached::QQuickOverlayAttached(QObject *parent)
+ : QObject(*(new QQuickOverlayAttachedPrivate), parent)
+{
+ Q_D(QQuickOverlayAttached);
+ if (QQuickItem *item = qobject_cast<QQuickItem *>(parent)) {
+ d->setWindow(item->window());
+ QObjectPrivate::connect(item, &QQuickItem::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
+ } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(parent)) {
+ d->setWindow(popup->window());
+ QObjectPrivate::connect(popup, &QQuickPopup::windowChanged, d, &QQuickOverlayAttachedPrivate::setWindow);
+ } else {
+ d->setWindow(qobject_cast<QQuickWindow *>(parent));
+ }
+}
+
+/*!
+ \qmlattachedproperty Overlay QtQuick.Controls::Overlay::overlay
+ \readonly
+
+ This attached property holds the window overlay item.
+
+ The property can be attached to any item, popup, or window. When attached to an
+ item or a popup, the value is \c null if the item or popup is not in a window.
+*/
+QQuickOverlay *QQuickOverlayAttached::overlay() const
+{
+ Q_D(const QQuickOverlayAttached);
+ return QQuickOverlay::overlay(d->window);
+}
+
+/*!
+ \qmlattachedproperty Component QtQuick.Controls::Overlay::modal
+
+ This attached property holds a component to use as a visual item that implements
+ background dimming for modal popups. It is created for and stacked below visible
+ modal popups.
+
+ The property can be attached to any popup.
+
+ For example, to change the color of the background dimming for a modal
+ popup, the following code can be used:
+
+ \snippet qtquickcontrols2-overlay-modal.qml 1
+
+ \sa Popup::modal
+*/
+QQmlComponent *QQuickOverlayAttached::modal() const
+{
+ Q_D(const QQuickOverlayAttached);
+ return d->modal;
+}
+
+void QQuickOverlayAttached::setModal(QQmlComponent *modal)
+{
+ Q_D(QQuickOverlayAttached);
+ if (d->modal == modal)
+ return;
+
+ d->modal = modal;
+ emit modalChanged();
+}
+
+/*!
+ \qmlattachedproperty Component QtQuick.Controls::Overlay::modeless
+
+ This attached property holds a component to use as a visual item that implements
+ background dimming for modeless popups. It is created for and stacked below visible
+ dimming popups.
+
+ The property can be attached to any popup.
+
+ For example, to change the color of the background dimming for a modeless
+ popup, the following code can be used:
+
+ \snippet qtquickcontrols2-overlay-modeless.qml 1
+
+ \sa Popup::dim
+*/
+QQmlComponent *QQuickOverlayAttached::modeless() const
+{
+ Q_D(const QQuickOverlayAttached);
+ return d->modeless;
+}
+
+void QQuickOverlayAttached::setModeless(QQmlComponent *modeless)
+{
+ Q_D(QQuickOverlayAttached);
+ if (d->modeless == modeless)
+ return;
+
+ d->modeless = modeless;
+ emit modelessChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickoverlay_p.cpp"
diff --git a/src/quicktemplates2/qquickoverlay_p.h b/src/quicktemplates2/qquickoverlay_p.h
new file mode 100644
index 0000000000..c6e530e280
--- /dev/null
+++ b/src/quicktemplates2/qquickoverlay_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKOVERLAY_P_H
+#define QQUICKOVERLAY_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/qquickitem.h>
+#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickOverlayPrivate;
+class QQuickOverlayAttached;
+class QQuickOverlayAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickOverlay : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QQmlComponent *modal READ modal WRITE setModal NOTIFY modalChanged FINAL)
+ Q_PROPERTY(QQmlComponent *modeless READ modeless WRITE setModeless NOTIFY modelessChanged FINAL)
+ QML_NAMED_ELEMENT(Overlay)
+ QML_ATTACHED(QQuickOverlayAttached)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 3)
+
+public:
+ explicit QQuickOverlay(QQuickItem *parent = nullptr);
+ ~QQuickOverlay();
+
+ QQmlComponent *modal() const;
+ void setModal(QQmlComponent *modal);
+
+ QQmlComponent *modeless() const;
+ void setModeless(QQmlComponent *modeless);
+
+ static QQuickOverlay *overlay(QQuickWindow *window);
+
+ static QQuickOverlayAttached *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void modalChanged();
+ void modelessChanged();
+ void pressed();
+ void released();
+
+protected:
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
+ bool eventFilter(QObject *object, QEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickOverlay)
+ Q_DECLARE_PRIVATE(QQuickOverlay)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickOverlayAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickOverlay *overlay READ overlay NOTIFY overlayChanged FINAL)
+ Q_PROPERTY(QQmlComponent *modal READ modal WRITE setModal NOTIFY modalChanged FINAL)
+ Q_PROPERTY(QQmlComponent *modeless READ modeless WRITE setModeless NOTIFY modelessChanged FINAL)
+
+public:
+ explicit QQuickOverlayAttached(QObject *parent = nullptr);
+
+ QQuickOverlay *overlay() const;
+
+ QQmlComponent *modal() const;
+ void setModal(QQmlComponent *modal);
+
+ QQmlComponent *modeless() const;
+ void setModeless(QQmlComponent *modeless);
+
+Q_SIGNALS:
+ void overlayChanged();
+ void modalChanged();
+ void modelessChanged();
+ void pressed();
+ void released();
+
+private:
+ Q_DISABLE_COPY(QQuickOverlayAttached)
+ Q_DECLARE_PRIVATE(QQuickOverlayAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickOverlay)
+QML_DECLARE_TYPEINFO(QQuickOverlay, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKOVERLAY_P_H
diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h
new file mode 100644
index 0000000000..fbb2f86c73
--- /dev/null
+++ b/src/quicktemplates2/qquickoverlay_p_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKOVERLAY_P_P_H
+#define QQUICKOVERLAY_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 <QtQuickTemplates2/private/qquickoverlay_p.h>
+
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPopup;
+class QQuickDrawer;
+
+class QQuickOverlayPrivate : public QQuickItemPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickOverlay)
+
+public:
+ static QQuickOverlayPrivate *get(QQuickOverlay *overlay)
+ {
+ return overlay->d_func();
+ }
+
+ bool startDrag(QEvent *event, const QPointF &pos);
+ bool handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target);
+ bool handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target);
+ bool handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target);
+
+ bool handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target = nullptr);
+ bool handleHoverEvent(QQuickItem *source, QHoverEvent *event, QQuickPopup *target = nullptr);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ bool handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target = nullptr);
+#endif
+
+ void addPopup(QQuickPopup *popup);
+ void removePopup(QQuickPopup *popup);
+ void setMouseGrabberPopup(QQuickPopup *popup);
+
+ QList<QQuickPopup *> stackingOrderPopups() const;
+ QList<QQuickDrawer *> stackingOrderDrawers() const;
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+
+ void updateGeometry();
+
+ QQmlComponent *modal = nullptr;
+ QQmlComponent *modeless = nullptr;
+ QList<QQuickPopup *> allPopups;
+ QList<QQuickDrawer *> allDrawers;
+ QPointer<QQuickPopup> mouseGrabberPopup;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKOVERLAY_P_P_H
diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp
new file mode 100644
index 0000000000..a65e53fe82
--- /dev/null
+++ b/src/quicktemplates2/qquickpage.cpp
@@ -0,0 +1,498 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpage_p.h"
+#include "qquickpage_p_p.h"
+#include "qquicktabbar_p.h"
+#include "qquicktoolbar_p.h"
+#include "qquickdialogbuttonbox_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Page
+ \inherits Pane
+//! \instantiates QQuickPage
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Styled page control with support for a header and footer.
+
+ Page is a container control which makes it convenient to add
+ a \l header and \l footer item to a page.
+
+ \image qtquickcontrols2-page-wireframe.png
+
+ Items declared as children of a Page are:
+ \list
+ \li automatically parented to the Page's contentItem. Items created
+ dynamically need to be explicitly parented to the contentItem.
+ \li not automatically positioned or resized.
+ \endlist
+
+ The following example snippet illustrates how to use a page-specific
+ toolbar header and an application-wide tabbar footer.
+
+ \qml
+ import QtQuick.Controls
+ import QtQuick.Layouts
+
+ ApplicationWindow {
+ visible: true
+
+ StackView {
+ anchors.fill: parent
+
+ initialItem: Page {
+ header: ToolBar {
+ // ...
+ }
+
+ ColumnLayout {
+ anchors.fill: parent
+ // ...
+ }
+ }
+ }
+
+ footer: TabBar {
+ // ...
+ }
+ }
+ \endqml
+
+ \sa ApplicationWindow, {Container Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+static const QQuickItemPrivate::ChangeTypes LayoutChanges = QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed
+ | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+
+namespace {
+ enum Position {
+ Header,
+ Footer
+ };
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickTabBar::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickTabBar::Footer));
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickToolBar::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickToolBar::Footer));
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickDialogButtonBox::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickDialogButtonBox::Footer));
+
+ static void setPos(QQuickItem *item, Position position)
+ {
+ if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(item))
+ toolBar->setPosition(static_cast<QQuickToolBar::Position>(position));
+ else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(item))
+ tabBar->setPosition(static_cast<QQuickTabBar::Position>(position));
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(item))
+ buttonBox->setPosition(static_cast<QQuickDialogButtonBox::Position>(position));
+ }
+}
+
+void QQuickPagePrivate::relayout()
+{
+ Q_Q(QQuickPage);
+ const qreal hh = header && header->isVisible() ? header->height() : 0;
+ const qreal fh = footer && footer->isVisible() ? footer->height() : 0;
+ const qreal hsp = hh > 0 ? spacing : 0;
+ const qreal fsp = fh > 0 ? spacing : 0;
+
+ if (contentItem) {
+ contentItem->setY(q->topPadding() + hh + hsp);
+ contentItem->setX(q->leftPadding());
+ contentItem->setWidth(q->availableWidth());
+ contentItem->setHeight(q->availableHeight() - hh - fh - hsp - fsp);
+ }
+
+ if (header)
+ header->setWidth(q->width());
+
+ if (footer) {
+ footer->setY(q->height() - footer->height());
+ footer->setWidth(q->width());
+ }
+}
+
+void QQuickPagePrivate::resizeContent()
+{
+ relayout();
+}
+
+void QQuickPagePrivate::itemVisibilityChanged(QQuickItem *item)
+{
+ Q_Q(QQuickPage);
+ QQuickPanePrivate::itemVisibilityChanged(item);
+ if (item == header) {
+ QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals);
+ emit q->implicitHeaderWidthChanged();
+ emit q->implicitHeaderHeightChanged();
+ relayout();
+ } else if (item == footer) {
+ QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals);
+ emit q->implicitFooterWidthChanged();
+ emit q->implicitFooterHeightChanged();
+ relayout();
+ }
+}
+
+void QQuickPagePrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickPage);
+ QQuickPanePrivate::itemImplicitWidthChanged(item);
+
+ // Avoid binding loops by skipping signal emission if we're already doing it.
+ if (emittingImplicitSizeChangedSignals)
+ return;
+
+ if (item == header)
+ emit q->implicitHeaderWidthChanged();
+ else if (item == footer)
+ emit q->implicitFooterWidthChanged();
+}
+
+void QQuickPagePrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickPage);
+ QQuickPanePrivate::itemImplicitHeightChanged(item);
+
+ // Avoid binding loops by skipping signal emission if we're already doing it.
+ if (emittingImplicitSizeChangedSignals)
+ return;
+
+ if (item == header)
+ emit q->implicitHeaderHeightChanged();
+ else if (item == footer)
+ emit q->implicitFooterHeightChanged();
+}
+
+void QQuickPagePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF & diff)
+{
+ QQuickPanePrivate::itemGeometryChanged(item, change, diff);
+ if (item == header || item == footer)
+ relayout();
+}
+
+void QQuickPagePrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickPage);
+ QQuickPanePrivate::itemDestroyed(item);
+ if (item == header) {
+ header = nullptr;
+ relayout();
+ emit q->implicitHeaderWidthChanged();
+ emit q->implicitHeaderHeightChanged();
+ emit q->headerChanged();
+ } else if (item == footer) {
+ footer = nullptr;
+ relayout();
+ emit q->implicitFooterWidthChanged();
+ emit q->implicitFooterHeightChanged();
+ emit q->footerChanged();
+ }
+}
+
+QQuickPage::QQuickPage(QQuickItem *parent)
+ : QQuickPane(*(new QQuickPagePrivate), parent)
+{
+}
+
+QQuickPage::QQuickPage(QQuickPagePrivate &dd, QQuickItem *parent)
+ : QQuickPane(dd, parent)
+{
+}
+
+QQuickPage::~QQuickPage()
+{
+ Q_D(QQuickPage);
+ if (d->header)
+ QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, LayoutChanges);
+ if (d->footer)
+ QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, LayoutChanges);
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::Page::title
+
+ This property holds the page title.
+
+ The title is often displayed at the top of a page to give
+ the user context about the page they are viewing.
+
+ Page does not render the title itself, but instead relies
+ on the application to do so. For example:
+
+ \code
+ ApplicationWindow {
+ visible: true
+ width: 400
+ height: 400
+
+ header: Label {
+ text: view.currentItem.title
+ horizontalAlignment: Text.AlignHCenter
+ }
+
+ SwipeView {
+ id: view
+ anchors.fill: parent
+
+ Page {
+ title: qsTr("Home")
+ }
+ Page {
+ title: qsTr("Discover")
+ }
+ Page {
+ title: qsTr("Activity")
+ }
+ }
+ }
+ \endcode
+*/
+
+QString QQuickPage::title() const
+{
+ return d_func()->title;
+}
+
+void QQuickPage::setTitle(const QString &title)
+{
+ Q_D(QQuickPage);
+ if (d->title == title)
+ return;
+
+ d->title = title;
+ maybeSetAccessibleName(title);
+ emit titleChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Page::header
+
+ This property holds the page header item. The header item is positioned to
+ the top, and resized to the width of the page. The default value is \c null.
+
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page header
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Header.
+
+ \sa footer, ApplicationWindow::header
+*/
+QQuickItem *QQuickPage::header() const
+{
+ Q_D(const QQuickPage);
+ return d->header;
+}
+
+void QQuickPage::setHeader(QQuickItem *header)
+{
+ Q_D(QQuickPage);
+ if (d->header == header)
+ return;
+
+ if (d->header) {
+ QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, LayoutChanges);
+ d->header->setParentItem(nullptr);
+ }
+ d->header = header;
+ if (header) {
+ header->setParentItem(this);
+ QQuickItemPrivate::get(header)->addItemChangeListener(d, LayoutChanges);
+ if (qFuzzyIsNull(header->z()))
+ header->setZ(1);
+ setPos(header, Header);
+ }
+ if (isComponentComplete())
+ d->relayout();
+ emit headerChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Page::footer
+
+ This property holds the page footer item. The footer item is positioned to
+ the bottom, and resized to the width of the page. The default value is \c null.
+
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page footer
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Footer.
+
+ \sa header, ApplicationWindow::footer
+*/
+QQuickItem *QQuickPage::footer() const
+{
+ Q_D(const QQuickPage);
+ return d->footer;
+}
+
+void QQuickPage::setFooter(QQuickItem *footer)
+{
+ Q_D(QQuickPage);
+ if (d->footer == footer)
+ return;
+
+ if (d->footer) {
+ QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, LayoutChanges);
+ d->footer->setParentItem(nullptr);
+ }
+ d->footer = footer;
+ if (footer) {
+ footer->setParentItem(this);
+ QQuickItemPrivate::get(footer)->addItemChangeListener(d, LayoutChanges);
+ if (qFuzzyIsNull(footer->z()))
+ footer->setZ(1);
+ setPos(footer, Footer);
+ }
+ if (isComponentComplete())
+ d->relayout();
+ emit footerChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Page::implicitHeaderWidth
+ \readonly
+
+ This property holds the implicit header width.
+
+ The value is equal to \c {header && header.visible ? header.implicitWidth : 0}.
+
+ \sa implicitHeaderHeight, implicitFooterWidth
+*/
+qreal QQuickPage::implicitHeaderWidth() const
+{
+ Q_D(const QQuickPage);
+ if (!d->header || !d->header->isVisible())
+ return 0;
+ return d->header->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Page::implicitHeaderHeight
+ \readonly
+
+ This property holds the implicit header height.
+
+ The value is equal to \c {header && header.visible ? header.implicitHeight : 0}.
+
+ \sa implicitHeaderWidth, implicitFooterHeight
+*/
+qreal QQuickPage::implicitHeaderHeight() const
+{
+ Q_D(const QQuickPage);
+ if (!d->header || !d->header->isVisible())
+ return 0;
+ return d->header->implicitHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Page::implicitFooterWidth
+ \readonly
+
+ This property holds the implicit footer width.
+
+ The value is equal to \c {footer && footer.visible ? footer.implicitWidth : 0}.
+
+ \sa implicitFooterHeight, implicitHeaderWidth
+*/
+qreal QQuickPage::implicitFooterWidth() const
+{
+ Q_D(const QQuickPage);
+ if (!d->footer || !d->footer->isVisible())
+ return 0;
+ return d->footer->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Page::implicitFooterHeight
+ \readonly
+
+ This property holds the implicit footer height.
+
+ The value is equal to \c {footer && footer.visible ? footer.implicitHeight : 0}.
+
+ \sa implicitFooterWidth, implicitHeaderHeight
+*/
+qreal QQuickPage::implicitFooterHeight() const
+{
+ Q_D(const QQuickPage);
+ if (!d->footer || !d->footer->isVisible())
+ return 0;
+ return d->footer->implicitHeight();
+}
+
+void QQuickPage::componentComplete()
+{
+ Q_D(QQuickPage);
+ QQuickPane::componentComplete();
+ d->relayout();
+}
+
+void QQuickPage::spacingChange(qreal newSpacing, qreal oldSpacing)
+{
+ Q_D(QQuickPage);
+ QQuickPane::spacingChange(newSpacing, oldSpacing);
+ d->relayout();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickPage::accessibleRole() const
+{
+ return QAccessible::PageTab;
+}
+
+void QQuickPage::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickPage);
+ QQuickPane::accessibilityActiveChanged(active);
+
+ if (active)
+ maybeSetAccessibleName(d->title);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpage_p.cpp"
diff --git a/src/quicktemplates2/qquickpage_p.h b/src/quicktemplates2/qquickpage_p.h
new file mode 100644
index 0000000000..0a65f67f28
--- /dev/null
+++ b/src/quicktemplates2/qquickpage_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPAGE_P_H
+#define QQUICKPAGE_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 <QtQuickTemplates2/private/qquickpane_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPagePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPage : public QQuickPane
+{
+ Q_OBJECT
+ Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged 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)
+ Q_PROPERTY(qreal implicitHeaderWidth READ implicitHeaderWidth NOTIFY implicitHeaderWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitHeaderHeight READ implicitHeaderHeight NOTIFY implicitHeaderHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitFooterWidth READ implicitFooterWidth NOTIFY implicitFooterWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitFooterHeight READ implicitFooterHeight NOTIFY implicitFooterHeightChanged FINAL REVISION(2, 5))
+ QML_NAMED_ELEMENT(Page)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickPage(QQuickItem *parent = nullptr);
+ ~QQuickPage();
+
+ QString title() const;
+ void setTitle(const QString &title);
+
+ QQuickItem *header() const;
+ void setHeader(QQuickItem *header);
+
+ QQuickItem *footer() const;
+ void setFooter(QQuickItem *footer);
+
+ // 2.5 (Qt 5.12)
+ qreal implicitHeaderWidth() const;
+ qreal implicitHeaderHeight() const;
+
+ qreal implicitFooterWidth() const;
+ qreal implicitFooterHeight() const;
+
+Q_SIGNALS:
+ void titleChanged();
+ void headerChanged();
+ void footerChanged();
+ // 2.5 (Qt 5.12)
+ void implicitHeaderWidthChanged();
+ void implicitHeaderHeightChanged();
+ void implicitFooterWidthChanged();
+ void implicitFooterHeightChanged();
+
+protected:
+ QQuickPage(QQuickPagePrivate &dd, QQuickItem *parent);
+
+ void componentComplete() override;
+
+ void spacingChange(qreal newSpacing, qreal oldSpacing) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickPage)
+ Q_DECLARE_PRIVATE(QQuickPage)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPage)
+
+#endif // QQUICKPAGE_P_H
diff --git a/src/quicktemplates2/qquickpage_p_p.h b/src/quicktemplates2/qquickpage_p_p.h
new file mode 100644
index 0000000000..6c8b037102
--- /dev/null
+++ b/src/quicktemplates2/qquickpage_p_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPAGE_P_P_H
+#define QQUICKPAGE_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 <QtQuickTemplates2/private/qquickpane_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPane;
+
+class QQuickPagePrivate : public QQuickPanePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPage)
+
+public:
+ void relayout();
+ void resizeContent() override;
+
+ void itemVisibilityChanged(QQuickItem *item) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF & diff) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QString title;
+ QQuickItem *header = nullptr;
+ QQuickItem *footer = nullptr;
+ bool emittingImplicitSizeChangedSignals = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPAGE_P_P_H
diff --git a/src/quicktemplates2/qquickpageindicator.cpp b/src/quicktemplates2/qquickpageindicator.cpp
new file mode 100644
index 0000000000..42834962e1
--- /dev/null
+++ b/src/quicktemplates2/qquickpageindicator.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpageindicator_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PageIndicator
+ \inherits Control
+//! \instantiates QQuickPageIndicator
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-indicators
+ \brief Indicates the currently active page.
+
+ PageIndicator is used to indicate the currently active page
+ in a container of multiple pages. PageIndicator consists of
+ delegate items that present pages.
+
+ \image qtquickcontrols2-pageindicator.png
+
+ \code
+ Column {
+ StackLayout {
+ id: stackLayout
+
+ Page {
+ // ...
+ }
+ Page {
+ // ...
+ }
+ Page {
+ // ...
+ }
+ }
+
+ PageIndicator {
+ currentIndex: stackLayout.currentIndex
+ count: stackLayout.count
+ }
+ }
+ \endcode
+
+ \sa SwipeView, {Customizing PageIndicator}, {Indicator Controls}
+*/
+
+class QQuickPageIndicatorPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPageIndicator)
+
+public:
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ QQuickItem *itemAt(const QPointF &pos) const;
+ void updatePressed(bool pressed, const QPointF &pos = QPointF());
+ void setContextProperty(QQuickItem *item, const QString &name, const QVariant &value);
+
+ void itemChildAdded(QQuickItem *, QQuickItem *child) override;
+
+ int count = 0;
+ int currentIndex = 0;
+ bool interactive = false;
+ QQmlComponent *delegate = nullptr;
+ QQuickItem *pressedItem = nullptr;
+};
+
+void QQuickPageIndicatorPrivate::handlePress(const QPointF &point)
+{
+ QQuickControlPrivate::handlePress(point);
+ if (interactive)
+ updatePressed(true, point);
+}
+
+void QQuickPageIndicatorPrivate::handleMove(const QPointF &point)
+{
+ QQuickControlPrivate::handleMove(point);
+ if (interactive)
+ updatePressed(true, point);
+}
+
+void QQuickPageIndicatorPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickPageIndicator);
+ QQuickControlPrivate::handleRelease(point);
+ if (interactive) {
+ if (pressedItem && contentItem)
+ q->setCurrentIndex(contentItem->childItems().indexOf(pressedItem));
+ updatePressed(false);
+ }
+}
+
+void QQuickPageIndicatorPrivate::handleUngrab()
+{
+ QQuickControlPrivate::handleUngrab();
+ if (interactive)
+ updatePressed(false);
+}
+
+QQuickItem *QQuickPageIndicatorPrivate::itemAt(const QPointF &pos) const
+{
+ Q_Q(const QQuickPageIndicator);
+ if (!contentItem || !q->contains(pos))
+ return nullptr;
+
+ QPointF contentPos = q->mapToItem(contentItem, pos);
+ QQuickItem *item = contentItem->childAt(contentPos.x(), contentPos.y());
+ while (item && item->parentItem() != contentItem)
+ item = item->parentItem();
+ if (item && !QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return item;
+
+ // find the nearest
+ qreal distance = qInf();
+ QQuickItem *nearest = nullptr;
+ const auto childItems = contentItem->childItems();
+ for (QQuickItem *child : childItems) {
+ if (QQuickItemPrivate::get(child)->isTransparentForPositioner())
+ continue;
+
+ QPointF center = child->boundingRect().center();
+ QPointF pt = contentItem->mapToItem(child, contentPos);
+
+ qreal len = QLineF(center, pt).length();
+ if (len < distance) {
+ distance = len;
+ nearest = child;
+ }
+ }
+ return nearest;
+}
+
+void QQuickPageIndicatorPrivate::updatePressed(bool pressed, const QPointF &pos)
+{
+ QQuickItem *prevItem = pressedItem;
+ pressedItem = pressed ? itemAt(pos) : nullptr;
+ if (prevItem != pressedItem) {
+ setContextProperty(prevItem, QStringLiteral("pressed"), false);
+ setContextProperty(pressedItem, QStringLiteral("pressed"), pressed);
+ }
+}
+
+void QQuickPageIndicatorPrivate::setContextProperty(QQuickItem *item, const QString &name, const QVariant &value)
+{
+ QQmlContext *context = qmlContext(item);
+ if (context && context->isValid()) {
+ context = context->parentContext();
+ if (context && context->isValid())
+ context->setContextProperty(name, value);
+ }
+}
+
+void QQuickPageIndicatorPrivate::itemChildAdded(QQuickItem *, QQuickItem *child)
+{
+ if (!QQuickItemPrivate::get(child)->isTransparentForPositioner())
+ setContextProperty(child, QStringLiteral("pressed"), false);
+}
+
+QQuickPageIndicator::QQuickPageIndicator(QQuickItem *parent)
+ : QQuickControl(*(new QQuickPageIndicatorPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::PageIndicator::count
+
+ This property holds the number of pages.
+*/
+int QQuickPageIndicator::count() const
+{
+ Q_D(const QQuickPageIndicator);
+ return d->count;
+}
+
+void QQuickPageIndicator::setCount(int count)
+{
+ Q_D(QQuickPageIndicator);
+ if (d->count == count)
+ return;
+
+ d->count = count;
+ emit countChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::PageIndicator::currentIndex
+
+ This property holds the index of the current page.
+*/
+int QQuickPageIndicator::currentIndex() const
+{
+ Q_D(const QQuickPageIndicator);
+ return d->currentIndex;
+}
+
+void QQuickPageIndicator::setCurrentIndex(int index)
+{
+ Q_D(QQuickPageIndicator);
+ if (d->currentIndex == index)
+ return;
+
+ d->currentIndex = index;
+ emit currentIndexChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::PageIndicator::interactive
+
+ This property holds whether the control is interactive. An interactive page indicator
+ reacts to presses and automatically changes the \l {currentIndex}{current index}
+ appropriately.
+
+ \snippet qtquickcontrols2-pageindicator-interactive.qml 1
+
+ \note Page indicators are typically quite small (in order to avoid
+ distracting the user from the actual content of the user interface). They
+ can be hard to click, and might not be easily recognized as interactive by
+ the user. For these reasons, they are best used to complement primary
+ methods of navigation (such as \l SwipeView), not replace them.
+
+ The default value is \c false.
+*/
+bool QQuickPageIndicator::isInteractive() const
+{
+ Q_D(const QQuickPageIndicator);
+ return d->interactive;
+}
+
+void QQuickPageIndicator::setInteractive(bool interactive)
+{
+ Q_D(QQuickPageIndicator);
+ if (d->interactive == interactive)
+ return;
+
+ d->interactive = interactive;
+ if (interactive) {
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+ } else {
+ setAcceptedMouseButtons(Qt::NoButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ unsetCursor();
+#endif
+ }
+ emit interactiveChanged();
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::PageIndicator::delegate
+
+ This property holds a delegate that presents a page.
+
+ The following properties are available in the context of each delegate:
+ \table
+ \row \li \b index : int \li The index of the item
+ \row \li \b pressed : bool \li Whether the item is pressed
+ \endtable
+*/
+QQmlComponent *QQuickPageIndicator::delegate() const
+{
+ Q_D(const QQuickPageIndicator);
+ return d->delegate;
+}
+
+void QQuickPageIndicator::setDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickPageIndicator);
+ if (d->delegate == delegate)
+ return;
+
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+void QQuickPageIndicator::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickPageIndicator);
+ QQuickControl::contentItemChange(newItem, oldItem);
+ if (oldItem)
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::Children);
+ if (newItem)
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::Children);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickPageIndicator::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickPageIndicator);
+ if (d->interactive)
+ QQuickControl::touchEvent(event);
+ else
+ event->ignore(); // QTBUG-61785
+}
+#endif
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickPageIndicator::accessibleRole() const
+{
+ return QAccessible::Indicator;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpageindicator_p.cpp"
diff --git a/src/quicktemplates2/qquickpageindicator_p.h b/src/quicktemplates2/qquickpageindicator_p.h
new file mode 100644
index 0000000000..a21e88fe49
--- /dev/null
+++ b/src/quicktemplates2/qquickpageindicator_p.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPAGEINDICATOR_P_H
+#define QQUICKPAGEINDICATOR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickPageIndicatorPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPageIndicator : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged FINAL)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged FINAL)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ QML_NAMED_ELEMENT(PageIndicator)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickPageIndicator(QQuickItem *parent = nullptr);
+
+ int count() const;
+ void setCount(int count);
+
+ int currentIndex() const;
+ void setCurrentIndex(int index);
+
+ bool isInteractive() const;
+ void setInteractive(bool interactive);
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+Q_SIGNALS:
+ void countChanged();
+ void currentIndexChanged();
+ void interactiveChanged();
+ void delegateChanged();
+
+protected:
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickPageIndicator)
+ Q_DECLARE_PRIVATE(QQuickPageIndicator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPageIndicator)
+
+#endif // QQUICKPAGEINDICATOR_P_H
diff --git a/src/quicktemplates2/qquickpane.cpp b/src/quicktemplates2/qquickpane.cpp
new file mode 100644
index 0000000000..3cdc450fd1
--- /dev/null
+++ b/src/quicktemplates2/qquickpane.cpp
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpane_p.h"
+#include "qquickpane_p_p.h"
+#include "qquickcontentitem_p.h"
+
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPane, "qt.quick.controls.pane")
+
+/*!
+ \qmltype Pane
+ \inherits Control
+//! \instantiates QQuickPane
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Provides a background matching with the application style and theme.
+
+ Pane provides a background color that matches with the application style
+ and theme. Pane 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.
+
+ Items declared as children of a Pane are automatically parented to the
+ Pane's \l[QtQuickControls2]{Control::}{contentItem}. Items created
+ dynamically need to be explicitly parented to the \c contentItem.
+
+ \section1 Content Sizing
+
+ If only a single item is used within a Pane, it will resize to fit the
+ implicit size of its contained item. This makes it particularly suitable
+ for use together with layouts.
+
+ \image qtquickcontrols2-pane.png
+
+ \snippet qtquickcontrols2-pane.qml 1
+
+ Sometimes there might be two items within the pane:
+
+ \code
+ Pane {
+ SwipeView {
+ // ...
+ }
+ PageIndicator {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ }
+ }
+ \endcode
+
+ In this case, Pane cannot calculate a sensible implicit size. Since we're
+ anchoring the \l PageIndicator over the \l SwipeView, we can simply set the
+ content size to the view's implicit size:
+
+ \code
+ Pane {
+ contentWidth: view.implicitWidth
+ contentHeight: view.implicitHeight
+
+ SwipeView {
+ id: view
+ // ...
+ }
+ PageIndicator {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ }
+ }
+ \endcode
+
+ If the \l[QtQuickControls2]{Control::}{contentItem} has no implicit size
+ and only one child, Pane will use the implicit size of that child. For
+ example, in the following code, the Pane assumes the size of the Rectangle:
+
+ \code
+ Pane {
+ Item {
+ Rectangle {
+ implicitWidth: 200
+ implicitHeight: 200
+ color: "salmon"
+ }
+ }
+ }
+ \endcode
+
+ \sa {Customizing Pane}, {Container Controls},
+ {Focus Management in Qt Quick Controls}, {Event Handling}
+*/
+
+void QQuickPanePrivate::init()
+{
+ Q_Q(QQuickPane);
+ q->setFlag(QQuickItem::ItemIsFocusScope);
+ q->setAcceptedMouseButtons(Qt::AllButtons);
+#if QT_CONFIG(cursor)
+ q->setCursor(Qt::ArrowCursor);
+#endif
+ connect(q, &QQuickControl::implicitContentWidthChanged, this, &QQuickPanePrivate::updateContentWidth);
+ connect(q, &QQuickControl::implicitContentHeightChanged, this, &QQuickPanePrivate::updateContentHeight);
+}
+
+QList<QQuickItem *> QQuickPanePrivate::contentChildItems() const
+{
+ if (!contentItem)
+ return QList<QQuickItem *>();
+
+ return contentItem->childItems();
+}
+
+QQuickItem *QQuickPanePrivate::getContentItem()
+{
+ Q_Q(QQuickPane);
+ if (QQuickItem *item = QQuickControlPrivate::getContentItem())
+ return item;
+
+ return new QQuickContentItem(q);
+}
+
+void QQuickPanePrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+
+ if (item == firstChild)
+ updateImplicitContentWidth();
+}
+
+void QQuickPanePrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+
+ if (item == firstChild)
+ updateImplicitContentHeight();
+}
+
+void QQuickPanePrivate::contentChildrenChange()
+{
+ Q_Q(QQuickPane);
+ QQuickItem *newFirstChild = contentChildItems().value(0);
+ if (newFirstChild != firstChild) {
+ if (firstChild)
+ removeImplicitSizeListener(firstChild);
+ if (newFirstChild)
+ addImplicitSizeListener(newFirstChild);
+ firstChild = newFirstChild;
+ }
+
+ updateImplicitContentSize();
+ emit q->contentChildrenChanged();
+}
+
+qreal QQuickPanePrivate::getContentWidth() const
+{
+ if (!contentItem)
+ return 0;
+
+ const qreal cw = contentItem->implicitWidth();
+ if (!qFuzzyIsNull(cw))
+ return cw;
+
+ const auto contentChildren = contentChildItems();
+ if (contentChildren.count() == 1)
+ return contentChildren.first()->implicitWidth();
+
+ return 0;
+}
+
+qreal QQuickPanePrivate::getContentHeight() const
+{
+ if (!contentItem)
+ return 0;
+
+ const qreal ch = contentItem->implicitHeight();
+ if (!qFuzzyIsNull(ch))
+ return ch;
+
+ const auto contentChildren = contentChildItems();
+ if (contentChildren.count() == 1)
+ return contentChildren.first()->implicitHeight();
+
+ return 0;
+}
+
+void QQuickPanePrivate::updateContentWidth()
+{
+ Q_Q(QQuickPane);
+ if (hasContentWidth || qFuzzyCompare(contentWidth, implicitContentWidth))
+ return;
+
+ const qreal oldContentWidth = contentWidth;
+ contentWidth = implicitContentWidth;
+ qCDebug(lcPane) << "contentWidth of" << q << "changed to" << contentWidth;
+ q->contentSizeChange(QSizeF(contentWidth, contentHeight), QSizeF(oldContentWidth, contentHeight));
+ emit q->contentWidthChanged();
+}
+
+void QQuickPanePrivate::updateContentHeight()
+{
+ Q_Q(QQuickPane);
+ if (hasContentHeight || qFuzzyCompare(contentHeight, implicitContentHeight))
+ return;
+
+ const qreal oldContentHeight = contentHeight;
+ contentHeight = implicitContentHeight;
+ qCDebug(lcPane) << "contentHeight of" << q << "changed to" << contentHeight;
+ q->contentSizeChange(QSizeF(contentWidth, contentHeight), QSizeF(contentWidth, oldContentHeight));
+ emit q->contentHeightChanged();
+}
+
+QQuickPane::QQuickPane(QQuickItem *parent)
+ : QQuickControl(*(new QQuickPanePrivate), parent)
+{
+ Q_D(QQuickPane);
+ d->init();
+}
+
+QQuickPane::~QQuickPane()
+{
+ Q_D(QQuickPane);
+ d->removeImplicitSizeListener(d->contentItem);
+ d->removeImplicitSizeListener(d->firstChild);
+}
+
+QQuickPane::QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent)
+ : QQuickControl(dd, parent)
+{
+ Q_D(QQuickPane);
+ d->init();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Pane::contentWidth
+
+ This property holds the content width. It is used for calculating the total
+ implicit width of the pane.
+
+ For more information, see \l {Content Sizing}.
+
+ \sa contentHeight
+*/
+qreal QQuickPane::contentWidth() const
+{
+ Q_D(const QQuickPane);
+ return d->contentWidth;
+}
+
+void QQuickPane::setContentWidth(qreal width)
+{
+ Q_D(QQuickPane);
+ d->hasContentWidth = true;
+ if (qFuzzyCompare(d->contentWidth, width))
+ return;
+
+ const qreal oldWidth = d->contentWidth;
+ d->contentWidth = width;
+ contentSizeChange(QSizeF(width, d->contentHeight), QSizeF(oldWidth, d->contentHeight));
+ emit contentWidthChanged();
+}
+
+void QQuickPane::resetContentWidth()
+{
+ Q_D(QQuickPane);
+ if (!d->hasContentWidth)
+ return;
+
+ d->hasContentHeight = false;
+ d->updateContentWidth();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Pane::contentHeight
+
+ This property holds the content height. It is used for calculating the total
+ implicit height of the pane.
+
+ For more information, see \l {Content Sizing}.
+
+ \sa contentWidth
+*/
+qreal QQuickPane::contentHeight() const
+{
+ Q_D(const QQuickPane);
+ return d->contentHeight;
+}
+
+void QQuickPane::setContentHeight(qreal height)
+{
+ Q_D(QQuickPane);
+ d->hasContentHeight = true;
+ if (qFuzzyCompare(d->contentHeight, height))
+ return;
+
+ const qreal oldHeight = d->contentHeight;
+ d->contentHeight = height;
+ contentSizeChange(QSizeF(d->contentWidth, height), QSizeF(d->contentWidth, oldHeight));
+ emit contentHeightChanged();
+}
+
+void QQuickPane::resetContentHeight()
+{
+ Q_D(QQuickPane);
+ if (!d->hasContentHeight)
+ return;
+
+ d->hasContentHeight = false;
+ d->updateContentHeight();
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::Pane::contentData
+ \qmldefault
+
+ This property holds the list of content data.
+
+ The list contains all objects that have been declared in QML as children
+ of the pane.
+
+ \note Unlike \c contentChildren, \c contentData does include non-visual QML
+ objects.
+
+ \sa Item::data, contentChildren
+*/
+QQmlListProperty<QObject> QQuickPanePrivate::contentData()
+{
+ Q_Q(QQuickPane);
+ return QQmlListProperty<QObject>(q->contentItem(), nullptr,
+ QQuickItemPrivate::data_append,
+ QQuickItemPrivate::data_count,
+ QQuickItemPrivate::data_at,
+ QQuickItemPrivate::data_clear);
+}
+
+/*!
+ \qmlproperty list<Item> QtQuick.Controls::Pane::contentChildren
+
+ This property holds the list of content children.
+
+ The list contains all items that have been declared in QML as children
+ of the pane.
+
+ \note Unlike \c contentData, \c contentChildren does not include non-visual
+ QML objects.
+
+ \sa Item::children, contentData
+*/
+QQmlListProperty<QQuickItem> QQuickPanePrivate::contentChildren()
+{
+ Q_Q(QQuickPane);
+ return QQmlListProperty<QQuickItem>(q->contentItem(), nullptr,
+ QQuickItemPrivate::children_append,
+ QQuickItemPrivate::children_count,
+ QQuickItemPrivate::children_at,
+ QQuickItemPrivate::children_clear);
+}
+
+void QQuickPane::componentComplete()
+{
+ Q_D(QQuickPane);
+ QQuickControl::componentComplete();
+ d->updateImplicitContentSize();
+}
+
+void QQuickPane::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickPane);
+ QQuickControl::contentItemChange(newItem, oldItem);
+ if (oldItem) {
+ d->removeImplicitSizeListener(oldItem);
+ QObjectPrivate::disconnect(oldItem, &QQuickItem::childrenChanged, d, &QQuickPanePrivate::contentChildrenChange);
+ }
+ if (newItem) {
+ d->addImplicitSizeListener(newItem);
+ QObjectPrivate::connect(newItem, &QQuickItem::childrenChanged, d, &QQuickPanePrivate::contentChildrenChange);
+ }
+ d->contentChildrenChange();
+}
+
+void QQuickPane::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
+{
+ Q_UNUSED(newSize);
+ Q_UNUSED(oldSize);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickPane::accessibleRole() const
+{
+ return QAccessible::Pane;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpane_p.cpp"
diff --git a/src/quicktemplates2/qquickpane_p.h b/src/quicktemplates2/qquickpane_p.h
new file mode 100644
index 0000000000..2aeb94cd7e
--- /dev/null
+++ b/src/quicktemplates2/qquickpane_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPANE_P_H
+#define QQUICKPANE_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPanePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPane : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth RESET resetContentWidth NOTIFY contentWidthChanged FINAL)
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight RESET resetContentHeight NOTIFY contentHeightChanged FINAL)
+ Q_PRIVATE_PROPERTY(QQuickPane::d_func(), QQmlListProperty<QObject> contentData READ contentData FINAL)
+ Q_PRIVATE_PROPERTY(QQuickPane::d_func(), QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL)
+ Q_CLASSINFO("DefaultProperty", "contentData")
+ QML_NAMED_ELEMENT(Pane)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickPane(QQuickItem *parent = nullptr);
+ ~QQuickPane();
+
+ qreal contentWidth() const;
+ void setContentWidth(qreal width);
+ void resetContentWidth();
+
+ qreal contentHeight() const;
+ void setContentHeight(qreal height);
+ void resetContentHeight();
+
+Q_SIGNALS:
+ void contentWidthChanged();
+ void contentHeightChanged();
+ void contentChildrenChanged();
+
+protected:
+ QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent);
+
+ void componentComplete() override;
+
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ virtual void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize);
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickPane)
+ Q_DECLARE_PRIVATE(QQuickPane)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPane)
+
+#endif // QQUICKPANE_P_H
diff --git a/src/quicktemplates2/qquickpane_p_p.h b/src/quicktemplates2/qquickpane_p_p.h
new file mode 100644
index 0000000000..bd89aee2f8
--- /dev/null
+++ b/src/quicktemplates2/qquickpane_p_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPANE_P_P_H
+#define QQUICKPANE_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 <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPane;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPanePrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPane)
+
+public:
+ void init();
+
+ virtual QQmlListProperty<QObject> contentData();
+ virtual QQmlListProperty<QQuickItem> contentChildren();
+ virtual QList<QQuickItem *> contentChildItems() const;
+
+ QQuickItem *getContentItem() override;
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void contentChildrenChange();
+
+ void updateContentWidth();
+ void updateContentHeight();
+
+ bool hasContentWidth = false;
+ bool hasContentHeight = false;
+ qreal contentWidth = 0;
+ qreal contentHeight = 0;
+ QQuickItem *firstChild = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPANE_P_P_H
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
new file mode 100644
index 0000000000..a3492fcb54
--- /dev/null
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -0,0 +1,2799 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpopup_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickpopupanchors_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickpopuppositioner_p_p.h"
+#include "qquickapplicationwindow_p.h"
+#include "qquickoverlay_p_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickdialog_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquicktransition_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer")
+Q_LOGGING_CATEGORY(lcPopup, "qt.quick.controls.popup")
+
+/*!
+ \qmltype Popup
+ \inherits QtObject
+//! \instantiates QQuickPopup
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-popups
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Base type of popup-like user interface controls.
+
+ Popup is the base type of popup-like user interface controls. It can be
+ used with \l Window or \l ApplicationWindow.
+
+ \qml
+ import QtQuick.Window 2.2
+ import QtQuick.Controls 2.12
+
+ ApplicationWindow {
+ id: window
+ width: 400
+ height: 400
+ visible: true
+
+ Button {
+ text: "Open"
+ onClicked: popup.open()
+ }
+
+ Popup {
+ id: popup
+ x: 100
+ y: 100
+ width: 200
+ height: 300
+ modal: true
+ focus: true
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent
+ }
+ }
+ \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.
+
+ Items declared as children of a Popup are automatically parented to the
+ Popups's \l contentItem. Items created dynamically need to be explicitly
+ parented to the contentItem.
+
+ \section1 Popup Layout
+
+ The following diagram illustrates the layout of a popup within a window:
+
+ \image qtquickcontrols2-popup.png
+
+ The \l implicitWidth and \l implicitHeight of a popup are typically based
+ on the implicit sizes of the background and the content item plus any insets
+ and paddings. These properties determine how large the popup will be when no
+ explicit \l width or \l height is specified.
+
+ The geometry of the \l contentItem is determined by the padding. The following
+ example reserves 10px padding between the boundaries of the popup and its content:
+
+ \code
+ Popup {
+ padding: 10
+
+ contentItem: Text {
+ text: "Content"
+ }
+ }
+ \endcode
+
+ The \l background item fills the entire width and height of the popup,
+ unless insets or an explicit size have been given for it.
+
+ Negative insets can be used to make the background larger than the popup.
+ The following example uses negative insets to place a shadow outside the
+ popup's boundaries:
+
+ \code
+ Popup {
+ topInset: -2
+ leftInset: -2
+ rightInset: -6
+ bottomInset: -6
+
+ background: BorderImage {
+ source: ":/images/shadowed-background.png"
+ }
+ }
+ \endcode
+
+ \section1 Popup Sizing
+
+ If only a single item is used within a Popup, it will resize to fit the
+ implicit size of its contained item. This makes it particularly suitable
+ for use together with layouts.
+
+ \code
+ Popup {
+ ColumnLayout {
+ anchors.fill: parent
+ CheckBox { text: qsTr("E-mail") }
+ CheckBox { text: qsTr("Calendar") }
+ CheckBox { text: qsTr("Contacts") }
+ }
+ }
+ \endcode
+
+ Sometimes there might be two items within the popup:
+
+ \code
+ Popup {
+ SwipeView {
+ // ...
+ }
+ PageIndicator {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ }
+ }
+ \endcode
+
+ In this case, Popup cannot calculate a sensible implicit size. Since we're
+ anchoring the \l PageIndicator over the \l SwipeView, we can simply set the
+ content size to the view's implicit size:
+
+ \code
+ Popup {
+ contentWidth: view.implicitWidth
+ contentHeight: view.implicitHeight
+
+ SwipeView {
+ id: view
+ // ...
+ }
+ PageIndicator {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ }
+ }
+ \endcode
+
+ \section1 Popup Positioning
+
+ Similar to items in Qt Quick, Popup's \l x and \l y coordinates are
+ relative to its parent. This means that opening a popup that is a
+ child of a \l Button, for example, will cause the popup to be positioned
+ relative to the button.
+
+ \include qquickoverlay-popup-parent.qdocinc
+
+ Another way to center a popup in the window regardless of its parent item
+ is to use \l {anchors.centerIn}:
+
+ \snippet qtquickcontrols2-popup.qml centerIn
+
+ To ensure that the popup is positioned within the bounds of the enclosing
+ window, the \l margins property can be set to a non-negative value.
+
+ \section1 Popup Transitions
+
+ Since Qt 5.15.3 the following properties are restored to their original values from before
+ the enter transition after the exit transition is completed.
+
+ \list
+ \li \l opacity
+ \li \l scale
+ \endlist
+
+ This allows the built-in styles to animate on these properties without losing any explicitly
+ defined value.
+
+ \section1 Back/Escape Event Handling
+
+ By default, a Popup will close if the Escape or Back keys are pressed. This
+ can be problematic for popups which contain items that want to handle those
+ events themselves. There are two solutions to this:
+
+ \list
+ \li Set Popup's \l closePolicy to a value that does not include
+ \c {Popup.CloseOnEscape}.
+ \li Handle \l {Keys}' \l {Keys::}{shortcutOverride} signal and accept the
+ event before Popup can.
+ \endlist
+
+ \sa {Popup Controls}, {Customizing Popup}, ApplicationWindow
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::Popup::opened()
+
+ This signal is emitted when the popup is opened.
+
+ \sa aboutToShow()
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::Popup::closed()
+
+ This signal is emitted when the popup is closed.
+
+ \sa aboutToHide()
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::Popup::aboutToShow()
+
+ This signal is emitted when the popup is about to show.
+
+ \sa opened()
+*/
+
+/*!
+ \qmlsignal void QtQuick.Controls::Popup::aboutToHide()
+
+ This signal is emitted when the popup is about to hide.
+
+ \sa closed()
+*/
+
+const QQuickPopup::ClosePolicy QQuickPopupPrivate::DefaultClosePolicy = QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutside;
+
+QQuickPopupPrivate::QQuickPopupPrivate()
+ : transitionManager(this)
+{
+}
+
+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);
+ QObject::connect(popupItem, &QQuickControl::implicitContentWidthChanged, q, &QQuickPopup::implicitContentWidthChanged);
+ QObject::connect(popupItem, &QQuickControl::implicitContentHeightChanged, q, &QQuickPopup::implicitContentHeightChanged);
+ QObject::connect(popupItem, &QQuickControl::implicitBackgroundWidthChanged, q, &QQuickPopup::implicitBackgroundWidthChanged);
+ QObject::connect(popupItem, &QQuickControl::implicitBackgroundHeightChanged, q, &QQuickPopup::implicitBackgroundHeightChanged);
+}
+
+void QQuickPopupPrivate::closeOrReject()
+{
+ Q_Q(QQuickPopup);
+ if (QQuickDialog *dialog = qobject_cast<QQuickDialog*>(q))
+ dialog->reject();
+ else
+ q->close();
+}
+
+bool QQuickPopupPrivate::tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags)
+{
+ if (!interactive)
+ return false;
+
+ static const QQuickPopup::ClosePolicy outsideFlags = QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnReleaseOutside;
+ static const QQuickPopup::ClosePolicy outsideParentFlags = QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent;
+
+ const bool onOutside = closePolicy & (flags & outsideFlags);
+ const bool onOutsideParent = closePolicy & (flags & outsideParentFlags);
+
+ if ((onOutside && outsidePressed) || (onOutsideParent && outsideParentPressed)) {
+ if (!contains(pos) && (!dimmer || dimmer->contains(dimmer->mapFromScene(pos)))) {
+ if (!onOutsideParent || !parentItem || !parentItem->contains(parentItem->mapFromScene(pos))) {
+ closeOrReject();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool QQuickPopupPrivate::contains(const QPointF &scenePos) const
+{
+ return popupItem->contains(popupItem->mapFromScene(scenePos));
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickPopupPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
+{
+ if (point.id() == touchId)
+ return true;
+
+ if (touchId == -1 && point.state() != QEventPoint::Released) {
+ touchId = point.id();
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+bool QQuickPopupPrivate::blockInput(QQuickItem *item, const QPointF &point) const
+{
+ // don't propagate events within the popup beyond the overlay
+ if (popupItem->contains(popupItem->mapFromScene(point))
+ && item == QQuickOverlay::overlay(window)) {
+ return true;
+ }
+
+ // don't block presses and releases
+ // a) outside a non-modal popup,
+ // b) to popup children/content, or
+ // b) outside a modal popups's background dimming
+ return modal && !popupItem->isAncestorOf(item) && (!dimmer || dimmer->contains(dimmer->mapFromScene(point)));
+}
+
+bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ Q_UNUSED(timestamp);
+ pressPoint = point;
+ outsidePressed = !contains(point);
+ outsideParentPressed = outsidePressed && parentItem && !parentItem->contains(parentItem->mapFromScene(point));
+ tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
+ return blockInput(item, point);
+}
+
+bool QQuickPopupPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ Q_UNUSED(timestamp);
+ return blockInput(item, point);
+}
+
+bool QQuickPopupPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ Q_UNUSED(timestamp);
+ if (item != popupItem && !contains(pressPoint))
+ tryClose(point, QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
+ pressPoint = QPointF();
+ outsidePressed = false;
+ outsideParentPressed = false;
+ touchId = -1;
+ return blockInput(item, point);
+}
+
+void QQuickPopupPrivate::handleUngrab()
+{
+ Q_Q(QQuickPopup);
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+ if (overlay) {
+ QQuickOverlayPrivate *p = QQuickOverlayPrivate::get(overlay);
+ if (p->mouseGrabberPopup == q)
+ p->mouseGrabberPopup = nullptr;
+ }
+ pressPoint = QPointF();
+ touchId = -1;
+}
+
+bool QQuickPopupPrivate::handleMouseEvent(QQuickItem *item, QMouseEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ return handlePress(item, event->scenePosition(), event->timestamp());
+ case QEvent::MouseMove:
+ return handleMove(item, event->scenePosition(), event->timestamp());
+ case QEvent::MouseButtonRelease:
+ return handleRelease(item, event->scenePosition(), event->timestamp());
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+}
+
+bool QQuickPopupPrivate::handleHoverEvent(QQuickItem *item, QHoverEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ case QEvent::HoverLeave:
+ return blockInput(item, event->scenePosition());
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (event->type() != QEvent::TouchEnd && !acceptTouch(point))
+ return blockInput(item, point.position());
+
+ switch (point.state()) {
+ case QEventPoint::Pressed:
+ return handlePress(item, item->mapToScene(point.position()), event->timestamp());
+ case QEventPoint::Updated:
+ return handleMove(item, item->mapToScene(point.position()), event->timestamp());
+ case QEventPoint::Released:
+ return handleRelease(item, item->mapToScene(point.position()), event->timestamp());
+ default:
+ break;
+ }
+ }
+ break;
+
+ case QEvent::TouchCancel:
+ handleUngrab();
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+#endif
+
+bool QQuickPopupPrivate::prepareEnterTransition()
+{
+ Q_Q(QQuickPopup);
+ if (!window) {
+ qmlWarning(q) << "cannot find any window to open popup in.";
+ return false;
+ }
+
+ if (transitionState == EnterTransition && transitionManager.isRunning())
+ return false;
+
+ if (transitionState != EnterTransition) {
+ popupItem->setParentItem(QQuickOverlay::overlay(window));
+ if (dim)
+ createOverlay();
+ showOverlay();
+ emit q->aboutToShow();
+ visible = true;
+ transitionState = EnterTransition;
+ popupItem->setVisible(true);
+ getPositioner()->setParentItem(parentItem);
+ emit q->visibleChanged();
+
+ if (focus)
+ popupItem->setFocus(true, Qt::PopupFocusReason);
+ }
+ return true;
+}
+
+bool QQuickPopupPrivate::prepareExitTransition()
+{
+ Q_Q(QQuickPopup);
+ if (transitionState == ExitTransition && transitionManager.isRunning())
+ return false;
+
+ // We need to cache the original scale and opacity values so we can reset it after
+ // the exit transition is done so they have the original values again
+ prevScale = popupItem->scale();
+ prevOpacity = popupItem->opacity();
+
+ if (transitionState != ExitTransition) {
+ // The setFocus(false) call below removes any active focus before we're
+ // able to check it in finalizeExitTransition.
+ if (!hadActiveFocusBeforeExitTransition)
+ hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus();
+ if (focus)
+ popupItem->setFocus(false, Qt::PopupFocusReason);
+ transitionState = ExitTransition;
+ hideOverlay();
+ emit q->aboutToHide();
+ emit q->openedChanged();
+ }
+ return true;
+}
+
+void QQuickPopupPrivate::finalizeEnterTransition()
+{
+ Q_Q(QQuickPopup);
+ transitionState = NoTransition;
+ getPositioner()->reposition();
+ emit q->openedChanged();
+ opened();
+}
+
+void QQuickPopupPrivate::finalizeExitTransition()
+{
+ Q_Q(QQuickPopup);
+ getPositioner()->setParentItem(nullptr);
+ if (popupItem) {
+ popupItem->setParentItem(nullptr);
+ popupItem->setVisible(false);
+ }
+ destroyOverlay();
+
+ if (hadActiveFocusBeforeExitTransition && window) {
+ // restore focus to the next popup in chain, or to the window content if there are no other popups open
+ QQuickPopup *nextFocusPopup = nullptr;
+ if (QQuickOverlay *overlay = QQuickOverlay::overlay(window)) {
+ const auto stackingOrderPopups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
+ for (auto popup : stackingOrderPopups) {
+ if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition
+ && popup->hasFocus()) {
+ nextFocusPopup = popup;
+ break;
+ }
+ }
+ }
+ if (nextFocusPopup) {
+ nextFocusPopup->forceActiveFocus(Qt::PopupFocusReason);
+ } else {
+ QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window);
+ if (applicationWindow)
+ applicationWindow->contentItem()->setFocus(true, Qt::PopupFocusReason);
+ else
+ window->contentItem()->setFocus(true, Qt::PopupFocusReason);
+ }
+ }
+
+ visible = false;
+ transitionState = NoTransition;
+ hadActiveFocusBeforeExitTransition = false;
+ emit q->visibleChanged();
+ emit q->closed();
+ if (popupItem) {
+ popupItem->setScale(prevScale);
+ popupItem->setOpacity(prevOpacity);
+ }
+}
+
+void QQuickPopupPrivate::opened()
+{
+ Q_Q(QQuickPopup);
+ emit q->opened();
+}
+
+QMarginsF QQuickPopupPrivate::getMargins() const
+{
+ Q_Q(const QQuickPopup);
+ return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin());
+}
+
+void QQuickPopupPrivate::setTopMargin(qreal value, bool reset)
+{
+ Q_Q(QQuickPopup);
+ qreal oldMargin = q->topMargin();
+ topMargin = value;
+ hasTopMargin = !reset;
+ if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
+ emit q->topMarginChanged();
+ q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
+ QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin));
+ }
+}
+
+void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset)
+{
+ Q_Q(QQuickPopup);
+ qreal oldMargin = q->leftMargin();
+ leftMargin = value;
+ hasLeftMargin = !reset;
+ if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
+ emit q->leftMarginChanged();
+ q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
+ QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin));
+ }
+}
+
+void QQuickPopupPrivate::setRightMargin(qreal value, bool reset)
+{
+ Q_Q(QQuickPopup);
+ qreal oldMargin = q->rightMargin();
+ rightMargin = value;
+ hasRightMargin = !reset;
+ if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
+ emit q->rightMarginChanged();
+ q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
+ QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin));
+ }
+}
+
+void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset)
+{
+ Q_Q(QQuickPopup);
+ qreal oldMargin = q->bottomMargin();
+ bottomMargin = value;
+ hasBottomMargin = !reset;
+ if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) {
+ emit q->bottomMarginChanged();
+ q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin),
+ QMarginsF(leftMargin, topMargin, rightMargin, oldMargin));
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty Object QtQuick.Controls::Popup::anchors.centerIn
+
+ Anchors provide a way to position an item by specifying its
+ relationship with other items.
+
+ A common use case is to center a popup within its parent. One way to do
+ this is with the \l[QtQuick]{Item::}{x} and \l[QtQuick]{Item::}{y} properties. Anchors offer
+ a more convenient approach:
+
+ \qml
+ Pane {
+ // ...
+
+ Popup {
+ anchors.centerIn: parent
+ }
+ }
+ \endqml
+
+ It is also possible to center the popup in the window by using \l Overlay:
+
+ \snippet qtquickcontrols2-popup.qml centerIn
+
+ This makes it easy to center a popup in the window from any component.
+
+ \note Popups can only be centered within their immediate parent or
+ the window overlay; trying to center in other items will produce a warning.
+
+ \sa {Popup Positioning}, {Item::}{anchors}, {Using Qt Quick Controls types
+ in property declarations}
+*/
+QQuickPopupAnchors *QQuickPopupPrivate::getAnchors()
+{
+ Q_Q(QQuickPopup);
+ if (!anchors)
+ anchors = new QQuickPopupAnchors(q);
+ return anchors;
+}
+
+QQuickPopupPositioner *QQuickPopupPrivate::getPositioner()
+{
+ Q_Q(QQuickPopup);
+ if (!positioner)
+ positioner = new QQuickPopupPositioner(q);
+ return positioner;
+}
+
+void QQuickPopupPrivate::setWindow(QQuickWindow *newWindow)
+{
+ Q_Q(QQuickPopup);
+ if (window == newWindow)
+ return;
+
+ if (window) {
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+ if (overlay)
+ QQuickOverlayPrivate::get(overlay)->removePopup(q);
+ }
+
+ window = newWindow;
+
+ if (newWindow) {
+ QQuickOverlay *overlay = QQuickOverlay::overlay(newWindow);
+ if (overlay)
+ QQuickOverlayPrivate::get(overlay)->addPopup(q);
+
+ QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem);
+ p->resolveFont();
+ if (QQuickApplicationWindow *appWindow = qobject_cast<QQuickApplicationWindow *>(newWindow))
+ p->updateLocale(appWindow->locale(), false); // explicit=false
+ }
+
+ emit q->windowChanged(newWindow);
+
+ if (complete && visible && window)
+ transitionManager.transitionEnter();
+}
+
+void QQuickPopupPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickPopup);
+ if (item == parentItem)
+ q->setParentItem(nullptr);
+}
+
+void QQuickPopupPrivate::reposition()
+{
+ getPositioner()->reposition();
+}
+
+QPalette QQuickPopupPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::System);
+}
+
+static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQuickItem *parent)
+{
+ QQuickItem *item = nullptr;
+ if (component) {
+ QQmlContext *creationContext = component->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(popup);
+ QQmlContext *context = new QQmlContext(creationContext, popup);
+ context->setContextObject(popup);
+ item = qobject_cast<QQuickItem*>(component->beginCreate(context));
+ }
+
+ // when there is no overlay component available (with plain QQuickWindow),
+ // use a plain QQuickItem as a fallback to block hover events
+ if (!item && popup->isModal())
+ item = new QQuickItem;
+
+ if (item) {
+ item->setOpacity(popup->isVisible() ? 1.0 : 0.0);
+ item->setParentItem(parent);
+ item->stackBefore(popup->popupItem());
+ item->setZ(popup->z());
+ // needed for the virtual keyboard to set a containment mask on the dimmer item
+ qCDebug(lcDimmer) << "dimmer" << item << "registered with" << parent;
+ parent->setProperty("_q_dimmerItem", QVariant::fromValue<QQuickItem*>(item));
+ if (popup->isModal()) {
+ item->setAcceptedMouseButtons(Qt::AllButtons);
+#if QT_CONFIG(cursor)
+ item->setCursor(Qt::ArrowCursor);
+#endif
+#if QT_CONFIG(quicktemplates2_hover)
+ // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
+ item->setAcceptHoverEvents(true);
+ // item->setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
+ // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, item, &QQuickItem::setAcceptHoverEvents);
+#endif
+ }
+ if (component)
+ component->completeCreate();
+ }
+ qCDebug(lcDimmer) << "finished creating dimmer from component" << component
+ << "for popup" << popup << "with parent" << parent << "- item is:" << item;
+ return item;
+}
+
+void QQuickPopupPrivate::createOverlay()
+{
+ Q_Q(QQuickPopup);
+ QQuickOverlay *overlay = QQuickOverlay::overlay(window);
+ if (!overlay)
+ return;
+
+ QQmlComponent *component = nullptr;
+ QQuickOverlayAttached *overlayAttached = qobject_cast<QQuickOverlayAttached *>(qmlAttachedPropertiesObject<QQuickOverlay>(q, false));
+ if (overlayAttached)
+ component = modal ? overlayAttached->modal() : overlayAttached->modeless();
+
+ if (!component)
+ component = modal ? overlay->modal() : overlay->modeless();
+
+ if (!dimmer)
+ dimmer = createDimmer(component, q, overlay);
+ resizeOverlay();
+}
+
+void QQuickPopupPrivate::destroyOverlay()
+{
+ if (dimmer) {
+ qCDebug(lcDimmer) << "destroying dimmer" << dimmer;
+ if (QObject *dimmerParentItem = dimmer->parentItem()) {
+ if (dimmerParentItem->property("_q_dimmerItem").value<QQuickItem*>() == dimmer)
+ dimmerParentItem->setProperty("_q_dimmerItem", QVariant());
+ }
+ dimmer->setParentItem(nullptr);
+ dimmer->deleteLater();
+ dimmer = nullptr;
+ }
+}
+
+void QQuickPopupPrivate::toggleOverlay()
+{
+ destroyOverlay();
+ if (dim)
+ createOverlay();
+}
+
+void QQuickPopupPrivate::showOverlay()
+{
+ // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
+ if (dim && dimmer)
+ QQmlProperty::write(dimmer, QStringLiteral("opacity"), 1.0);
+}
+
+void QQuickPopupPrivate::hideOverlay()
+{
+ // use QQmlProperty instead of QQuickItem::setOpacity() to trigger QML Behaviors
+ if (dim && dimmer)
+ QQmlProperty::write(dimmer, QStringLiteral("opacity"), 0.0);
+}
+
+void QQuickPopupPrivate::resizeOverlay()
+{
+ if (!dimmer)
+ return;
+
+ qreal w = window ? window->width() : 0;
+ qreal h = window ? window->height() : 0;
+ dimmer->setSize(QSizeF(w, h));
+}
+
+QQuickPopupTransitionManager::QQuickPopupTransitionManager(QQuickPopupPrivate *popup)
+ : popup(popup)
+{
+}
+
+void QQuickPopupTransitionManager::transitionEnter()
+{
+ if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
+ cancel();
+
+ if (!popup->prepareEnterTransition())
+ return;
+
+ if (popup->window)
+ transition(popup->enterActions, popup->enter, popup->q_func());
+ else
+ finished();
+}
+
+void QQuickPopupTransitionManager::transitionExit()
+{
+ if (!popup->prepareExitTransition())
+ return;
+
+ if (popup->window)
+ transition(popup->exitActions, popup->exit, popup->q_func());
+ else
+ finished();
+}
+
+void QQuickPopupTransitionManager::finished()
+{
+ if (popup->transitionState == QQuickPopupPrivate::EnterTransition)
+ popup->finalizeEnterTransition();
+ else if (popup->transitionState == QQuickPopupPrivate::ExitTransition)
+ popup->finalizeExitTransition();
+}
+
+QQuickPopup::QQuickPopup(QObject *parent)
+ : QObject(*(new QQuickPopupPrivate), parent)
+{
+ Q_D(QQuickPopup);
+ d->init();
+}
+
+QQuickPopup::QQuickPopup(QQuickPopupPrivate &dd, QObject *parent)
+ : QObject(dd, parent)
+{
+ Q_D(QQuickPopup);
+ d->init();
+}
+
+QQuickPopup::~QQuickPopup()
+{
+ Q_D(QQuickPopup);
+ setParentItem(nullptr);
+ d->popupItem->ungrabShortcut();
+
+ // If the popup is destroyed before the exit transition finishes,
+ // the necessary cleanup (removing modal dimmers that block mouse events,
+ // emitting closed signal, etc.) won't happen. That's why we do it manually here.
+ if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning())
+ d->finalizeExitTransition();
+
+ delete d->popupItem;
+ d->popupItem = nullptr;
+ delete d->positioner;
+ d->positioner = nullptr;
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Popup::open()
+
+ Opens the popup.
+
+ \sa visible
+*/
+void QQuickPopup::open()
+{
+ setVisible(true);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Popup::close()
+
+ Closes the popup.
+
+ \sa visible
+*/
+void QQuickPopup::close()
+{
+ setVisible(false);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::x
+
+ This property holds the x-coordinate of the popup.
+
+ \sa y, z
+*/
+qreal QQuickPopup::x() const
+{
+ Q_D(const QQuickPopup);
+ return d->effectiveX;
+}
+
+void QQuickPopup::setX(qreal x)
+{
+ Q_D(QQuickPopup);
+ setPosition(QPointF(x, d->y));
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::y
+
+ This property holds the y-coordinate of the popup.
+
+ \sa x, z
+*/
+qreal QQuickPopup::y() const
+{
+ Q_D(const QQuickPopup);
+ return d->effectiveY;
+}
+
+void QQuickPopup::setY(qreal y)
+{
+ Q_D(QQuickPopup);
+ setPosition(QPointF(d->x, y));
+}
+
+QPointF QQuickPopup::position() const
+{
+ Q_D(const QQuickPopup);
+ return QPointF(d->effectiveX, d->effectiveY);
+}
+
+void QQuickPopup::setPosition(const QPointF &pos)
+{
+ Q_D(QQuickPopup);
+ const bool xChange = !qFuzzyCompare(d->x, pos.x());
+ const bool yChange = !qFuzzyCompare(d->y, pos.y());
+ if (!xChange && !yChange)
+ return;
+
+ d->x = pos.x();
+ d->y = pos.y();
+ if (d->popupItem->isVisible()) {
+ d->reposition();
+ } else {
+ if (xChange)
+ emit xChanged();
+ if (yChange)
+ emit yChanged();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::z
+
+ This property holds the z-value of the popup. Z-value determines
+ the stacking order of popups.
+
+ If two visible popups have the same z-value, the last one that
+ was opened will be on top.
+
+ The default z-value is \c 0.
+
+ \sa x, y
+*/
+qreal QQuickPopup::z() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->z();
+}
+
+void QQuickPopup::setZ(qreal z)
+{
+ Q_D(QQuickPopup);
+ if (qFuzzyCompare(z, d->popupItem->z()))
+ return;
+ d->popupItem->setZ(z);
+ emit zChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::width
+
+ This property holds the width of the popup.
+*/
+qreal QQuickPopup::width() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->width();
+}
+
+void QQuickPopup::setWidth(qreal width)
+{
+ Q_D(QQuickPopup);
+ d->hasWidth = true;
+ d->popupItem->setWidth(width);
+}
+
+void QQuickPopup::resetWidth()
+{
+ Q_D(QQuickPopup);
+ if (!d->hasWidth)
+ return;
+
+ d->hasWidth = false;
+ d->popupItem->resetWidth();
+ if (d->popupItem->isVisible())
+ d->reposition();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::height
+
+ This property holds the height of the popup.
+*/
+qreal QQuickPopup::height() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->height();
+}
+
+void QQuickPopup::setHeight(qreal height)
+{
+ Q_D(QQuickPopup);
+ d->hasHeight = true;
+ d->popupItem->setHeight(height);
+}
+
+void QQuickPopup::resetHeight()
+{
+ Q_D(QQuickPopup);
+ if (!d->hasHeight)
+ return;
+
+ d->hasHeight = false;
+ d->popupItem->resetHeight();
+ if (d->popupItem->isVisible())
+ d->reposition();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::implicitWidth
+
+ This property holds the implicit width of the popup.
+*/
+qreal QQuickPopup::implicitWidth() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitWidth();
+}
+
+void QQuickPopup::setImplicitWidth(qreal width)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setImplicitWidth(width);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::implicitHeight
+
+ This property holds the implicit height of the popup.
+*/
+qreal QQuickPopup::implicitHeight() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitHeight();
+}
+
+void QQuickPopup::setImplicitHeight(qreal height)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setImplicitHeight(height);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::contentWidth
+
+ This property holds the content width. It is used for calculating the
+ total implicit width of the Popup.
+
+ For more information, see \l {Popup Sizing}.
+
+ \sa contentHeight
+*/
+qreal QQuickPopup::contentWidth() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->contentWidth();
+}
+
+void QQuickPopup::setContentWidth(qreal width)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setContentWidth(width);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::contentHeight
+
+ This property holds the content height. It is used for calculating the
+ total implicit height of the Popup.
+
+ For more information, see \l {Popup Sizing}.
+
+ \sa contentWidth
+*/
+qreal QQuickPopup::contentHeight() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->contentHeight();
+}
+
+void QQuickPopup::setContentHeight(qreal height)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setContentHeight(height);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::availableWidth
+ \readonly
+
+ This property holds the width available to the \l contentItem after
+ deducting horizontal padding from the \l {Item::}{width} of the popup.
+
+ \sa padding, leftPadding, rightPadding
+*/
+qreal QQuickPopup::availableWidth() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->availableWidth();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::availableHeight
+ \readonly
+
+ This property holds the height available to the \l contentItem after
+ deducting vertical padding from the \l {Item::}{height} of the popup.
+
+ \sa padding, topPadding, bottomPadding
+*/
+qreal QQuickPopup::availableHeight() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->availableHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty real QtQuick.Controls::Popup::spacing
+
+ This property holds the spacing.
+
+ Spacing is useful for popups that have multiple or repetitive building
+ blocks. For example, some styles use spacing to determine the distance
+ between the header, content, and footer of \l Dialog. Spacing is not
+ enforced by Popup, so each style may interpret it differently, and some
+ may ignore it altogether.
+*/
+qreal QQuickPopup::spacing() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->spacing();
+}
+
+void QQuickPopup::setSpacing(qreal spacing)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setSpacing(spacing);
+}
+
+void QQuickPopup::resetSpacing()
+{
+ setSpacing(0);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::margins
+
+ This property holds the distance between the edges of the popup and the
+ edges of its window.
+
+ A popup with negative margins is not pushed within the bounds
+ of the enclosing window. The default value is \c -1.
+
+ \sa topMargin, leftMargin, rightMargin, bottomMargin, {Popup Layout}
+*/
+qreal QQuickPopup::margins() const
+{
+ Q_D(const QQuickPopup);
+ return d->margins;
+}
+
+void QQuickPopup::setMargins(qreal margins)
+{
+ Q_D(QQuickPopup);
+ if (qFuzzyCompare(d->margins, margins))
+ return;
+ QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
+ d->margins = margins;
+ emit marginsChanged();
+ QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin());
+ if (!qFuzzyCompare(newMargins.top(), oldMargins.top()))
+ emit topMarginChanged();
+ if (!qFuzzyCompare(newMargins.left(), oldMargins.left()))
+ emit leftMarginChanged();
+ if (!qFuzzyCompare(newMargins.right(), oldMargins.right()))
+ emit rightMarginChanged();
+ if (!qFuzzyCompare(newMargins.bottom(), oldMargins.bottom()))
+ emit bottomMarginChanged();
+ marginsChange(newMargins, oldMargins);
+}
+
+void QQuickPopup::resetMargins()
+{
+ setMargins(-1);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::topMargin
+
+ This property holds the distance between the top edge of the popup and
+ the top edge of its window.
+
+ A popup with a negative top margin is not pushed within the top edge
+ of the enclosing window. The default value is \c -1.
+
+ \sa margins, bottomMargin, {Popup Layout}
+*/
+qreal QQuickPopup::topMargin() const
+{
+ Q_D(const QQuickPopup);
+ if (d->hasTopMargin)
+ return d->topMargin;
+ return d->margins;
+}
+
+void QQuickPopup::setTopMargin(qreal margin)
+{
+ Q_D(QQuickPopup);
+ d->setTopMargin(margin);
+}
+
+void QQuickPopup::resetTopMargin()
+{
+ Q_D(QQuickPopup);
+ d->setTopMargin(-1, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::leftMargin
+
+ This property holds the distance between the left edge of the popup and
+ the left edge of its window.
+
+ A popup with a negative left margin is not pushed within the left edge
+ of the enclosing window. The default value is \c -1.
+
+ \sa margins, rightMargin, {Popup Layout}
+*/
+qreal QQuickPopup::leftMargin() const
+{
+ Q_D(const QQuickPopup);
+ if (d->hasLeftMargin)
+ return d->leftMargin;
+ return d->margins;
+}
+
+void QQuickPopup::setLeftMargin(qreal margin)
+{
+ Q_D(QQuickPopup);
+ d->setLeftMargin(margin);
+}
+
+void QQuickPopup::resetLeftMargin()
+{
+ Q_D(QQuickPopup);
+ d->setLeftMargin(-1, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::rightMargin
+
+ This property holds the distance between the right edge of the popup and
+ the right edge of its window.
+
+ A popup with a negative right margin is not pushed within the right edge
+ of the enclosing window. The default value is \c -1.
+
+ \sa margins, leftMargin, {Popup Layout}
+*/
+qreal QQuickPopup::rightMargin() const
+{
+ Q_D(const QQuickPopup);
+ if (d->hasRightMargin)
+ return d->rightMargin;
+ return d->margins;
+}
+
+void QQuickPopup::setRightMargin(qreal margin)
+{
+ Q_D(QQuickPopup);
+ d->setRightMargin(margin);
+}
+
+void QQuickPopup::resetRightMargin()
+{
+ Q_D(QQuickPopup);
+ d->setRightMargin(-1, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::bottomMargin
+
+ This property holds the distance between the bottom edge of the popup and
+ the bottom edge of its window.
+
+ A popup with a negative bottom margin is not pushed within the bottom edge
+ of the enclosing window. The default value is \c -1.
+
+ \sa margins, topMargin, {Popup Layout}
+*/
+qreal QQuickPopup::bottomMargin() const
+{
+ Q_D(const QQuickPopup);
+ if (d->hasBottomMargin)
+ return d->bottomMargin;
+ return d->margins;
+}
+
+void QQuickPopup::setBottomMargin(qreal margin)
+{
+ Q_D(QQuickPopup);
+ d->setBottomMargin(margin);
+}
+
+void QQuickPopup::resetBottomMargin()
+{
+ Q_D(QQuickPopup);
+ d->setBottomMargin(-1, true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::padding
+
+ This property holds the default padding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa availableWidth, availableHeight, topPadding, leftPadding, rightPadding, bottomPadding
+*/
+qreal QQuickPopup::padding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->padding();
+}
+
+void QQuickPopup::setPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setPadding(padding);
+}
+
+void QQuickPopup::resetPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetPadding();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::topPadding
+
+ This property holds the top padding. Unless explicitly set, the value
+ is equal to \c verticalPadding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, bottomPadding, verticalPadding, availableHeight
+*/
+qreal QQuickPopup::topPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->topPadding();
+}
+
+void QQuickPopup::setTopPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setTopPadding(padding);
+}
+
+void QQuickPopup::resetTopPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetTopPadding();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::leftPadding
+
+ This property holds the left padding. Unless explicitly set, the value
+ is equal to \c horizontalPadding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, rightPadding, horizontalPadding, availableWidth
+*/
+qreal QQuickPopup::leftPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->leftPadding();
+}
+
+void QQuickPopup::setLeftPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setLeftPadding(padding);
+}
+
+void QQuickPopup::resetLeftPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetLeftPadding();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::rightPadding
+
+ This property holds the right padding. Unless explicitly set, the value
+ is equal to \c horizontalPadding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, leftPadding, horizontalPadding, availableWidth
+*/
+qreal QQuickPopup::rightPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->rightPadding();
+}
+
+void QQuickPopup::setRightPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setRightPadding(padding);
+}
+
+void QQuickPopup::resetRightPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetRightPadding();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::bottomPadding
+
+ This property holds the bottom padding. Unless explicitly set, the value
+ is equal to \c verticalPadding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, topPadding, verticalPadding, availableHeight
+*/
+qreal QQuickPopup::bottomPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->bottomPadding();
+}
+
+void QQuickPopup::setBottomPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setBottomPadding(padding);
+}
+
+void QQuickPopup::resetBottomPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetBottomPadding();
+}
+
+/*!
+ \qmlproperty Locale QtQuick.Controls::Popup::locale
+
+ This property holds the locale of the popup.
+
+ \sa mirrored, {LayoutMirroring}{LayoutMirroring}
+*/
+QLocale QQuickPopup::locale() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->locale();
+}
+
+void QQuickPopup::setLocale(const QLocale &locale)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setLocale(locale);
+}
+
+void QQuickPopup::resetLocale()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetLocale();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Popup::mirrored
+ \readonly
+
+ This property holds whether the popup is mirrored.
+
+ This property is provided for convenience. A popup is considered mirrored
+ when its visual layout direction is right-to-left; that is, when using a
+ right-to-left locale.
+
+ \sa locale, {Right-to-left User Interfaces}
+*/
+bool QQuickPopup::isMirrored() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->isMirrored();
+}
+
+/*!
+ \qmlproperty font QtQuick.Controls::Popup::font
+
+ This property holds the font currently set for the popup.
+
+ Popup propagates explicit font properties to its children. If you change a specific
+ property on a popup's font, that property propagates to all of the popup's children,
+ overriding any system defaults for that property.
+
+ \code
+ Popup {
+ font.family: "Courier"
+
+ Column {
+ Label {
+ text: qsTr("This will use Courier...")
+ }
+
+ Switch {
+ text: qsTr("... and so will this")
+ }
+ }
+ }
+ \endcode
+
+ \sa Control::font, ApplicationWindow::font
+*/
+QFont QQuickPopup::font() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->font();
+}
+
+void QQuickPopup::setFont(const QFont &font)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setFont(font);
+}
+
+void QQuickPopup::resetFont()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetFont();
+}
+
+QQuickWindow *QQuickPopup::window() const
+{
+ Q_D(const QQuickPopup);
+ return d->window;
+}
+
+QQuickItem *QQuickPopup::popupItem() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem;
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Popup::parent
+
+ This property holds the parent item.
+*/
+QQuickItem *QQuickPopup::parentItem() const
+{
+ Q_D(const QQuickPopup);
+ return d->parentItem;
+}
+
+void QQuickPopup::setParentItem(QQuickItem *parent)
+{
+ Q_D(QQuickPopup);
+ if (d->parentItem == parent)
+ return;
+
+ if (d->parentItem) {
+ QObjectPrivate::disconnect(d->parentItem, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow);
+ QQuickItemPrivate::get(d->parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Destroyed);
+ }
+ d->parentItem = parent;
+ QQuickPopupPositioner *positioner = d->getPositioner();
+ if (positioner->parentItem())
+ positioner->setParentItem(parent);
+ if (parent) {
+ QObjectPrivate::connect(parent, &QQuickItem::windowChanged, d, &QQuickPopupPrivate::setWindow);
+ QQuickItemPrivate::get(d->parentItem)->addItemChangeListener(d, QQuickItemPrivate::Destroyed);
+ } else {
+ close();
+ }
+ d->setWindow(parent ? parent->window() : nullptr);
+ emit parentChanged();
+}
+
+void QQuickPopup::resetParentItem()
+{
+ if (QQuickWindow *window = qobject_cast<QQuickWindow *>(parent()))
+ setParentItem(window->contentItem());
+ else
+ setParentItem(qobject_cast<QQuickItem *>(parent()));
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Popup::background
+
+ This property holds the background item.
+
+ \note If the background item has no explicit size specified, it automatically
+ follows the popup's size. In most cases, there is no need to specify
+ width or height for a background item.
+
+ \note Most popups use the implicit size of the background item to calculate
+ the implicit size of the popup itself. If you replace the background item
+ with a custom one, you should also consider providing a sensible implicit
+ size for it (unless it is an item like \l Image which has its own implicit
+ size).
+
+ \sa {Customizing Popup}
+*/
+QQuickItem *QQuickPopup::background() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->background();
+}
+
+void QQuickPopup::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setBackground(background);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Popup::contentItem
+
+ This property holds the content item of the popup.
+
+ The content item is the visual implementation of the popup. When the
+ popup is made visible, the content item is automatically reparented to
+ the \l {Overlay::overlay}{overlay item}.
+
+ \note The content item is automatically resized to fit within the
+ \l padding of the popup.
+
+ \note Most popups use the implicit size of the content item to calculate
+ the implicit size of the popup itself. If you replace the content item
+ with a custom one, you should also consider providing a sensible implicit
+ size for it (unless it is an item like \l Text which has its own implicit
+ size).
+
+ \sa {Customizing Popup}
+*/
+QQuickItem *QQuickPopup::contentItem() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->contentItem();
+}
+
+void QQuickPopup::setContentItem(QQuickItem *item)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setContentItem(item);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::Popup::contentData
+ \qmldefault
+
+ This property holds the list of content data.
+
+ The list contains all objects that have been declared in QML as children
+ of the popup.
+
+ \note Unlike \c contentChildren, \c contentData does include non-visual QML
+ objects.
+
+ \sa Item::data, contentChildren
+*/
+QQmlListProperty<QObject> QQuickPopupPrivate::contentData()
+{
+ QQuickControlPrivate *p = QQuickControlPrivate::get(popupItem);
+ if (!p->contentItem)
+ p->executeContentItem();
+ return QQmlListProperty<QObject>(popupItem->contentItem(), nullptr,
+ QQuickItemPrivate::data_append,
+ QQuickItemPrivate::data_count,
+ QQuickItemPrivate::data_at,
+ QQuickItemPrivate::data_clear);
+}
+
+/*!
+ \qmlproperty list<Item> QtQuick.Controls::Popup::contentChildren
+
+ This property holds the list of content children.
+
+ The list contains all items that have been declared in QML as children
+ of the popup.
+
+ \note Unlike \c contentData, \c contentChildren does not include non-visual
+ QML objects.
+
+ \sa Item::children, contentData
+*/
+QQmlListProperty<QQuickItem> QQuickPopupPrivate::contentChildren()
+{
+ return QQmlListProperty<QQuickItem>(popupItem->contentItem(), nullptr,
+ QQuickItemPrivate::children_append,
+ QQuickItemPrivate::children_count,
+ QQuickItemPrivate::children_at,
+ QQuickItemPrivate::children_clear);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::clip
+
+ This property holds whether clipping is enabled. The default value is \c false.
+*/
+bool QQuickPopup::clip() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->clip();
+}
+
+void QQuickPopup::setClip(bool clip)
+{
+ Q_D(QQuickPopup);
+ if (clip == d->popupItem->clip())
+ return;
+ d->popupItem->setClip(clip);
+ emit clipChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::focus
+
+ This property holds whether the popup wants focus.
+
+ When the popup actually receives focus, \l activeFocus will be \c true.
+ For more information, see \l {Keyboard Focus in Qt Quick}.
+
+ The default value is \c false.
+
+ \sa activeFocus
+*/
+bool QQuickPopup::hasFocus() const
+{
+ Q_D(const QQuickPopup);
+ return d->focus;
+}
+
+void QQuickPopup::setFocus(bool focus)
+{
+ Q_D(QQuickPopup);
+ if (d->focus == focus)
+ return;
+ d->focus = focus;
+ emit focusChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::activeFocus
+ \readonly
+
+ This property holds whether the popup has active focus.
+
+ \sa focus, {Keyboard Focus in Qt Quick}
+*/
+bool QQuickPopup::hasActiveFocus() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->hasActiveFocus();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::modal
+
+ This property holds whether the popup is modal.
+
+ Modal popups often have a distinctive background dimming effect defined
+ in \l {Overlay::modal}{Overlay.modal}, and do not allow press
+ or release events through to items beneath them. For example, if the user
+ accidentally clicks outside of a popup, any item beneath that popup at
+ the location of the click will not receive the event.
+
+ On desktop platforms, it is common for modal popups to be closed only when
+ the escape key is pressed. To achieve this behavior, set
+ \l closePolicy to \c Popup.CloseOnEscape. By default, \c closePolicy
+ is set to \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}, which
+ means that clicking outside of a modal popup will close it.
+
+ The default value is \c false.
+
+ \sa dim
+*/
+bool QQuickPopup::isModal() const
+{
+ Q_D(const QQuickPopup);
+ return d->modal;
+}
+
+void QQuickPopup::setModal(bool modal)
+{
+ Q_D(QQuickPopup);
+ if (d->modal == modal)
+ return;
+ d->modal = modal;
+ if (d->complete && d->visible)
+ d->toggleOverlay();
+ emit modalChanged();
+
+ QQuickItemPrivate::get(d->popupItem)->isTabFence = modal;
+
+ if (!d->hasDim) {
+ setDim(modal);
+ d->hasDim = false;
+ }
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::dim
+
+ This property holds whether the popup dims the background.
+
+ Unless explicitly set, this property follows the value of \l modal. To
+ return to the default value, set this property to \c undefined.
+
+ \sa modal, {Overlay::modeless}{Overlay.modeless}
+*/
+bool QQuickPopup::dim() const
+{
+ Q_D(const QQuickPopup);
+ return d->dim;
+}
+
+void QQuickPopup::setDim(bool dim)
+{
+ Q_D(QQuickPopup);
+ d->hasDim = true;
+
+ if (d->dim == dim)
+ return;
+
+ d->dim = dim;
+ if (d->complete && d->visible)
+ d->toggleOverlay();
+ emit dimChanged();
+}
+
+void QQuickPopup::resetDim()
+{
+ Q_D(QQuickPopup);
+ if (!d->hasDim)
+ return;
+
+ setDim(d->modal);
+ d->hasDim = false;
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Popup::visible
+
+ This property holds whether the popup is visible. The default value is \c false.
+
+ \sa open(), close(), opened
+*/
+bool QQuickPopup::isVisible() const
+{
+ Q_D(const QQuickPopup);
+ return d->visible && d->popupItem->isVisible();
+}
+
+void QQuickPopup::setVisible(bool visible)
+{
+ Q_D(QQuickPopup);
+ if (d->visible == visible && d->transitionState != QQuickPopupPrivate::ExitTransition)
+ return;
+
+ if (d->complete) {
+ if (visible)
+ d->transitionManager.transitionEnter();
+ else
+ d->transitionManager.transitionExit();
+ } else {
+ d->visible = visible;
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Popup::enabled
+
+ This property holds whether the popup is enabled. The default value is \c true.
+
+ \sa visible, Item::enabled
+*/
+bool QQuickPopup::isEnabled() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->isEnabled();
+}
+
+void QQuickPopup::setEnabled(bool enabled)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setEnabled(enabled);
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Popup::opened
+
+ This property holds whether the popup is fully open. The popup is considered opened
+ when it's visible and neither the \l enter nor \l exit transitions are running.
+
+ \sa open(), close(), visible
+*/
+bool QQuickPopup::isOpened() const
+{
+ Q_D(const QQuickPopup);
+ return d->transitionState == QQuickPopupPrivate::NoTransition && isVisible();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::opacity
+
+ This property holds the opacity of the popup. Opacity is specified as a number between
+ \c 0.0 (fully transparent) and \c 1.0 (fully opaque). The default value is \c 1.0.
+
+ \sa visible
+*/
+qreal QQuickPopup::opacity() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->opacity();
+}
+
+void QQuickPopup::setOpacity(qreal opacity)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setOpacity(opacity);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Popup::scale
+
+ This property holds the scale factor of the popup. The default value is \c 1.0.
+
+ A scale of less than \c 1.0 causes the popup to be rendered at a smaller size,
+ and a scale greater than \c 1.0 renders the popup at a larger size. Negative
+ scales are not supported.
+*/
+qreal QQuickPopup::scale() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->scale();
+}
+
+void QQuickPopup::setScale(qreal scale)
+{
+ Q_D(QQuickPopup);
+ if (qFuzzyCompare(scale, d->popupItem->scale()))
+ return;
+ d->popupItem->setScale(scale);
+ emit scaleChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Popup::closePolicy
+
+ This property determines the circumstances under which the popup closes.
+ The flags can be combined to allow several ways of closing the popup.
+
+ The available values are:
+ \value Popup.NoAutoClose The popup will only close when manually instructed to do so.
+ \value Popup.CloseOnPressOutside The popup will close when the mouse is pressed outside of it.
+ \value Popup.CloseOnPressOutsideParent The popup will close when the mouse is pressed outside of its parent.
+ \value Popup.CloseOnReleaseOutside The popup will close when the mouse is released outside of it.
+ \value Popup.CloseOnReleaseOutsideParent The popup will close when the mouse is released outside of its parent.
+ \value Popup.CloseOnEscape The popup will close when the escape key is pressed while the popup
+ has active focus.
+
+ The \c {CloseOnPress*} and \c {CloseOnRelease*} policies only apply for events
+ outside of popups. That is, if there are two popups open and the first has
+ \c Popup.CloseOnPressOutside as its policy, clicking on the second popup will
+ not result in the first closing.
+
+ The default value is \c {Popup.CloseOnEscape | Popup.CloseOnPressOutside}.
+ This default value may interfere with existing shortcuts in the application
+ that makes use of the \e Escape key.
+
+ \note There is a known limitation that the \c Popup.CloseOnReleaseOutside
+ and \c Popup.CloseOnReleaseOutsideParent policies only work with
+ \l modal popups.
+*/
+QQuickPopup::ClosePolicy QQuickPopup::closePolicy() const
+{
+ Q_D(const QQuickPopup);
+ return d->closePolicy;
+}
+
+void QQuickPopup::setClosePolicy(ClosePolicy policy)
+{
+ Q_D(QQuickPopup);
+ d->hasClosePolicy = true;
+ if (d->closePolicy == policy)
+ return;
+ d->closePolicy = policy;
+ if (isVisible()) {
+ if (policy & QQuickPopup::CloseOnEscape)
+ d->popupItem->grabShortcut();
+ else
+ d->popupItem->ungrabShortcut();
+ }
+ emit closePolicyChanged();
+}
+
+void QQuickPopup::resetClosePolicy()
+{
+ Q_D(QQuickPopup);
+ setClosePolicy(QQuickPopupPrivate::DefaultClosePolicy);
+ d->hasClosePolicy = false;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Popup::transformOrigin
+
+ This property holds the origin point for transformations in enter and exit transitions.
+
+ Nine transform origins are available, as shown in the image below.
+ The default transform origin is \c Popup.Center.
+
+ \image qtquickcontrols2-popup-transformorigin.png
+
+ \sa enter, exit, Item::transformOrigin
+*/
+QQuickPopup::TransformOrigin QQuickPopup::transformOrigin() const
+{
+ Q_D(const QQuickPopup);
+ return static_cast<TransformOrigin>(d->popupItem->transformOrigin());
+}
+
+void QQuickPopup::setTransformOrigin(TransformOrigin origin)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setTransformOrigin(static_cast<QQuickItem::TransformOrigin>(origin));
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::Popup::enter
+
+ This property holds the transition that is applied to the popup item
+ when the popup is opened and enters the screen.
+
+ The following example animates the opacity of the popup when it enters
+ the screen:
+ \code
+ Popup {
+ enter: Transition {
+ NumberAnimation { property: "opacity"; from: 0.0; to: 1.0 }
+ }
+ }
+ \endcode
+
+ \sa exit
+*/
+QQuickTransition *QQuickPopup::enter() const
+{
+ Q_D(const QQuickPopup);
+ return d->enter;
+}
+
+void QQuickPopup::setEnter(QQuickTransition *transition)
+{
+ Q_D(QQuickPopup);
+ if (d->enter == transition)
+ return;
+ d->enter = transition;
+ emit enterChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::Popup::exit
+
+ This property holds the transition that is applied to the popup item
+ when the popup is closed and exits the screen.
+
+ The following example animates the opacity of the popup when it exits
+ the screen:
+ \code
+ Popup {
+ exit: Transition {
+ NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
+ }
+ }
+ \endcode
+
+ \sa enter
+*/
+QQuickTransition *QQuickPopup::exit() const
+{
+ Q_D(const QQuickPopup);
+ return d->exit;
+}
+
+void QQuickPopup::setExit(QQuickTransition *transition)
+{
+ Q_D(QQuickPopup);
+ if (d->exit == transition)
+ return;
+ d->exit = transition;
+ emit exitChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::horizontalPadding
+
+ This property holds the horizontal padding. Unless explicitly set, the value
+ is equal to \c padding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, leftPadding, rightPadding, verticalPadding
+*/
+qreal QQuickPopup::horizontalPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->horizontalPadding();
+}
+
+void QQuickPopup::setHorizontalPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setHorizontalPadding(padding);
+}
+
+void QQuickPopup::resetHorizontalPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetHorizontalPadding();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::verticalPadding
+
+ This property holds the vertical padding. Unless explicitly set, the value
+ is equal to \c padding.
+
+ \include qquickpopup-padding.qdocinc
+
+ \sa padding, topPadding, bottomPadding, horizontalPadding
+*/
+qreal QQuickPopup::verticalPadding() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->verticalPadding();
+}
+
+void QQuickPopup::setVerticalPadding(qreal padding)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setVerticalPadding(padding);
+}
+
+void QQuickPopup::resetVerticalPadding()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetVerticalPadding();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::implicitContentWidth
+ \readonly
+
+ This property holds the implicit content width.
+
+ The value is calculated based on the content children.
+
+ \sa implicitContentHeight, implicitBackgroundWidth
+*/
+qreal QQuickPopup::implicitContentWidth() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitContentWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::implicitContentHeight
+ \readonly
+
+ This property holds the implicit content height.
+
+ The value is calculated based on the content children.
+
+ \sa implicitContentWidth, implicitBackgroundHeight
+*/
+qreal QQuickPopup::implicitContentHeight() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitContentHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundWidth
+ \readonly
+
+ This property holds the implicit background width.
+
+ The value is equal to \c {background ? background.implicitWidth : 0}.
+
+ \sa implicitBackgroundHeight, implicitContentWidth
+*/
+qreal QQuickPopup::implicitBackgroundWidth() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitBackgroundWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::implicitBackgroundHeight
+ \readonly
+
+ This property holds the implicit background height.
+
+ The value is equal to \c {background ? background.implicitHeight : 0}.
+
+ \sa implicitBackgroundWidth, implicitContentHeight
+*/
+qreal QQuickPopup::implicitBackgroundHeight() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->implicitBackgroundHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::topInset
+
+ This property holds the top inset for the background.
+
+ \sa {Popup Layout}, bottomInset
+*/
+qreal QQuickPopup::topInset() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->topInset();
+}
+
+void QQuickPopup::setTopInset(qreal inset)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setTopInset(inset);
+}
+
+void QQuickPopup::resetTopInset()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetTopInset();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::leftInset
+
+ This property holds the left inset for the background.
+
+ \sa {Popup Layout}, rightInset
+*/
+qreal QQuickPopup::leftInset() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->leftInset();
+}
+
+void QQuickPopup::setLeftInset(qreal inset)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setLeftInset(inset);
+}
+
+void QQuickPopup::resetLeftInset()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetLeftInset();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::rightInset
+
+ This property holds the right inset for the background.
+
+ \sa {Popup Layout}, leftInset
+*/
+qreal QQuickPopup::rightInset() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->rightInset();
+}
+
+void QQuickPopup::setRightInset(qreal inset)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setRightInset(inset);
+}
+
+void QQuickPopup::resetRightInset()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetRightInset();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Popup::bottomInset
+
+ This property holds the bottom inset for the background.
+
+ \sa {Popup Layout}, topInset
+*/
+qreal QQuickPopup::bottomInset() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->bottomInset();
+}
+
+void QQuickPopup::setBottomInset(qreal inset)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setBottomInset(inset);
+}
+
+void QQuickPopup::resetBottomInset()
+{
+ Q_D(QQuickPopup);
+ d->popupItem->resetBottomInset();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty palette QtQuick.Controls::Popup::palette
+
+ This property holds the palette currently set for the popup.
+
+ Popup propagates explicit palette properties to its children. If you change a specific
+ property on a popup's palette, that property propagates to all of the popup's children,
+ overriding any system defaults for that property.
+
+ \code
+ Popup {
+ palette.text: "red"
+
+ Column {
+ Label {
+ text: qsTr("This will use red color...")
+ }
+
+ Switch {
+ text: qsTr("... and so will this")
+ }
+ }
+ }
+ \endcode
+
+ \sa Item::palette, Window::palette, ColorGroup, Palette
+*/
+
+bool QQuickPopup::filtersChildMouseEvents() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->filtersChildMouseEvents();
+}
+
+void QQuickPopup::setFiltersChildMouseEvents(bool filter)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->setFiltersChildMouseEvents(filter);
+}
+
+/*!
+ \qmlmethod QtQuick.Controls::Popup::forceActiveFocus(enumeration reason = Qt.OtherFocusReason)
+
+ Forces active focus on the popup with the given \a reason.
+
+ This method sets focus on the popup and ensures that all ancestor
+ \l FocusScope objects in the object hierarchy are also given \l focus.
+
+ \sa activeFocus, Qt::FocusReason
+*/
+void QQuickPopup::forceActiveFocus(Qt::FocusReason reason)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->forceActiveFocus(reason);
+}
+
+void QQuickPopup::classBegin()
+{
+ Q_D(QQuickPopup);
+ d->complete = false;
+ QQmlContext *context = qmlContext(this);
+ if (context)
+ QQmlEngine::setContextForObject(d->popupItem, context);
+ d->popupItem->classBegin();
+}
+
+void QQuickPopup::componentComplete()
+{
+ Q_D(QQuickPopup);
+ qCDebug(lcPopup) << "componentComplete" << this;
+ if (!parentItem())
+ resetParentItem();
+
+ if (d->visible && d->window)
+ d->transitionManager.transitionEnter();
+
+ d->complete = true;
+ d->popupItem->componentComplete();
+
+ if (isVisible()) {
+ if (d->closePolicy & QQuickPopup::CloseOnEscape)
+ d->popupItem->grabShortcut();
+ else
+ d->popupItem->ungrabShortcut();
+ }
+}
+
+bool QQuickPopup::isComponentComplete() const
+{
+ Q_D(const QQuickPopup);
+ return d->complete;
+}
+
+bool QQuickPopup::childMouseEventFilter(QQuickItem *child, QEvent *event)
+{
+ Q_UNUSED(child);
+ Q_UNUSED(event);
+ return false;
+}
+
+void QQuickPopup::focusInEvent(QFocusEvent *event)
+{
+ event->accept();
+}
+
+void QQuickPopup::focusOutEvent(QFocusEvent *event)
+{
+ event->accept();
+}
+
+void QQuickPopup::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickPopup);
+ event->accept();
+
+ if (hasActiveFocus() && (event->key() == Qt::Key_Tab || event->key() == Qt::Key_Backtab))
+ QQuickItemPrivate::focusNextPrev(d->popupItem, event->key() == Qt::Key_Tab);
+}
+
+void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
+{
+ event->accept();
+}
+
+void QQuickPopup::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopup);
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
+}
+
+void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopup);
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
+}
+
+void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopup);
+ event->setAccepted(d->handleMouseEvent(d->popupItem, event));
+}
+
+void QQuickPopup::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ event->accept();
+}
+
+void QQuickPopup::mouseUngrabEvent()
+{
+ Q_D(QQuickPopup);
+ d->handleUngrab();
+}
+
+bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
+{
+ Q_D(QQuickPopup);
+ switch (event->type()) {
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ case QEvent::MouseMove:
+ case QEvent::Wheel:
+ if (d->modal)
+ event->accept();
+ return d->modal;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event));
+#endif
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ case QEvent::HoverLeave:
+ return d->handleHoverEvent(item, static_cast<QHoverEvent *>(event));
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event));
+
+ default:
+ return false;
+ }
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickPopup::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickPopup);
+ d->handleTouchEvent(d->popupItem, event);
+}
+
+void QQuickPopup::touchUngrabEvent()
+{
+ Q_D(QQuickPopup);
+ d->handleUngrab();
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickPopup::wheelEvent(QWheelEvent *event)
+{
+ event->accept();
+}
+#endif
+
+void QQuickPopup::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_UNUSED(newItem);
+ Q_UNUSED(oldItem);
+}
+
+void QQuickPopup::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
+{
+ qCDebug(lcPopup) << "contentSizeChange called on" << this << "with newSize" << newSize << "oldSize" << oldSize;
+ if (!qFuzzyCompare(newSize.width(), oldSize.width()))
+ emit contentWidthChanged();
+ if (!qFuzzyCompare(newSize.height(), oldSize.height()))
+ emit contentHeightChanged();
+}
+
+void QQuickPopup::fontChange(const QFont &newFont, const QFont &oldFont)
+{
+ Q_UNUSED(newFont);
+ Q_UNUSED(oldFont);
+ emit fontChanged();
+}
+
+void QQuickPopup::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickPopup);
+ qCDebug(lcPopup) << "geometryChange called on" << this << "with newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
+ d->reposition();
+ if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
+ emit widthChanged();
+ emit availableWidthChanged();
+ }
+ if (!qFuzzyCompare(newGeometry.height(), oldGeometry.height())) {
+ emit heightChanged();
+ emit availableHeightChanged();
+ }
+}
+
+void QQuickPopup::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ Q_D(QQuickPopup);
+
+ switch (change) {
+ case QQuickItem::ItemActiveFocusHasChanged:
+ emit activeFocusChanged();
+ break;
+ case QQuickItem::ItemOpacityHasChanged:
+ emit opacityChanged();
+ break;
+ case QQuickItem::ItemVisibleHasChanged:
+ if (isComponentComplete() && d->closePolicy & CloseOnEscape) {
+ if (data.boolValue)
+ d->popupItem->grabShortcut();
+ else
+ d->popupItem->ungrabShortcut();
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickPopup::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
+{
+ Q_UNUSED(newLocale);
+ Q_UNUSED(oldLocale);
+ emit localeChanged();
+}
+
+void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins)
+{
+ Q_D(QQuickPopup);
+ Q_UNUSED(newMargins);
+ Q_UNUSED(oldMargins);
+ d->reposition();
+}
+
+void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
+{
+ const bool tp = !qFuzzyCompare(newPadding.top(), oldPadding.top());
+ const bool lp = !qFuzzyCompare(newPadding.left(), oldPadding.left());
+ const bool rp = !qFuzzyCompare(newPadding.right(), oldPadding.right());
+ const bool bp = !qFuzzyCompare(newPadding.bottom(), oldPadding.bottom());
+
+ if (tp)
+ emit topPaddingChanged();
+ if (lp)
+ emit leftPaddingChanged();
+ if (rp)
+ emit rightPaddingChanged();
+ if (bp)
+ emit bottomPaddingChanged();
+
+ if (lp || rp) {
+ emit horizontalPaddingChanged();
+ emit availableWidthChanged();
+ }
+ if (tp || bp) {
+ emit verticalPaddingChanged();
+ emit availableHeightChanged();
+ }
+}
+
+void QQuickPopup::spacingChange(qreal newSpacing, qreal oldSpacing)
+{
+ Q_UNUSED(newSpacing);
+ Q_UNUSED(oldSpacing);
+ emit spacingChanged();
+}
+
+void QQuickPopup::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
+{
+ if (!qFuzzyCompare(newInset.top(), oldInset.top()))
+ emit topInsetChanged();
+ if (!qFuzzyCompare(newInset.left(), oldInset.left()))
+ emit leftInsetChanged();
+ if (!qFuzzyCompare(newInset.right(), oldInset.right()))
+ emit rightInsetChanged();
+ if (!qFuzzyCompare(newInset.bottom(), oldInset.bottom()))
+ emit bottomInsetChanged();
+}
+
+QFont QQuickPopup::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::System);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickPopup::accessibleRole() const
+{
+ return QAccessible::Dialog;
+}
+
+void QQuickPopup::accessibilityActiveChanged(bool active)
+{
+ Q_UNUSED(active);
+}
+#endif
+
+QString QQuickPopup::accessibleName() const
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->accessibleName();
+}
+
+void QQuickPopup::maybeSetAccessibleName(const QString &name)
+{
+ Q_D(QQuickPopup);
+ d->popupItem->maybeSetAccessibleName(name);
+}
+
+QVariant QQuickPopup::accessibleProperty(const char *propertyName)
+{
+ Q_D(const QQuickPopup);
+ return d->popupItem->accessibleProperty(propertyName);
+}
+
+bool QQuickPopup::setAccessibleProperty(const char *propertyName, const QVariant &value)
+{
+ Q_D(QQuickPopup);
+ return d->popupItem->setAccessibleProperty(propertyName, value);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpopup_p.cpp"
diff --git a/src/quicktemplates2/qquickpopup_p.h b/src/quicktemplates2/qquickpopup_p.h
new file mode 100644
index 0000000000..cdbc3cc4be
--- /dev/null
+++ b/src/quicktemplates2/qquickpopup_p.h
@@ -0,0 +1,478 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUP_P_H
+#define QQUICKPOPUP_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/qmargins.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qlocale.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtQml/qqml.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/qqmlparserstatus.h>
+#include <QtQuick/qquickitem.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQuickWindow;
+class QQuickPopupAnchors;
+class QQuickPopupPrivate;
+class QQuickTransition;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopup : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(qreal x READ x WRITE setX NOTIFY xChanged FINAL)
+ Q_PROPERTY(qreal y READ y WRITE setY NOTIFY yChanged FINAL)
+ Q_PROPERTY(qreal z READ z WRITE setZ NOTIFY zChanged FINAL)
+ Q_PROPERTY(qreal width READ width WRITE setWidth RESET resetWidth NOTIFY widthChanged FINAL)
+ Q_PROPERTY(qreal height READ height WRITE setHeight RESET resetHeight NOTIFY heightChanged FINAL)
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged FINAL)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged FINAL)
+ Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged FINAL)
+ Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged FINAL)
+ Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL)
+ Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL)
+ Q_PROPERTY(qreal margins READ margins WRITE setMargins RESET resetMargins NOTIFY marginsChanged FINAL)
+ Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged FINAL)
+ Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged FINAL)
+ Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL)
+ Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged FINAL)
+ Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL)
+ Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL)
+ Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL)
+ Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL)
+ Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL)
+ Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL)
+ Q_PROPERTY(QQuickItem *parent READ parentItem WRITE setParentItem RESET resetParentItem NOTIFY parentChanged FINAL)
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QQuickItem *contentItem READ contentItem WRITE setContentItem NOTIFY contentItemChanged FINAL)
+ Q_PRIVATE_PROPERTY(QQuickPopup::d_func(), QQmlListProperty<QObject> contentData READ contentData)
+ Q_PRIVATE_PROPERTY(QQuickPopup::d_func(), QQmlListProperty<QQuickItem> contentChildren READ contentChildren NOTIFY contentChildrenChanged FINAL)
+ Q_PROPERTY(bool clip READ clip WRITE setClip NOTIFY clipChanged FINAL)
+ Q_PROPERTY(bool focus READ hasFocus WRITE setFocus NOTIFY focusChanged FINAL)
+ Q_PROPERTY(bool activeFocus READ hasActiveFocus NOTIFY activeFocusChanged FINAL)
+ Q_PROPERTY(bool modal READ isModal WRITE setModal NOTIFY modalChanged FINAL)
+ Q_PROPERTY(bool dim READ dim WRITE setDim RESET resetDim NOTIFY dimChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity NOTIFY opacityChanged FINAL)
+ Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged FINAL)
+ Q_PROPERTY(ClosePolicy closePolicy READ closePolicy WRITE setClosePolicy RESET resetClosePolicy NOTIFY closePolicyChanged FINAL)
+ Q_PROPERTY(TransformOrigin transformOrigin READ transformOrigin WRITE setTransformOrigin FINAL)
+ Q_PROPERTY(QQuickTransition *enter READ enter WRITE setEnter NOTIFY enterChanged FINAL)
+ Q_PROPERTY(QQuickTransition *exit READ exit WRITE setExit NOTIFY exitChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing RESET resetSpacing NOTIFY spacingChanged FINAL REVISION(2, 1))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool opened READ isOpened NOTIFY openedChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool mirrored READ isMirrored NOTIFY mirroredChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL REVISION(2, 3))
+ Q_PRIVATE_PROPERTY(QQuickPopup::d_func(), QQuickPalette *palette READ palette WRITE setPalette RESET resetPalette NOTIFY paletteChanged REVISION(2, 3))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal horizontalPadding READ horizontalPadding WRITE setHorizontalPadding RESET resetHorizontalPadding NOTIFY horizontalPaddingChanged FINAL)
+ Q_PROPERTY(qreal verticalPadding READ verticalPadding WRITE setVerticalPadding RESET resetVerticalPadding NOTIFY verticalPaddingChanged FINAL)
+ Q_PRIVATE_PROPERTY(QQuickPopup::d_func(), QQuickPopupAnchors *anchors READ getAnchors DESIGNABLE false CONSTANT FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitContentWidth READ implicitContentWidth NOTIFY implicitContentWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitContentHeight READ implicitContentHeight NOTIFY implicitContentHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundWidth READ implicitBackgroundWidth NOTIFY implicitBackgroundWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundHeight READ implicitBackgroundHeight NOTIFY implicitBackgroundHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal topInset READ topInset WRITE setTopInset RESET resetTopInset NOTIFY topInsetChanged FINAL REVISION(2, 5))
+ 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_CLASSINFO("DeferredPropertyNames", "background,contentItem")
+ Q_CLASSINFO("DefaultProperty", "contentData")
+ QML_NAMED_ELEMENT(Popup)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickPopup(QObject *parent = nullptr);
+ ~QQuickPopup();
+
+ qreal x() const;
+ void setX(qreal x);
+
+ qreal y() const;
+ void setY(qreal y);
+
+ QPointF position() const;
+ void setPosition(const QPointF &pos);
+
+ qreal z() const;
+ void setZ(qreal z);
+
+ qreal width() const;
+ void setWidth(qreal width);
+ void resetWidth();
+
+ qreal height() const;
+ void setHeight(qreal height);
+ void resetHeight();
+
+ qreal implicitWidth() const;
+ void setImplicitWidth(qreal width);
+
+ qreal implicitHeight() const;
+ void setImplicitHeight(qreal height);
+
+ qreal contentWidth() const;
+ void setContentWidth(qreal width);
+
+ qreal contentHeight() const;
+ void setContentHeight(qreal height);
+
+ qreal availableWidth() const;
+ qreal availableHeight() const;
+
+ qreal margins() const;
+ void setMargins(qreal margins);
+ void resetMargins();
+
+ qreal topMargin() const;
+ void setTopMargin(qreal margin);
+ void resetTopMargin();
+
+ qreal leftMargin() const;
+ void setLeftMargin(qreal margin);
+ void resetLeftMargin();
+
+ qreal rightMargin() const;
+ void setRightMargin(qreal margin);
+ void resetRightMargin();
+
+ qreal bottomMargin() const;
+ void setBottomMargin(qreal margin);
+ void resetBottomMargin();
+
+ qreal padding() const;
+ void setPadding(qreal padding);
+ void resetPadding();
+
+ qreal topPadding() const;
+ void setTopPadding(qreal padding);
+ void resetTopPadding();
+
+ qreal leftPadding() const;
+ void setLeftPadding(qreal padding);
+ void resetLeftPadding();
+
+ qreal rightPadding() const;
+ void setRightPadding(qreal padding);
+ void resetRightPadding();
+
+ qreal bottomPadding() const;
+ void setBottomPadding(qreal padding);
+ void resetBottomPadding();
+
+ QLocale locale() const;
+ void setLocale(const QLocale &locale);
+ void resetLocale();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+ void resetFont();
+
+ QQuickWindow *window() const;
+ QQuickItem *popupItem() const;
+
+ QQuickItem *parentItem() const;
+ void setParentItem(QQuickItem *parent);
+ void resetParentItem();
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ QQuickItem *contentItem() const;
+ void setContentItem(QQuickItem *item);
+
+ bool clip() const;
+ void setClip(bool clip);
+
+ bool hasFocus() const;
+ void setFocus(bool focus);
+
+ bool hasActiveFocus() const;
+
+ bool isModal() const;
+ void setModal(bool modal);
+
+ bool dim() const;
+ void setDim(bool dim);
+ void resetDim();
+
+ bool isVisible() const;
+ virtual void setVisible(bool visible);
+
+ qreal opacity() const;
+ void setOpacity(qreal opacity);
+
+ qreal scale() const;
+ void setScale(qreal scale);
+
+ enum ClosePolicyFlag {
+ NoAutoClose = 0x00,
+ CloseOnPressOutside = 0x01,
+ CloseOnPressOutsideParent = 0x02,
+ CloseOnReleaseOutside = 0x04,
+ CloseOnReleaseOutsideParent = 0x08,
+ CloseOnEscape = 0x10
+ };
+ Q_DECLARE_FLAGS(ClosePolicy, ClosePolicyFlag)
+ Q_FLAG(ClosePolicy)
+
+ ClosePolicy closePolicy() const;
+ void setClosePolicy(ClosePolicy policy);
+ void resetClosePolicy();
+
+ // keep in sync with Item.TransformOrigin
+ enum TransformOrigin {
+ TopLeft, Top, TopRight,
+ Left, Center, Right,
+ BottomLeft, Bottom, BottomRight
+ };
+ Q_ENUM(TransformOrigin)
+
+ TransformOrigin transformOrigin() const;
+ void setTransformOrigin(TransformOrigin);
+
+ QQuickTransition *enter() const;
+ void setEnter(QQuickTransition *transition);
+
+ QQuickTransition *exit() const;
+ void setExit(QQuickTransition *transition);
+
+ bool filtersChildMouseEvents() const;
+ void setFiltersChildMouseEvents(bool filter);
+
+ Q_INVOKABLE void forceActiveFocus(Qt::FocusReason reason = Qt::OtherFocusReason);
+
+ // 2.1 (Qt 5.8)
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+ void resetSpacing();
+
+ // 2.3 (Qt 5.10)
+ bool isOpened() const;
+ bool isMirrored() const;
+
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ // 2.5 (Qt 5.12)
+ qreal horizontalPadding() const;
+ void setHorizontalPadding(qreal padding);
+ void resetHorizontalPadding();
+
+ qreal verticalPadding() const;
+ void setVerticalPadding(qreal padding);
+ void resetVerticalPadding();
+
+ qreal implicitContentWidth() const;
+ qreal implicitContentHeight() const;
+
+ qreal implicitBackgroundWidth() const;
+ qreal implicitBackgroundHeight() const;
+
+ qreal topInset() const;
+ void setTopInset(qreal inset);
+ void resetTopInset();
+
+ qreal leftInset() const;
+ void setLeftInset(qreal inset);
+ void resetLeftInset();
+
+ qreal rightInset() const;
+ void setRightInset(qreal inset);
+ void resetRightInset();
+
+ qreal bottomInset() const;
+ void setBottomInset(qreal inset);
+ void resetBottomInset();
+
+public Q_SLOTS:
+ void open();
+ void close();
+
+Q_SIGNALS:
+ void opened();
+ void closed();
+ void aboutToShow();
+ void aboutToHide();
+ void xChanged();
+ void yChanged();
+ void zChanged();
+ void widthChanged();
+ void heightChanged();
+ void implicitWidthChanged();
+ void implicitHeightChanged();
+ void contentWidthChanged();
+ void contentHeightChanged();
+ void availableWidthChanged();
+ void availableHeightChanged();
+ void marginsChanged();
+ void topMarginChanged();
+ void leftMarginChanged();
+ void rightMarginChanged();
+ void bottomMarginChanged();
+ void paddingChanged();
+ void topPaddingChanged();
+ void leftPaddingChanged();
+ void rightPaddingChanged();
+ void bottomPaddingChanged();
+ void fontChanged();
+ void localeChanged();
+ void parentChanged();
+ void backgroundChanged();
+ void contentItemChanged();
+ void contentChildrenChanged();
+ void clipChanged();
+ void focusChanged();
+ void activeFocusChanged();
+ void modalChanged();
+ void dimChanged();
+ void visibleChanged();
+ void opacityChanged();
+ void scaleChanged();
+ void closePolicyChanged();
+ void enterChanged();
+ void exitChanged();
+ void windowChanged(QQuickWindow *window);
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void spacingChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void openedChanged();
+ Q_REVISION(2, 3) void mirroredChanged();
+ Q_REVISION(2, 3) void enabledChanged();
+ Q_REVISION(2, 3) void paletteChanged();
+ Q_REVISION(2, 3) void paletteCreated();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void horizontalPaddingChanged();
+ Q_REVISION(2, 5) void verticalPaddingChanged();
+ Q_REVISION(2, 5) void implicitContentWidthChanged();
+ Q_REVISION(2, 5) void implicitContentHeightChanged();
+ Q_REVISION(2, 5) void implicitBackgroundWidthChanged();
+ Q_REVISION(2, 5) void implicitBackgroundHeightChanged();
+ Q_REVISION(2, 5) void topInsetChanged();
+ Q_REVISION(2, 5) void leftInsetChanged();
+ Q_REVISION(2, 5) void rightInsetChanged();
+ Q_REVISION(2, 5) void bottomInsetChanged();
+
+protected:
+ QQuickPopup(QQuickPopupPrivate &dd, QObject *parent);
+
+ void classBegin() override;
+ void componentComplete() override;
+ bool isComponentComplete() const;
+
+ virtual bool childMouseEventFilter(QQuickItem *child, QEvent *event);
+ virtual void focusInEvent(QFocusEvent *event);
+ virtual void focusOutEvent(QFocusEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void mousePressEvent(QMouseEvent *event);
+ virtual void mouseMoveEvent(QMouseEvent *event);
+ virtual void mouseReleaseEvent(QMouseEvent *event);
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+ virtual void mouseUngrabEvent();
+ virtual bool overlayEvent(QQuickItem *item, QEvent *event);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ virtual void touchEvent(QTouchEvent *event);
+ virtual void touchUngrabEvent();
+#endif
+#if QT_CONFIG(wheelevent)
+ virtual void wheelEvent(QWheelEvent *event);
+#endif
+
+ virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem);
+ virtual void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize);
+ virtual void fontChange(const QFont &newFont, const QFont &oldFont);
+ virtual void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry);
+ virtual void localeChange(const QLocale &newLocale, const QLocale &oldLocale);
+ virtual void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data);
+ virtual void marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins);
+ virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding);
+ virtual void spacingChange(qreal newSpacing, qreal oldSpacing);
+ virtual void insetChange(const QMarginsF &newInset, const QMarginsF &oldInset);
+
+ virtual QFont defaultFont() const;
+
+#if QT_CONFIG(accessibility)
+ virtual QAccessible::Role accessibleRole() const;
+ virtual void accessibilityActiveChanged(bool active);
+#endif
+
+ QString accessibleName() const;
+ void maybeSetAccessibleName(const QString &name);
+
+ QVariant accessibleProperty(const char *propertyName);
+ bool setAccessibleProperty(const char *propertyName, const QVariant &value);
+
+private:
+ Q_DISABLE_COPY(QQuickPopup)
+ Q_DECLARE_PRIVATE(QQuickPopup)
+ friend class QQuickPopupItem;
+ friend class QQuickOverlay;
+ friend class QQuickOverlayPrivate;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickPopup::ClosePolicy)
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPopup)
+
+#endif // QQUICKPOPUP_P_H
diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h
new file mode 100644
index 0000000000..82aa6308ed
--- /dev/null
+++ b/src/quicktemplates2/qquickpopup_p_p.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUP_P_P_H
+#define QQUICKPOPUP_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 <QtQuickTemplates2/private/qquickpopup_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#include <QtCore/private/qobject_p.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuick/private/qquicktransitionmanager_p_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTransition;
+class QQuickTransitionManager;
+class QQuickPopup;
+class QQuickPopupAnchors;
+class QQuickPopupItem;
+class QQuickPopupPrivate;
+class QQuickPopupPositioner;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupTransitionManager : public QQuickTransitionManager
+{
+public:
+ QQuickPopupTransitionManager(QQuickPopupPrivate *popup);
+
+ void transitionEnter();
+ void transitionExit();
+
+protected:
+ void finished() override;
+
+private:
+ QQuickPopupPrivate *popup = nullptr;
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupPrivate
+ : public QObjectPrivate
+ , public QQuickItemChangeListener
+ , public QQuickPaletteProviderPrivateBase<QQuickPopup, QQuickPopupPrivate>
+{
+ Q_DECLARE_PUBLIC(QQuickPopup)
+
+public:
+ QQuickPopupPrivate();
+
+ static QQuickPopupPrivate *get(QQuickPopup *popup)
+ {
+ return popup->d_func();
+ }
+
+ QQmlListProperty<QObject> contentData();
+ QQmlListProperty<QQuickItem> contentChildren();
+
+ void init();
+ void closeOrReject();
+ bool tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags);
+
+ bool contains(const QPointF &scenePos) const;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ virtual bool acceptTouch(const QTouchEvent::TouchPoint &point);
+#endif
+ virtual bool blockInput(QQuickItem *item, const QPointF &point) const;
+
+ 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 void handleUngrab();
+
+ bool handleMouseEvent(QQuickItem *item, QMouseEvent *event);
+ bool handleHoverEvent(QQuickItem *item, QHoverEvent *event);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ bool handleTouchEvent(QQuickItem *item, QTouchEvent *event);
+#endif
+
+ void reposition();
+
+ void createOverlay();
+ void destroyOverlay();
+ void toggleOverlay();
+ virtual void showOverlay();
+ virtual void hideOverlay();
+ virtual void resizeOverlay();
+
+ virtual bool prepareEnterTransition();
+ virtual bool prepareExitTransition();
+ virtual void finalizeEnterTransition();
+ virtual void finalizeExitTransition();
+
+ virtual void opened();
+
+ QMarginsF getMargins() const;
+
+ void setTopMargin(qreal value, bool reset = false);
+ void setLeftMargin(qreal value, bool reset = false);
+ void setRightMargin(qreal value, bool reset = false);
+ void setBottomMargin(qreal value, bool reset = false);
+
+ QQuickPopupAnchors *getAnchors();
+ virtual QQuickPopupPositioner *getPositioner();
+
+ void setWindow(QQuickWindow *window);
+ void itemDestroyed(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override;
+
+ enum TransitionState {
+ NoTransition, EnterTransition, ExitTransition
+ };
+
+ static const QQuickPopup::ClosePolicy DefaultClosePolicy;
+
+ bool focus = false;
+ bool modal = false;
+ bool dim = false;
+ bool hasDim = false;
+ bool visible = false;
+ bool complete = true;
+ bool positioning = false;
+ bool hasWidth = false;
+ bool hasHeight = false;
+ bool hasTopMargin = false;
+ bool hasLeftMargin = false;
+ bool hasRightMargin = false;
+ bool hasBottomMargin = false;
+ bool allowVerticalFlip = false;
+ bool allowHorizontalFlip = false;
+ bool allowVerticalMove = true;
+ bool allowHorizontalMove = true;
+ bool allowVerticalResize = true;
+ bool allowHorizontalResize = true;
+ bool hadActiveFocusBeforeExitTransition = false;
+ bool interactive = true;
+ bool hasClosePolicy = false;
+ bool outsidePressed = false;
+ bool outsideParentPressed = false;
+ int touchId = -1;
+ qreal x = 0;
+ qreal y = 0;
+ qreal effectiveX = 0;
+ qreal effectiveY = 0;
+ qreal margins = -1;
+ qreal topMargin = 0;
+ qreal leftMargin = 0;
+ qreal rightMargin = 0;
+ qreal bottomMargin = 0;
+ QPointF pressPoint;
+ TransitionState transitionState = NoTransition;
+ QQuickPopup::ClosePolicy closePolicy = DefaultClosePolicy;
+ QQuickItem *parentItem = nullptr;
+ QQuickItem *dimmer = nullptr;
+ QPointer<QQuickWindow> window;
+ QQuickTransition *enter = nullptr;
+ QQuickTransition *exit = nullptr;
+ QQuickPopupItem *popupItem = nullptr;
+ QQuickPopupPositioner *positioner = nullptr;
+ QList<QQuickStateAction> enterActions;
+ QList<QQuickStateAction> exitActions;
+ QQuickPopupTransitionManager transitionManager;
+ QQuickPopupAnchors *anchors = nullptr;
+ qreal prevOpacity = 0;
+ qreal prevScale = 0;
+
+ friend class QQuickPopupTransitionManager;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUP_P_P_H
diff --git a/src/quicktemplates2/qquickpopupanchors.cpp b/src/quicktemplates2/qquickpopupanchors.cpp
new file mode 100644
index 0000000000..0d286cc01a
--- /dev/null
+++ b/src/quicktemplates2/qquickpopupanchors.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpopupanchors_p.h"
+#include "qquickpopupanchors_p_p.h"
+#include "qquickpopup_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QQuickPopupAnchors::QQuickPopupAnchors(QQuickPopup *popup)
+ : QObject(*(new QQuickPopupAnchorsPrivate), popup)
+{
+ Q_D(QQuickPopupAnchors);
+ d->popup = popup;
+}
+
+QQuickPopupAnchors::~QQuickPopupAnchors()
+{
+ Q_D(const QQuickPopupAnchors);
+ if (d->centerIn) {
+ auto centerInPrivate = QQuickItemPrivate::get(d->centerIn);
+ centerInPrivate->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ }
+}
+
+QQuickItem *QQuickPopupAnchors::centerIn() const
+{
+ Q_D(const QQuickPopupAnchors);
+ return d->centerIn;
+}
+
+void QQuickPopupAnchors::setCenterIn(QQuickItem *item)
+{
+ Q_D(QQuickPopupAnchors);
+ if (item == d->centerIn)
+ return;
+
+ if (d->centerIn) {
+ auto centerInPrivate = QQuickItemPrivate::get(d->centerIn);
+ centerInPrivate->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ }
+
+ d->centerIn = item;
+
+ if (d->centerIn) {
+ auto centerInPrivate = QQuickItemPrivate::get(d->centerIn);
+ centerInPrivate->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ }
+
+ QQuickPopupPrivate::get(d->popup)->reposition();
+
+ emit centerInChanged();
+}
+
+void QQuickPopupAnchors::resetCenterIn()
+{
+ setCenterIn(nullptr);
+}
+
+void QQuickPopupAnchors::itemDestroyed(QQuickItem *)
+{
+ resetCenterIn();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpopupanchors_p.cpp"
diff --git a/src/quicktemplates2/qquickpopupanchors_p.h b/src/quicktemplates2/qquickpopupanchors_p.h
new file mode 100644
index 0000000000..dce1c5b26a
--- /dev/null
+++ b/src/quicktemplates2/qquickpopupanchors_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUPANCHORS_P_H
+#define QQUICKPOPUPANCHORS_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 <QtQml/qqml.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickPopupAnchorsPrivate;
+class QQuickPopup;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupAnchors : public QObject, public QQuickItemChangeListener
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 5)
+
+public:
+ explicit QQuickPopupAnchors(QQuickPopup *popup);
+ ~QQuickPopupAnchors();
+
+ QQuickItem *centerIn() const;
+ void setCenterIn(QQuickItem *item);
+ void resetCenterIn();
+
+Q_SIGNALS:
+ void centerInChanged();
+
+private:
+ void itemDestroyed(QQuickItem *item) override;
+
+ Q_DISABLE_COPY(QQuickPopupAnchors)
+ Q_DECLARE_PRIVATE(QQuickPopupAnchors)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPopupAnchors)
+
+#endif // QQUICKPOPUPANCHORS_P_H
diff --git a/src/quicktemplates2/qquickpopupanchors_p_p.h b/src/quicktemplates2/qquickpopupanchors_p_p.h
new file mode 100644
index 0000000000..989dc6df8f
--- /dev/null
+++ b/src/quicktemplates2/qquickpopupanchors_p_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUPANCHORS_P_P_H
+#define QQUICKPOPUPANCHORS_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 <QtCore/private/qobject_p.h>
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickPopup;
+
+class QQuickPopupAnchorsPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPopupAnchors)
+
+public:
+ static QQuickPopupAnchorsPrivate *get(QQuickPopupAnchors *popupAnchors)
+ {
+ return popupAnchors->d_func();
+ }
+
+ QQuickPopup *popup = nullptr;
+ QQuickItem *centerIn = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUPANCHORS_P_P_H
diff --git a/src/quicktemplates2/qquickpopupitem.cpp b/src/quicktemplates2/qquickpopupitem.cpp
new file mode 100644
index 0000000000..4111cbef99
--- /dev/null
+++ b/src/quicktemplates2/qquickpopupitem.cpp
@@ -0,0 +1,433 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpopupitem_p_p.h"
+#include "qquickapplicationwindow_p.h"
+#include "qquickshortcutcontext_p_p.h"
+#include "qquickpage_p_p.h"
+#include "qquickcontentitem_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#if QT_CONFIG(shortcut)
+# include <QtGui/private/qshortcutmap_p.h>
+#endif
+#include <QtGui/private/qguiapplication_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPopupItem, "qt.quick.controls.popupitem")
+
+QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup)
+ : popup(popup)
+{
+ isTabFence = true;
+}
+
+void QQuickPopupItemPrivate::implicitWidthChanged()
+{
+ qCDebug(lcPopupItem).nospace() << "implicitWidthChanged called on " << q_func() << "; new implicitWidth is " << implicitWidth;
+ QQuickPagePrivate::implicitWidthChanged();
+ emit popup->implicitWidthChanged();
+}
+
+void QQuickPopupItemPrivate::implicitHeightChanged()
+{
+ qCDebug(lcPopupItem).nospace() << "implicitHeightChanged called on " << q_func() << "; new implicitHeight is " << implicitHeight;
+ QQuickPagePrivate::implicitHeightChanged();
+ emit popup->implicitHeightChanged();
+}
+
+void QQuickPopupItemPrivate::resolveFont()
+{
+ if (QQuickApplicationWindow *window = qobject_cast<QQuickApplicationWindow *>(popup->window()))
+ inheritFont(window->font());
+ else
+ inheritFont(QQuickTheme::font(QQuickTheme::System));
+}
+
+QQuickItem *QQuickPopupItemPrivate::getContentItem()
+{
+ Q_Q(QQuickPopupItem);
+ if (QQuickItem *item = QQuickPagePrivate::getContentItem())
+ return item;
+
+ return new QQuickContentItem(popup, q);
+}
+
+static inline QString contentItemName() { return QStringLiteral("contentItem"); }
+
+void QQuickPopupItemPrivate::cancelContentItem()
+{
+ quickCancelDeferred(popup, contentItemName());
+}
+
+void QQuickPopupItemPrivate::executeContentItem(bool complete)
+{
+ if (contentItem.wasExecuted())
+ return;
+
+ if (!contentItem || complete)
+ quickBeginDeferred(popup, contentItemName(), contentItem);
+ if (complete)
+ quickCompleteDeferred(popup, contentItemName(), contentItem);
+}
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickPopupItemPrivate::cancelBackground()
+{
+ quickCancelDeferred(popup, backgroundName());
+}
+
+void QQuickPopupItemPrivate::executeBackground(bool complete)
+{
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(popup, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(popup, backgroundName(), background);
+}
+
+QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup)
+ : QQuickPage(*(new QQuickPopupItemPrivate(popup)), nullptr)
+{
+ setParent(popup);
+ setFlag(ItemIsFocusScope);
+ setAcceptedMouseButtons(Qt::AllButtons);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+
+ connect(popup, &QQuickPopup::paletteChanged, this, &QQuickItem::paletteChanged);
+ connect(popup, &QQuickPopup::paletteCreated, this, &QQuickItem::paletteCreated);
+
+#if QT_CONFIG(quicktemplates2_hover)
+ // TODO: switch to QStyleHints::useHoverEffects in Qt 5.8
+ setHoverEnabled(true);
+ // setAcceptHoverEvents(QGuiApplication::styleHints()->useHoverEffects());
+ // connect(QGuiApplication::styleHints(), &QStyleHints::useHoverEffectsChanged, this, &QQuickItem::setAcceptHoverEvents);
+#endif
+}
+
+void QQuickPopupItem::grabShortcut()
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickPopupItem);
+ QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
+ if (!d->backId)
+ d->backId = pApp->shortcutMap.addShortcut(this, Qt::Key_Back, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+ if (!d->escapeId)
+ d->escapeId = pApp->shortcutMap.addShortcut(this, Qt::Key_Escape, Qt::WindowShortcut, QQuickShortcutContext::matcher);
+#endif
+}
+
+void QQuickPopupItem::ungrabShortcut()
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickPopupItem);
+ QGuiApplicationPrivate *pApp = QGuiApplicationPrivate::instance();
+ if (d->backId) {
+ pApp->shortcutMap.removeShortcut(d->backId, this);
+ d->backId = 0;
+ }
+ if (d->escapeId) {
+ pApp->shortcutMap.removeShortcut(d->escapeId, this);
+ d->escapeId = 0;
+ }
+#endif
+}
+
+QQuickPalette *QQuickPopupItemPrivate::palette() const
+{
+ return QQuickPopupPrivate::get(popup)->palette();
+}
+
+void QQuickPopupItemPrivate::setPalette(QQuickPalette *p)
+{
+ QQuickPopupPrivate::get(popup)->setPalette(p);
+}
+
+void QQuickPopupItemPrivate::resetPalette()
+{
+ QQuickPopupPrivate::get(popup)->resetPalette();
+}
+
+QPalette QQuickPopupItemPrivate::defaultPalette() const
+{
+ return QQuickPopupPrivate::get(popup)->defaultPalette();
+}
+
+bool QQuickPopupItemPrivate::providesPalette() const
+{
+ return QQuickPopupPrivate::get(popup)->providesPalette();
+}
+
+QPalette QQuickPopupItemPrivate::parentPalette() const
+{
+ return QQuickPopupPrivate::get(popup)->parentPalette();
+}
+
+void QQuickPopupItem::updatePolish()
+{
+ Q_D(QQuickPopupItem);
+ return QQuickPopupPrivate::get(d->popup)->reposition();
+}
+
+bool QQuickPopupItem::event(QEvent *event)
+{
+#if QT_CONFIG(shortcut)
+ Q_D(QQuickPopupItem);
+ if (event->type() == QEvent::Shortcut) {
+ QShortcutEvent *se = static_cast<QShortcutEvent *>(event);
+ if (se->shortcutId() == d->escapeId || se->shortcutId() == d->backId) {
+ QQuickPopupPrivate *p = QQuickPopupPrivate::get(d->popup);
+ if (p->interactive) {
+ p->closeOrReject();
+ return true;
+ }
+ }
+ }
+#endif
+ return QQuickItem::event(event);
+}
+
+bool QQuickPopupItem::childMouseEventFilter(QQuickItem *child, QEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ return d->popup->childMouseEventFilter(child, event);
+}
+
+void QQuickPopupItem::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->focusInEvent(event);
+}
+
+void QQuickPopupItem::focusOutEvent(QFocusEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->focusOutEvent(event);
+}
+
+void QQuickPopupItem::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->keyPressEvent(event);
+}
+
+void QQuickPopupItem::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->keyReleaseEvent(event);
+}
+
+void QQuickPopupItem::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->mousePressEvent(event);
+}
+
+void QQuickPopupItem::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->mouseMoveEvent(event);
+}
+
+void QQuickPopupItem::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->mouseReleaseEvent(event);
+}
+
+void QQuickPopupItem::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->mouseDoubleClickEvent(event);
+}
+
+void QQuickPopupItem::mouseUngrabEvent()
+{
+ Q_D(QQuickPopupItem);
+ d->popup->mouseUngrabEvent();
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickPopupItem::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->touchEvent(event);
+}
+
+void QQuickPopupItem::touchUngrabEvent()
+{
+ Q_D(QQuickPopupItem);
+ d->popup->touchUngrabEvent();
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickPopupItem::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickPopupItem);
+ d->popup->wheelEvent(event);
+}
+#endif
+
+void QQuickPopupItem::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickPopupItem);
+ QQuickPage::contentItemChange(newItem, oldItem);
+ d->popup->contentItemChange(newItem, oldItem);
+}
+
+void QQuickPopupItem::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
+{
+ Q_D(QQuickPopupItem);
+ qCDebug(lcPopupItem) << "contentSizeChange called on" << this << "newSize" << newSize << "oldSize" << oldSize;
+ QQuickPage::contentSizeChange(newSize, oldSize);
+ d->popup->contentSizeChange(newSize, oldSize);
+}
+
+void QQuickPopupItem::fontChange(const QFont &newFont, const QFont &oldFont)
+{
+ Q_D(QQuickPopupItem);
+ QQuickPage::fontChange(newFont, oldFont);
+ d->popup->fontChange(newFont, oldFont);
+}
+
+void QQuickPopupItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickPopupItem);
+ qCDebug(lcPopupItem) << "geometryChange called on" << this << "newGeometry" << newGeometry << "oldGeometry" << oldGeometry;
+ QQuickPage::geometryChange(newGeometry, oldGeometry);
+ d->popup->geometryChange(newGeometry, oldGeometry);
+}
+
+void QQuickPopupItem::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
+{
+ Q_D(QQuickPopupItem);
+ QQuickPage::localeChange(newLocale, oldLocale);
+ d->popup->localeChange(newLocale, oldLocale);
+}
+
+void QQuickPopupItem::mirrorChange()
+{
+ Q_D(QQuickPopupItem);
+ emit d->popup->mirroredChanged();
+}
+
+void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data)
+{
+ Q_D(QQuickPopupItem);
+ QQuickPage::itemChange(change, data);
+ d->popup->itemChange(change, data);
+}
+
+void QQuickPopupItem::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
+{
+ Q_D(QQuickPopupItem);
+ QQuickPage::paddingChange(newPadding, oldPadding);
+ d->popup->paddingChange(newPadding, oldPadding);
+}
+
+void QQuickPopupItem::enabledChange()
+{
+ Q_D(QQuickPopupItem);
+ // Just having QQuickPopup connect our QQuickItem::enabledChanged() signal
+ // to its enabledChanged() signal is enough for the enabled property to work,
+ // but we must also ensure that its paletteChanged() signal is emitted
+ // so that bindings to palette are re-evaluated, because QQuickControl::palette()
+ // returns a different palette depending on whether or not the control is enabled.
+ // To save a connection, we also emit enabledChanged here.
+ emit d->popup->enabledChanged();
+}
+
+QFont QQuickPopupItem::defaultFont() const
+{
+ Q_D(const QQuickPopupItem);
+ return d->popup->defaultFont();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickPopupItem::accessibleRole() const
+{
+ Q_D(const QQuickPopupItem);
+ return d->popup->accessibleRole();
+}
+
+void QQuickPopupItem::accessibilityActiveChanged(bool active)
+{
+ Q_D(const QQuickPopupItem);
+ // Can't just use d->popup->accessibleName() here, because that refers to the accessible
+ // name of us, the popup item, which is not what we want.
+ const QQuickAccessibleAttached *popupAccessibleAttached = QQuickControlPrivate::accessibleAttached(d->popup);
+ const QString oldPopupName = popupAccessibleAttached ? popupAccessibleAttached->name() : QString();
+ const bool wasNameExplicitlySetOnPopup = popupAccessibleAttached && popupAccessibleAttached->wasNameExplicitlySet();
+
+ QQuickPage::accessibilityActiveChanged(active);
+
+ QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this);
+ const QString ourName = accessibleAttached ? accessibleAttached->name() : QString();
+ if (wasNameExplicitlySetOnPopup && accessibleAttached && ourName != oldPopupName) {
+ // The user set Accessible.name on the Popup. Since the Popup and its popup item
+ // have different accessible attached properties, the popup item doesn't know that
+ // a name was set on the Popup by the user, and that it should use that, rather than
+ // whatever QQuickPage sets. That's why we need to do it here.
+ // To avoid it being overridden by the call to accessibilityActiveChanged() below,
+ // we set it explicitly. It's safe to do this as the popup item is an internal implementation detail.
+ accessibleAttached->setName(oldPopupName);
+ }
+
+ // This allows the different popup types to set a name on their popup item accordingly.
+ // For example: Dialog uses its title and ToolTip uses its text.
+ d->popup->accessibilityActiveChanged(active);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickpopupitem_p_p.cpp"
diff --git a/src/quicktemplates2/qquickpopupitem_p_p.h b/src/quicktemplates2/qquickpopupitem_p_p.h
new file mode 100644
index 0000000000..04486650a0
--- /dev/null
+++ b/src/quicktemplates2/qquickpopupitem_p_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUPITEM_P_P_H
+#define QQUICKPOPUPITEM_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 <QtQuickTemplates2/private/qquickpage_p.h>
+#include <QtQuickTemplates2/private/qquickpage_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPopup;
+class QQuickPopupItemPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupItem : public QQuickPage
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickPopupItem(QQuickPopup *popup);
+
+ void grabShortcut();
+ void ungrabShortcut();
+
+protected:
+ void updatePolish() override;
+
+ bool event(QEvent *event) override;
+ bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void mouseUngrabEvent() override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+ void touchUngrabEvent() override;
+#endif
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) override;
+ void fontChange(const QFont &newFont, const QFont &oldFont) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override;
+ void mirrorChange() override;
+ void itemChange(ItemChange change, const ItemChangeData &data) override;
+ void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override;
+ void enabledChange() override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickPopupItem)
+ Q_DECLARE_PRIVATE(QQuickPopupItem)
+ friend class QQuickPopup;
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupItemPrivate : public QQuickPagePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickPopupItem)
+
+public:
+ QQuickPopupItemPrivate(QQuickPopup *popup);
+
+ void implicitWidthChanged() override;
+ void implicitHeightChanged() override;
+
+ void resolveFont() override;
+
+ QQuickItem *getContentItem() override;
+
+ void cancelContentItem() override;
+ void executeContentItem(bool complete = false) override;
+
+ void cancelBackground() override;
+ void executeBackground(bool complete = false) override;
+
+ QQuickPalette *palette() const override;
+ void setPalette(QQuickPalette* p) override;
+ void resetPalette() override;
+
+ QPalette defaultPalette() const override;
+ bool providesPalette() const override;
+
+ QPalette parentPalette() const override;
+
+ int backId = 0;
+ int escapeId = 0;
+ QQuickPopup *popup = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUPITEM_P_P_H
diff --git a/src/quicktemplates2/qquickpopuppositioner.cpp b/src/quicktemplates2/qquickpopuppositioner.cpp
new file mode 100644
index 0000000000..bbdc3848cd
--- /dev/null
+++ b/src/quicktemplates2/qquickpopuppositioner.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickoverlay_p.h"
+#include "qquickpopuppositioner_p_p.h"
+#include "qquickpopupanchors_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickpopup_p_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcPopupPositioner, "qt.quick.controls.popuppositioner")
+
+static const QQuickItemPrivate::ChangeTypes AncestorChangeTypes = QQuickItemPrivate::Geometry
+ | QQuickItemPrivate::Parent
+ | QQuickItemPrivate::Children;
+
+static const QQuickItemPrivate::ChangeTypes ItemChangeTypes = QQuickItemPrivate::Geometry
+ | QQuickItemPrivate::Parent;
+
+QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopup *popup)
+ : m_popup(popup)
+{
+}
+
+QQuickPopupPositioner::~QQuickPopupPositioner()
+{
+ if (m_parentItem) {
+ QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes);
+ removeAncestorListeners(m_parentItem->parentItem());
+ }
+}
+
+QQuickPopup *QQuickPopupPositioner::popup() const
+{
+ return m_popup;
+}
+
+QQuickItem *QQuickPopupPositioner::parentItem() const
+{
+ return m_parentItem;
+}
+
+void QQuickPopupPositioner::setParentItem(QQuickItem *parent)
+{
+ if (m_parentItem == parent)
+ return;
+
+ if (m_parentItem) {
+ QQuickItemPrivate::get(m_parentItem)->removeItemChangeListener(this, ItemChangeTypes);
+ removeAncestorListeners(m_parentItem->parentItem());
+ }
+
+ m_parentItem = parent;
+
+ if (!parent)
+ return;
+
+ QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes);
+ addAncestorListeners(parent->parentItem());
+ // Store the scale property so the end result of any transition that could effect the scale
+ // does not influence the top left of the final popup, so it doesn't appear to flip from one
+ // position to another as a result
+ m_popupScale = m_popup->popupItem()->scale();
+ if (m_popup->popupItem()->isVisible())
+ QQuickPopupPrivate::get(m_popup)->reposition();
+}
+
+void QQuickPopupPositioner::reposition()
+{
+ QQuickItem *popupItem = m_popup->popupItem();
+ if (!popupItem->isVisible())
+ return;
+
+ if (m_positioning) {
+ popupItem->polish();
+ return;
+ }
+
+ qCDebug(lcPopupPositioner) << "reposition called for" << m_popup;
+
+ const qreal w = popupItem->width() * m_popupScale;
+ const qreal h = popupItem->height() * m_popupScale;
+ const qreal iw = popupItem->implicitWidth() * m_popupScale;
+ const qreal ih = popupItem->implicitHeight() * m_popupScale;
+
+ 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);
+ if (m_parentItem) {
+ // m_parentItem is the parent that the popup should open in,
+ // and popupItem()->parentItem() is the overlay, so the mapToItem() calls below
+ // effectively map the rect to scene coordinates.
+ if (centerInParent) {
+ if (centerInParent != parentItem() && !centerInOverlay) {
+ qmlWarning(m_popup) << "Popup can only be centered within its immediate parent or Overlay.overlay";
+ return;
+ }
+
+ if (centerInOverlay) {
+ rect.moveCenter(QPointF(qRound(centerInOverlay->width() / 2.0), qRound(centerInOverlay->height() / 2.0)));
+ } else {
+ const QPointF parentItemCenter = QPointF(qRound(m_parentItem->width() / 2), qRound(m_parentItem->height() / 2));
+ rect.moveCenter(m_parentItem->mapToItem(popupItem->parentItem(), parentItemCenter));
+ }
+ } else {
+ rect.moveTopLeft(m_parentItem->mapToItem(popupItem->parentItem(), rect.topLeft()));
+ }
+
+ if (p->window) {
+ const QMarginsF margins = p->getMargins();
+ QRectF bounds(qMax<qreal>(0.0, margins.left()),
+ qMax<qreal>(0.0, margins.top()),
+ p->window->width() - qMax<qreal>(0.0, margins.left()) - qMax<qreal>(0.0, margins.right()),
+ p->window->height() - qMax<qreal>(0.0, margins.top()) - qMax<qreal>(0.0, margins.bottom()));
+ if (p->window->contentOrientation() == Qt::LandscapeOrientation || p->window->contentOrientation() == Qt::InvertedLandscapeOrientation)
+ bounds = bounds.transposed();
+
+ // if the popup doesn't fit horizontally inside the window, try flipping it around (left <-> right)
+ if (p->allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
+ const QPointF newTopLeft(m_parentItem->width() - p->x - rect.width(), p->y);
+ const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
+ rect.size());
+ if (flipped.intersected(bounds).width() > rect.intersected(bounds).width())
+ rect.moveLeft(flipped.left());
+ }
+
+ // if the popup doesn't fit vertically inside the window, try flipping it around (above <-> below)
+ if (p->allowVerticalFlip && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) {
+ const QPointF newTopLeft(p->x, m_parentItem->height() - p->y - rect.height());
+ const QRectF flipped(m_parentItem->mapToItem(popupItem->parentItem(), newTopLeft),
+ rect.size());
+ if (flipped.intersected(bounds).height() > rect.intersected(bounds).height())
+ rect.moveTop(flipped.top());
+ }
+
+ // push inside the margins if specified
+ if (p->allowVerticalMove) {
+ if (margins.top() >= 0 && rect.top() < bounds.top())
+ rect.moveTop(margins.top());
+ if (margins.bottom() >= 0 && rect.bottom() > bounds.bottom())
+ rect.moveBottom(bounds.bottom());
+ }
+ if (p->allowHorizontalMove) {
+ if (margins.left() >= 0 && rect.left() < bounds.left())
+ rect.moveLeft(margins.left());
+ if (margins.right() >= 0 && rect.right() > bounds.right())
+ rect.moveRight(bounds.right());
+ }
+
+ if (iw > 0 && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
+ // neither the flipped or pushed geometry fits inside the window, choose
+ // whichever side (left vs. right) fits larger part of the popup
+ if (p->allowHorizontalMove && p->allowHorizontalFlip) {
+ if (rect.left() < bounds.left() && bounds.left() + rect.width() <= bounds.right())
+ rect.moveLeft(bounds.left());
+ else if (rect.right() > bounds.right() && bounds.right() - rect.width() >= bounds.left())
+ rect.moveRight(bounds.right());
+ }
+
+ // as a last resort, adjust the width to fit the window
+ if (p->allowHorizontalResize) {
+ if (rect.left() < bounds.left()) {
+ rect.setLeft(bounds.left());
+ widthAdjusted = true;
+ }
+ if (rect.right() > bounds.right()) {
+ rect.setRight(bounds.right());
+ widthAdjusted = true;
+ }
+ }
+ } else if (iw > 0 && rect.left() >= bounds.left() && rect.right() <= bounds.right()
+ && iw != w) {
+ // restore original width
+ rect.setWidth(iw);
+ widthAdjusted = true;
+ }
+
+ if (ih > 0 && (rect.top() < bounds.top() || rect.bottom() > bounds.bottom())) {
+ // neither the flipped or pushed geometry fits inside the window, choose
+ // whichever side (above vs. below) fits larger part of the popup
+ if (p->allowVerticalMove && p->allowVerticalFlip) {
+ if (rect.top() < bounds.top() && bounds.top() + rect.height() <= bounds.bottom())
+ rect.moveTop(bounds.top());
+ else if (rect.bottom() > bounds.bottom() && bounds.bottom() - rect.height() >= bounds.top())
+ rect.moveBottom(bounds.bottom());
+ }
+
+ // as a last resort, adjust the height to fit the window
+ if (p->allowVerticalResize) {
+ if (rect.top() < bounds.top()) {
+ rect.setTop(bounds.top());
+ heightAdjusted = true;
+ }
+ if (rect.bottom() > bounds.bottom()) {
+ rect.setBottom(bounds.bottom());
+ heightAdjusted = true;
+ }
+ }
+ } else if (ih > 0 && rect.top() >= bounds.top() && rect.bottom() <= bounds.bottom()
+ && ih != h) {
+ // restore original height
+ rect.setHeight(ih);
+ heightAdjusted = true;
+ }
+ }
+ }
+
+ m_positioning = true;
+
+ 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.
+ const QPointF effectivePos = m_parentItem && !centerInOverlay ? m_parentItem->mapFromScene(rect.topLeft()) : rect.topLeft();
+ if (!qFuzzyCompare(p->effectiveX, effectivePos.x())) {
+ p->effectiveX = effectivePos.x();
+ emit m_popup->xChanged();
+ }
+ if (!qFuzzyCompare(p->effectiveY, effectivePos.y())) {
+ p->effectiveY = effectivePos.y();
+ emit m_popup->yChanged();
+ }
+
+ if (!p->hasWidth && widthAdjusted && rect.width() > 0) {
+ popupItem->setWidth(rect.width() / m_popupScale);
+ // The popup doesn't have an explicit width, so we should respect that by not
+ // making our call above an explicit assignment. If we don't, the popup won't
+ // resize after being repositioned in some cases.
+ QQuickItemPrivate::get(popupItem)->widthValidFlag = false;
+ }
+ if (!p->hasHeight && heightAdjusted && rect.height() > 0) {
+ popupItem->setHeight(rect.height() / m_popupScale);
+ QQuickItemPrivate::get(popupItem)->heightValidFlag = false;
+ }
+ m_positioning = false;
+
+ qCDebug(lcPopupPositioner) << "- new popupItem geometry:"
+ << popupItem->x() << popupItem->y() << popupItem->width() << popupItem->height();
+}
+
+void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
+{
+ if (m_parentItem && m_popup->popupItem()->isVisible())
+ QQuickPopupPrivate::get(m_popup)->reposition();
+}
+
+void QQuickPopupPositioner::itemParentChanged(QQuickItem *, QQuickItem *parent)
+{
+ addAncestorListeners(parent);
+}
+
+void QQuickPopupPositioner::itemChildRemoved(QQuickItem *item, QQuickItem *child)
+{
+ if (child == m_parentItem || child->isAncestorOf(m_parentItem))
+ removeAncestorListeners(item);
+}
+
+void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item)
+{
+ if (item == m_parentItem)
+ return;
+
+ QQuickItem *p = item;
+ while (p) {
+ QQuickItemPrivate::get(p)->removeItemChangeListener(this, AncestorChangeTypes);
+ p = p->parentItem();
+ }
+}
+
+void QQuickPopupPositioner::addAncestorListeners(QQuickItem *item)
+{
+ if (item == m_parentItem)
+ return;
+
+ QQuickItem *p = item;
+ while (p) {
+ QQuickItemPrivate::get(p)->updateOrAddItemChangeListener(this, AncestorChangeTypes);
+ p = p->parentItem();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickpopuppositioner_p_p.h b/src/quicktemplates2/qquickpopuppositioner_p_p.h
new file mode 100644
index 0000000000..74bc467c61
--- /dev/null
+++ b/src/quicktemplates2/qquickpopuppositioner_p_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPOPUPPOSITIONER_P_P_H
+#define QQUICKPOPUPPOSITIONER_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/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QQuickPopup;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupPositioner : public QQuickItemChangeListener
+{
+public:
+ explicit QQuickPopupPositioner(QQuickPopup *popup);
+ ~QQuickPopupPositioner();
+
+ QQuickPopup *popup() const;
+
+ QQuickItem *parentItem() const;
+ void setParentItem(QQuickItem *parent);
+
+ virtual void reposition();
+
+protected:
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
+ void itemParentChanged(QQuickItem *, QQuickItem *parent) override;
+ void itemChildRemoved(QQuickItem *, QQuickItem *child) override;
+
+ void removeAncestorListeners(QQuickItem *item);
+ void addAncestorListeners(QQuickItem *item);
+
+ bool m_positioning = false;
+ QQuickItem *m_parentItem = nullptr;
+ QQuickPopup *m_popup = nullptr;
+ qreal m_popupScale = 1.0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPOPUPPOSITIONER_P_P_H
diff --git a/src/quicktemplates2/qquickpresshandler.cpp b/src/quicktemplates2/qquickpresshandler.cpp
new file mode 100644
index 0000000000..d9ed484be9
--- /dev/null
+++ b/src/quicktemplates2/qquickpresshandler.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpresshandler_p_p.h"
+
+#include <QtCore/private/qobject_p.h>
+#include <QtGui/qguiapplication.h>
+#include <QtGui/qstylehints.h>
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuickTemplates2/private/qquicktextarea_p.h>
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickPressHandler::mousePressEvent(QMouseEvent *event)
+{
+ longPress = false;
+ pressPos = event->position();
+ if (Qt::LeftButton == (event->buttons() & Qt::LeftButton)) {
+ timer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), control);
+ delayedMousePressEvent = new QMouseEvent(event->type(), event->position().toPoint(), event->button(), event->buttons(), event->modifiers());
+ } else {
+ timer.stop();
+ }
+
+ if (isSignalConnected(control, "pressed(QQuickMouseEvent*)", pressedSignalIndex)) {
+ QQuickMouseEvent mev;
+ mev.reset(pressPos.x(), pressPos.y(), event->button(), event->buttons(),
+ event->modifiers(), false/*isClick*/, false/*wasHeld*/);
+ mev.setAccepted(true);
+ QQuickMouseEvent *mevPtr = &mev;
+ void *args[] = { nullptr, &mevPtr };
+ QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressedSignalIndex, args);
+ event->setAccepted(mev.isAccepted());
+ }
+}
+
+void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event)
+{
+ if (qAbs(int(event->position().x() - pressPos.x())) > QGuiApplication::styleHints()->startDragDistance())
+ timer.stop();
+}
+
+void QQuickPressHandler::mouseReleaseEvent(QMouseEvent *event)
+{
+ if (!longPress) {
+ timer.stop();
+
+ if (isSignalConnected(control, "released(QQuickMouseEvent*)", releasedSignalIndex)) {
+ QQuickMouseEvent mev;
+ mev.reset(pressPos.x(), pressPos.y(), event->button(), event->buttons(),
+ event->modifiers(), false/*isClick*/, false/*wasHeld*/);
+ mev.setAccepted(true);
+ QQuickMouseEvent *mevPtr = &mev;
+ void *args[] = { nullptr, &mevPtr };
+ QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, releasedSignalIndex, args);
+ event->setAccepted(mev.isAccepted());
+ }
+ }
+}
+
+void QQuickPressHandler::timerEvent(QTimerEvent *)
+{
+ timer.stop();
+ clearDelayedMouseEvent();
+
+ longPress = isSignalConnected(control, "pressAndHold(QQuickMouseEvent*)", pressAndHoldSignalIndex);
+ if (longPress) {
+ QQuickMouseEvent mev;
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ mev.reset(pressPos.x(), pressPos.y(), Qt::LeftButton, Qt::LeftButton,
+ QGuiApplication::keyboardModifiers(), false/*isClick*/, true/*wasHeld*/);
+QT_WARNING_POP
+ mev.setAccepted(true);
+ // Use fast signal invocation since we already got its index
+ QQuickMouseEvent *mevPtr = &mev;
+ void *args[] = { nullptr, &mevPtr };
+ QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressAndHoldSignalIndex, args);
+ if (!mev.isAccepted())
+ longPress = false;
+ }
+}
+
+void QQuickPressHandler::clearDelayedMouseEvent()
+{
+ if (delayedMousePressEvent) {
+ delete delayedMousePressEvent;
+ delayedMousePressEvent = 0;
+ }
+}
+
+bool QQuickPressHandler::isActive()
+{
+ return !(timer.isActive() || longPress);
+}
+
+bool QQuickPressHandler::isSignalConnected(QQuickItem *item, const char *signalName, int &signalIndex)
+{
+ if (signalIndex == -1)
+ signalIndex = item->metaObject()->indexOfSignal(signalName);
+ Q_ASSERT(signalIndex != -1);
+ const auto signalMetaMethod = item->metaObject()->method(signalIndex);
+ if (QQuickTextArea *textArea = qobject_cast<QQuickTextArea*>(item)) {
+ return textArea->isSignalConnected(signalMetaMethod);
+ } else if (QQuickTextField *textField = qobject_cast<QQuickTextField*>(item)) {
+ return textField->isSignalConnected(signalMetaMethod);
+ }
+ qFatal("Unhandled control type for signal name: %s", signalName);
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickpresshandler_p_p.h b/src/quicktemplates2/qquickpresshandler_p_p.h
new file mode 100644
index 0000000000..19312cddf4
--- /dev/null
+++ b/src/quicktemplates2/qquickpresshandler_p_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPRESSHANDLER_P_P_H
+#define QQUICKPRESSHANDLER_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 <QtCore/qpoint.h>
+#include <QtCore/qbasictimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+class QMouseEvent;
+class QTimerEvent;
+
+struct QQuickPressHandler
+{
+ void mousePressEvent(QMouseEvent *event);
+ void mouseMoveEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
+ void timerEvent(QTimerEvent *event);
+
+ void clearDelayedMouseEvent();
+ bool isActive();
+
+ static bool isSignalConnected(QQuickItem *item, const char *signalName, int &signalIndex);
+
+ QQuickItem *control = nullptr;
+ QBasicTimer timer;
+ QPointF pressPos;
+ bool longPress = false;
+ int pressAndHoldSignalIndex = -1;
+ int pressedSignalIndex = -1;
+ int releasedSignalIndex = -1;
+ QMouseEvent *delayedMousePressEvent = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPRESSHANDLER_P_P_H
diff --git a/src/quicktemplates2/qquickprogressbar.cpp b/src/quicktemplates2/qquickprogressbar.cpp
new file mode 100644
index 0000000000..f4bc52b9be
--- /dev/null
+++ b/src/quicktemplates2/qquickprogressbar.cpp
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickprogressbar_p.h"
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ProgressBar
+ \inherits Control
+//! \instantiates QQuickProgressBar
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-indicators
+ \brief Indicates the progress of an operation.
+
+ \image qtquickcontrols2-progressbar.gif
+
+ ProgressBar indicates the progress of an operation. The value should be updated
+ regularly. The range is defined by \l from and \l to, which both can contain any value.
+
+ \code
+ ProgressBar {
+ value: 0.5
+ }
+ \endcode
+
+ ProgressBar also supports a special \l indeterminate mode, which is useful,
+ for example, when unable to determine the size of the item being downloaded,
+ or if the download progress gets interrupted due to a network disconnection.
+
+ \image qtquickcontrols2-progressbar-indeterminate.gif
+
+ \code
+ ProgressBar {
+ indeterminate: true
+ }
+ \endcode
+
+ The indeterminate mode is similar to a \l BusyIndicator. Both can be used
+ to indicate background activity. The main difference is visual, and that
+ ProgressBar can also present a concrete amount of progress (when it can be
+ determined). Due to the visual difference, indeterminate progress bars and
+ busy indicators fit different places in user interfaces. Typical places for
+ an indeterminate progress bar:
+ \list
+ \li at the bottom of a \l ToolBar
+ \li inline within the content of a \l Page
+ \li in an \l ItemDelegate to show the progress of a particular item
+ \endlist
+
+ \sa {Customizing ProgressBar}, BusyIndicator, {Indicator Controls}
+*/
+
+class QQuickProgressBarPrivate : public QQuickControlPrivate
+{
+public:
+ qreal from = 0;
+ qreal to = 1;
+ qreal value = 0;
+ bool indeterminate = false;
+};
+
+QQuickProgressBar::QQuickProgressBar(QQuickItem *parent)
+ : QQuickControl(*(new QQuickProgressBarPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ProgressBar::from
+
+ This property holds the starting value for the progress. The default value is \c 0.0.
+
+ \sa to, value
+*/
+qreal QQuickProgressBar::from() const
+{
+ Q_D(const QQuickProgressBar);
+ return d->from;
+}
+
+void QQuickProgressBar::setFrom(qreal from)
+{
+ Q_D(QQuickProgressBar);
+ if (qFuzzyCompare(d->from, from))
+ return;
+
+ d->from = from;
+ emit fromChanged();
+ emit positionChanged();
+ emit visualPositionChanged();
+ if (isComponentComplete())
+ setValue(d->value);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ProgressBar::to
+
+ This property holds the end value for the progress. The default value is \c 1.0.
+
+ \sa from, value
+*/
+qreal QQuickProgressBar::to() const
+{
+ Q_D(const QQuickProgressBar);
+ return d->to;
+}
+
+void QQuickProgressBar::setTo(qreal to)
+{
+ Q_D(QQuickProgressBar);
+ if (qFuzzyCompare(d->to, to))
+ return;
+
+ d->to = to;
+ emit toChanged();
+ emit positionChanged();
+ emit visualPositionChanged();
+ if (isComponentComplete())
+ setValue(d->value);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ProgressBar::value
+
+ This property holds the progress value. The default value is \c 0.0.
+
+ \sa from, to, position
+*/
+qreal QQuickProgressBar::value() const
+{
+ Q_D(const QQuickProgressBar);
+ return d->value;
+}
+
+void QQuickProgressBar::setValue(qreal value)
+{
+ Q_D(QQuickProgressBar);
+ if (isComponentComplete())
+ value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to);
+
+ if (qFuzzyCompare(d->value, value))
+ return;
+
+ d->value = value;
+ emit valueChanged();
+ emit positionChanged();
+ emit visualPositionChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ProgressBar::position
+ \readonly
+
+ This property holds the logical position of the progress.
+
+ The position is expressed as a fraction of the value, in the range
+ \c {0.0 - 1.0}. For visualizing the progress, the right-to-left
+ aware \l visualPosition should be used instead.
+
+ \sa value, visualPosition
+*/
+qreal QQuickProgressBar::position() const
+{
+ Q_D(const QQuickProgressBar);
+ if (qFuzzyCompare(d->from, d->to))
+ return 0;
+ return (d->value - d->from) / (d->to - d->from);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ProgressBar::visualPosition
+ \readonly
+
+ This property holds the visual position of the progress.
+
+ The position is expressed as a fraction of the value, in the range \c {0.0 - 1.0}.
+ When the control is \l {Control::mirrored}{mirrored}, \c visuaPosition is equal
+ to \c {1.0 - position}. This makes \c visualPosition suitable for visualizing
+ the progress, taking right-to-left support into account.
+
+ \sa position, value
+*/
+qreal QQuickProgressBar::visualPosition() const
+{
+ if (isMirrored())
+ return 1.0 - position();
+ return position();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ProgressBar::indeterminate
+
+ This property holds whether the progress bar is in indeterminate mode.
+ A progress bar in indeterminate mode displays that an operation is in progress, but it
+ doesn't show how much progress has been made.
+
+ \image qtquickcontrols2-progressbar-indeterminate.gif
+*/
+bool QQuickProgressBar::isIndeterminate() const
+{
+ Q_D(const QQuickProgressBar);
+ return d->indeterminate;
+}
+
+void QQuickProgressBar::setIndeterminate(bool indeterminate)
+{
+ Q_D(QQuickProgressBar);
+ if (d->indeterminate == indeterminate)
+ return;
+
+ d->indeterminate = indeterminate;
+ emit indeterminateChanged();
+}
+
+void QQuickProgressBar::mirrorChange()
+{
+ QQuickControl::mirrorChange();
+ if (!qFuzzyCompare(position(), qreal(0.5)))
+ emit visualPositionChanged();
+}
+
+void QQuickProgressBar::componentComplete()
+{
+ Q_D(QQuickProgressBar);
+ QQuickControl::componentComplete();
+ setValue(d->value);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickProgressBar::accessibleRole() const
+{
+ return QAccessible::ProgressBar;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickprogressbar_p.cpp"
diff --git a/src/quicktemplates2/qquickprogressbar_p.h b/src/quicktemplates2/qquickprogressbar_p.h
new file mode 100644
index 0000000000..8322670fcd
--- /dev/null
+++ b/src/quicktemplates2/qquickprogressbar_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPROGRESSBAR_P_H
+#define QQUICKPROGRESSBAR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickProgressBarPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickProgressBar : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
+ Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate NOTIFY indeterminateChanged FINAL)
+ QML_NAMED_ELEMENT(ProgressBar)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickProgressBar(QQuickItem *parent = nullptr);
+
+ qreal from() const;
+ void setFrom(qreal from);
+
+ qreal to() const;
+ void setTo(qreal to);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+ qreal position() const;
+ qreal visualPosition() const;
+
+ bool isIndeterminate() const;
+ void setIndeterminate(bool indeterminate);
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void valueChanged();
+ void positionChanged();
+ void visualPositionChanged();
+ void indeterminateChanged();
+
+protected:
+ void mirrorChange() override;
+ void componentComplete() override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickProgressBar)
+ Q_DECLARE_PRIVATE(QQuickProgressBar)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickProgressBar)
+
+#endif // QQUICKPROGRESSBAR_P_H
diff --git a/src/quicktemplates2/qquickradiobutton.cpp b/src/quicktemplates2/qquickradiobutton.cpp
new file mode 100644
index 0000000000..3f1262e03a
--- /dev/null
+++ b/src/quicktemplates2/qquickradiobutton.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickradiobutton_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickabstractbutton_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RadioButton
+ \inherits AbstractButton
+//! \instantiates QQuickRadioButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Exclusive radio button that can be toggled on or off.
+
+ \image qtquickcontrols2-radiobutton.gif
+
+ RadioButton presents an option button that can be toggled on (checked) or
+ off (unchecked). Radio buttons are typically used to select one option
+ from a set of options.
+
+ RadioButton inherits its API from \l AbstractButton. For instance,
+ you can set \l {AbstractButton::text}{text} and react to
+ \l {AbstractButton::clicked}{clicks} using the AbstractButton API.
+ The state of the radio button can be set with the
+ \l {AbstractButton::}{checked} property.
+
+ Radio buttons are \l {AbstractButton::autoExclusive}{auto-exclusive}
+ by default. Only one button can be checked at any time amongst radio
+ buttons that belong to the same parent item; checking another button
+ automatically unchecks the previously checked one. For radio buttons
+ that do not share a common parent, ButtonGroup can be used to manage
+ exclusivity.
+
+ \l RadioDelegate is similar to RadioButton, except that it is typically
+ used in views.
+
+ \code
+ ColumnLayout {
+ RadioButton {
+ checked: true
+ text: qsTr("First")
+ }
+ RadioButton {
+ text: qsTr("Second")
+ }
+ RadioButton {
+ text: qsTr("Third")
+ }
+ }
+ \endcode
+
+ \sa ButtonGroup, {Customizing RadioButton}, {Button Controls}, RadioDelegate
+*/
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRadioButtonPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickRadioButton)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::RadioButton); }
+};
+
+QQuickRadioButton::QQuickRadioButton(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickRadioButtonPrivate), parent)
+{
+ setCheckable(true);
+ setAutoExclusive(true);
+}
+
+QFont QQuickRadioButton::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::RadioButton);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickRadioButton::accessibleRole() const
+{
+ return QAccessible::RadioButton;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickradiobutton_p.cpp"
diff --git a/src/quicktemplates2/qquickradiobutton_p.h b/src/quicktemplates2/qquickradiobutton_p.h
new file mode 100644
index 0000000000..29e1892294
--- /dev/null
+++ b/src/quicktemplates2/qquickradiobutton_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRADIOBUTTON_P_H
+#define QQUICKRADIOBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickRadioButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRadioButton : public QQuickAbstractButton
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(RadioButton)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickRadioButton(QQuickItem *parent = nullptr);
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickRadioButton)
+
+#endif // QQUICKRADIOBUTTON_P_H
diff --git a/src/quicktemplates2/qquickradiodelegate.cpp b/src/quicktemplates2/qquickradiodelegate.cpp
new file mode 100644
index 0000000000..836739389d
--- /dev/null
+++ b/src/quicktemplates2/qquickradiodelegate.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickradiodelegate_p.h"
+#include "qquickabstractbutton_p_p.h"
+#include "qquickitemdelegate_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RadioDelegate
+ \inherits ItemDelegate
+//! \instantiates QQuickRadioDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-delegates
+ \brief Exclusive item delegate with a radio indicator that can be toggled on or off.
+
+ \image qtquickcontrols2-radiodelegate.gif
+
+ RadioDelegate presents an item delegate that can be toggled on (checked) or
+ off (unchecked). Radio delegates are typically used to select one option
+ from a set of options.
+
+ RadioDelegate inherits its API from \l ItemDelegate, which is inherited
+ from AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton
+ API. The state of the radio delegate can be set with the
+ \l {AbstractButton::}{checked} property.
+
+ Radio delegates are \l {AbstractButton::autoExclusive}{auto-exclusive}
+ by default. Only one delegate can be checked at any time amongst radio
+ delegates that belong to the same parent item; checking another delegate
+ automatically unchecks the previously checked one. For radio delegates
+ that do not share a common parent, ButtonGroup can be used to manage
+ exclusivity.
+
+ \l RadioButton is similar to RadioDelegate, except that it is typically
+ not used in views, but rather when there are only a few options, and often
+ with the requirement that each button is uniquely identifiable.
+
+ \code
+ ButtonGroup {
+ id: buttonGroup
+ }
+
+ ListView {
+ model: ["Option 1", "Option 2", "Option 3"]
+ delegate: RadioDelegate {
+ text: modelData
+ checked: index == 0
+ ButtonGroup.group: buttonGroup
+ }
+ }
+ \endcode
+
+ \sa {Customizing RadioDelegate}, {Delegate Controls}, RadioButton
+*/
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRadioDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickRadioDelegate)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ListView); }
+};
+
+QQuickRadioDelegate::QQuickRadioDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickRadioDelegatePrivate), parent)
+{
+ setCheckable(true);
+ setAutoExclusive(true);
+}
+
+QFont QQuickRadioDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ListView);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickRadioDelegate::accessibleRole() const
+{
+ return QAccessible::RadioButton;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickradiodelegate_p.cpp"
diff --git a/src/quicktemplates2/qquickradiodelegate_p.h b/src/quicktemplates2/qquickradiodelegate_p.h
new file mode 100644
index 0000000000..0ddff985ce
--- /dev/null
+++ b/src/quicktemplates2/qquickradiodelegate_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRADIODELEGATE_P_H
+#define QQUICKRADIODELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickRadioDelegatePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRadioDelegate : public QQuickItemDelegate
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(RadioDelegate)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickRadioDelegate(QQuickItem *parent = nullptr);
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QQuickRadioDelegate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickRadioDelegate)
+
+#endif // QQUICKRADIODELEGATE_P_H
diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp
new file mode 100644
index 0000000000..4cedde66dc
--- /dev/null
+++ b/src/quicktemplates2/qquickrangeslider.cpp
@@ -0,0 +1,1344 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickrangeslider_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtCore/qscopedpointer.h>
+#include <QtQuick/private/qquickwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RangeSlider
+ \inherits Control
+//! \instantiates QQuickRangeSlider
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Used to select a range of values by sliding two handles along a track.
+
+ \image qtquickcontrols2-rangeslider.gif
+
+ RangeSlider is used to select a range specified by two values, by sliding
+ each handle along a track.
+
+ In the example below, custom \l from and \l to values are set, and the
+ initial positions of the \l first and \l second handles are set:
+
+ \code
+ RangeSlider {
+ from: 1
+ to: 100
+ first.value: 25
+ second.value: 75
+ }
+ \endcode
+
+ In order to perform an action when the value for a particular handle changes,
+ use the following syntax:
+
+ \code
+ first.onMoved: console.log("first.value changed to " + first.value)
+ \endcode
+
+ The \l {first.position} and \l {second.position} properties are expressed as
+ fractions of the control's size, in the range \c {0.0 - 1.0}.
+ The \l {first.visualPosition} and \l {second.visualPosition} properties are
+ the same, except that they are reversed in a
+ \l {Right-to-left User Interfaces}{right-to-left} application.
+ The \c visualPosition is useful for positioning the handles when styling
+ RangeSlider. In the example above, \l {first.visualPosition} will be \c 0.24
+ in a left-to-right application, and \c 0.76 in a right-to-left application.
+
+ For a slider that allows the user to select a single value, see \l Slider.
+
+ \sa {Customizing RangeSlider}, {Input Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+class QQuickRangeSliderNodePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickRangeSliderNode)
+public:
+ QQuickRangeSliderNodePrivate(qreal value, QQuickRangeSlider *slider)
+ : value(value),
+ slider(slider)
+ {
+ }
+
+ bool isFirst() const;
+
+ void setPosition(qreal position, bool ignoreOtherPosition = false);
+ void updatePosition(bool ignoreOtherPosition = false);
+
+ void cancelHandle();
+ void executeHandle(bool complete = false);
+
+ static QQuickRangeSliderNodePrivate *get(QQuickRangeSliderNode *node);
+
+ qreal value = 0;
+ bool isPendingValue = false;
+ qreal pendingValue = 0;
+ qreal position = 0;
+ QQuickDeferredPointer<QQuickItem> handle;
+ QQuickRangeSlider *slider = nullptr;
+ bool pressed = false;
+ bool hovered = false;
+ int touchId = -1;
+};
+
+bool QQuickRangeSliderNodePrivate::isFirst() const
+{
+ return this == get(slider->first());
+}
+
+void QQuickRangeSliderNodePrivate::setPosition(qreal position, bool ignoreOtherPosition)
+{
+ Q_Q(QQuickRangeSliderNode);
+
+ const qreal min = isFirst() || ignoreOtherPosition ? 0.0 : qMax<qreal>(0.0, slider->first()->position());
+ const qreal max = !isFirst() || ignoreOtherPosition ? 1.0 : qMin<qreal>(1.0, slider->second()->position());
+ position = qBound(min, position, max);
+ if (!qFuzzyCompare(this->position, position)) {
+ this->position = position;
+ emit q->positionChanged();
+ emit q->visualPositionChanged();
+ }
+}
+
+void QQuickRangeSliderNodePrivate::updatePosition(bool ignoreOtherPosition)
+{
+ qreal pos = 0;
+ if (!qFuzzyCompare(slider->from(), slider->to()))
+ pos = (value - slider->from()) / (slider->to() - slider->from());
+ setPosition(pos, ignoreOtherPosition);
+}
+
+static inline QString handleName() { return QStringLiteral("handle"); }
+
+void QQuickRangeSliderNodePrivate::cancelHandle()
+{
+ Q_Q(QQuickRangeSliderNode);
+ quickCancelDeferred(q, handleName());
+}
+
+void QQuickRangeSliderNodePrivate::executeHandle(bool complete)
+{
+ Q_Q(QQuickRangeSliderNode);
+ if (handle.wasExecuted())
+ return;
+
+ if (!handle || complete)
+ quickBeginDeferred(q, handleName(), handle);
+ if (complete)
+ quickCompleteDeferred(q, handleName(), handle);
+}
+
+QQuickRangeSliderNodePrivate *QQuickRangeSliderNodePrivate::get(QQuickRangeSliderNode *node)
+{
+ return node->d_func();
+}
+
+QQuickRangeSliderNode::QQuickRangeSliderNode(qreal value, QQuickRangeSlider *slider)
+ : QObject(*(new QQuickRangeSliderNodePrivate(value, slider)), slider)
+{
+}
+
+QQuickRangeSliderNode::~QQuickRangeSliderNode()
+{
+}
+
+qreal QQuickRangeSliderNode::value() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ return d->value;
+}
+
+void QQuickRangeSliderNode::setValue(qreal value)
+{
+ Q_D(QQuickRangeSliderNode);
+ if (!d->slider->isComponentComplete()) {
+ d->pendingValue = value;
+ d->isPendingValue = true;
+ return;
+ }
+
+ // First, restrict the first value to be within to and from.
+ const qreal smaller = qMin(d->slider->to(), d->slider->from());
+ const qreal larger = qMax(d->slider->to(), d->slider->from());
+ value = qBound(smaller, value, larger);
+
+ // Then, ensure that it doesn't go past the other value,
+ // a check that depends on whether or not the range is inverted.
+ const bool invertedRange = d->slider->from() > d->slider->to();
+ if (d->isFirst()) {
+ if (invertedRange) {
+ if (value < d->slider->second()->value())
+ value = d->slider->second()->value();
+ } else {
+ if (value > d->slider->second()->value())
+ value = d->slider->second()->value();
+ }
+ } else {
+ if (invertedRange) {
+ if (value > d->slider->first()->value())
+ value = d->slider->first()->value();
+ } else {
+ if (value < d->slider->first()->value())
+ value = d->slider->first()->value();
+ }
+ }
+
+ if (!qFuzzyCompare(d->value, value)) {
+ d->value = value;
+ d->updatePosition();
+ emit valueChanged();
+ }
+}
+
+qreal QQuickRangeSliderNode::position() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ return d->position;
+}
+
+qreal QQuickRangeSliderNode::visualPosition() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ if (d->slider->orientation() == Qt::Vertical || d->slider->isMirrored())
+ return 1.0 - d->position;
+ return d->position;
+}
+
+QQuickItem *QQuickRangeSliderNode::handle() const
+{
+ QQuickRangeSliderNodePrivate *d = const_cast<QQuickRangeSliderNodePrivate *>(d_func());
+ if (!d->handle)
+ d->executeHandle();
+ return d->handle;
+}
+
+void QQuickRangeSliderNode::setHandle(QQuickItem *handle)
+{
+ Q_D(QQuickRangeSliderNode);
+ if (d->handle == handle)
+ return;
+
+ if (!d->handle.isExecuting())
+ d->cancelHandle();
+
+ const qreal oldImplicitHandleWidth = implicitHandleWidth();
+ const qreal oldImplicitHandleHeight = implicitHandleHeight();
+
+ QQuickControlPrivate::get(d->slider)->removeImplicitSizeListener(d->handle);
+ QQuickControlPrivate::hideOldItem(d->handle);
+ d->handle = handle;
+
+ if (handle) {
+ if (!handle->parentItem())
+ handle->setParentItem(d->slider);
+
+ QQuickItem *firstHandle = QQuickRangeSliderNodePrivate::get(d->slider->first())->handle;
+ QQuickItem *secondHandle = QQuickRangeSliderNodePrivate::get(d->slider->second())->handle;
+ if (firstHandle && secondHandle) {
+ // The order of property assignments in QML is undefined,
+ // but we need the first handle to be before the second due
+ // to focus order constraints, so check for that here.
+ const QList<QQuickItem *> childItems = d->slider->childItems();
+ const int firstIndex = childItems.indexOf(firstHandle);
+ const int secondIndex = childItems.indexOf(secondHandle);
+ if (firstIndex != -1 && secondIndex != -1 && firstIndex > secondIndex) {
+ firstHandle->stackBefore(secondHandle);
+ // Ensure we have some way of knowing which handle is above
+ // the other when it comes to mouse presses, and also that
+ // they are rendered in the correct order.
+ secondHandle->setZ(secondHandle->z() + 1);
+ }
+ }
+
+ handle->setActiveFocusOnTab(true);
+ QQuickControlPrivate::get(d->slider)->addImplicitSizeListener(handle);
+ }
+
+ if (!qFuzzyCompare(oldImplicitHandleWidth, implicitHandleWidth()))
+ emit implicitHandleWidthChanged();
+ if (!qFuzzyCompare(oldImplicitHandleHeight, implicitHandleHeight()))
+ emit implicitHandleHeightChanged();
+ if (!d->handle.isExecuting())
+ emit handleChanged();
+}
+
+bool QQuickRangeSliderNode::isPressed() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ return d->pressed;
+}
+
+void QQuickRangeSliderNode::setPressed(bool pressed)
+{
+ Q_D(QQuickRangeSliderNode);
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ d->slider->setAccessibleProperty("pressed", pressed || d->slider->second()->isPressed());
+ emit pressedChanged();
+}
+
+bool QQuickRangeSliderNode::isHovered() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ return d->hovered;
+}
+
+void QQuickRangeSliderNode::setHovered(bool hovered)
+{
+ Q_D(QQuickRangeSliderNode);
+ if (d->hovered == hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
+qreal QQuickRangeSliderNode::implicitHandleWidth() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ if (!d->handle)
+ return 0;
+ return d->handle->implicitWidth();
+}
+
+qreal QQuickRangeSliderNode::implicitHandleHeight() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ if (!d->handle)
+ return 0;
+ return d->handle->implicitHeight();
+}
+
+void QQuickRangeSliderNode::increase()
+{
+ Q_D(QQuickRangeSliderNode);
+ qreal step = qFuzzyIsNull(d->slider->stepSize()) ? 0.1 : d->slider->stepSize();
+ setValue(d->value + step);
+}
+
+void QQuickRangeSliderNode::decrease()
+{
+ Q_D(QQuickRangeSliderNode);
+ qreal step = qFuzzyIsNull(d->slider->stepSize()) ? 0.1 : d->slider->stepSize();
+ setValue(d->value - step);
+}
+
+static const qreal defaultFrom = 0.0;
+static const qreal defaultTo = 1.0;
+
+class QQuickRangeSliderPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickRangeSlider)
+
+public:
+ QQuickRangeSliderNode *pressedNode(int touchId = -1) const;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ bool acceptTouch(const QTouchEvent::TouchPoint &point) override;
+#endif
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void updateHover(const QPointF &pos);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ bool live = true;
+ qreal from = defaultFrom;
+ qreal to = defaultTo;
+ qreal stepSize = 0;
+ qreal touchDragThreshold = -1;
+ QQuickRangeSliderNode *first = nullptr;
+ QQuickRangeSliderNode *second = nullptr;
+ QPointF pressPoint;
+ Qt::Orientation orientation = Qt::Horizontal;
+ QQuickRangeSlider::SnapMode snapMode = QQuickRangeSlider::NoSnap;
+};
+
+static qreal valueAt(const QQuickRangeSlider *slider, qreal position)
+{
+ return slider->from() + (slider->to() - slider->from()) * position;
+}
+
+static qreal snapPosition(const QQuickRangeSlider *slider, qreal position)
+{
+ const qreal range = slider->to() - slider->from();
+ if (qFuzzyIsNull(range))
+ return position;
+
+ const qreal effectiveStep = slider->stepSize() / range;
+ if (qFuzzyIsNull(effectiveStep))
+ return position;
+
+ return qRound(position / effectiveStep) * effectiveStep;
+}
+
+static qreal positionAt(const QQuickRangeSlider *slider, QQuickItem *handle, const QPointF &point)
+{
+ if (slider->orientation() == Qt::Horizontal) {
+ const qreal hw = handle ? handle->width() : 0;
+ const qreal offset = hw / 2;
+ const qreal extent = slider->availableWidth() - hw;
+ if (!qFuzzyIsNull(extent)) {
+ if (slider->isMirrored())
+ return (slider->width() - point.x() - slider->rightPadding() - offset) / extent;
+ return (point.x() - slider->leftPadding() - offset) / extent;
+ }
+ } else {
+ const qreal hh = handle ? handle->height() : 0;
+ const qreal offset = hh / 2;
+ const qreal extent = slider->availableHeight() - hh;
+ if (!qFuzzyIsNull(extent))
+ return (slider->height() - point.y() - slider->bottomPadding() - offset) / extent;
+ }
+ return 0;
+}
+
+QQuickRangeSliderNode *QQuickRangeSliderPrivate::pressedNode(int touchId) const
+{
+ if (touchId == -1)
+ return first->isPressed() ? first : (second->isPressed() ? second : nullptr);
+ if (QQuickRangeSliderNodePrivate::get(first)->touchId == touchId)
+ return first;
+ if (QQuickRangeSliderNodePrivate::get(second)->touchId == touchId)
+ return second;
+ return nullptr;
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+bool QQuickRangeSliderPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
+{
+ int firstId = QQuickRangeSliderNodePrivate::get(first)->touchId;
+ int secondId = QQuickRangeSliderNodePrivate::get(second)->touchId;
+
+ if (((firstId == -1 || secondId == -1) && point.state() == QEventPoint::Pressed) || point.id() == firstId || point.id() == secondId) {
+ touchId = point.id();
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+void QQuickRangeSliderPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickRangeSlider);
+ QQuickControlPrivate::handlePress(point);
+ pressPoint = point;
+
+ QQuickItem *firstHandle = first->handle();
+ QQuickItem *secondHandle = second->handle();
+ const bool firstHit = firstHandle && !first->isPressed() && firstHandle->contains(q->mapToItem(firstHandle, point));
+ const bool secondHit = secondHandle && !second->isPressed() && secondHandle->contains(q->mapToItem(secondHandle, point));
+ QQuickRangeSliderNode *hitNode = nullptr;
+ QQuickRangeSliderNode *otherNode = nullptr;
+
+ if (firstHit && secondHit) {
+ // choose highest
+ hitNode = firstHandle->z() > secondHandle->z() ? first : second;
+ otherNode = firstHandle->z() > secondHandle->z() ? second : first;
+ } else if (firstHit) {
+ hitNode = first;
+ otherNode = second;
+ } else if (secondHit) {
+ hitNode = second;
+ otherNode = first;
+ } else {
+ // find the nearest
+ const qreal firstPos = positionAt(q, firstHandle, point);
+ const qreal secondPos = positionAt(q, secondHandle, point);
+ const qreal firstDistance = qAbs(firstPos - first->position());
+ const qreal secondDistance = qAbs(secondPos - second->position());
+
+ if (qFuzzyCompare(firstDistance, secondDistance)) {
+ // same distance => choose the one that can be moved towards the press position
+ const bool inverted = from > to;
+ if ((!inverted && firstPos < first->position()) || (inverted && firstPos > first->position())) {
+ hitNode = first;
+ otherNode = second;
+ } else {
+ hitNode = second;
+ otherNode = first;
+ }
+ } else if (firstDistance < secondDistance) {
+ hitNode = first;
+ otherNode = second;
+ } else {
+ hitNode = second;
+ otherNode = first;
+ }
+ }
+
+ if (hitNode) {
+ hitNode->setPressed(true);
+ if (QQuickItem *handle = hitNode->handle())
+ handle->setZ(1);
+ QQuickRangeSliderNodePrivate::get(hitNode)->touchId = touchId;
+ }
+ if (otherNode) {
+ if (QQuickItem *handle = otherNode->handle())
+ handle->setZ(0);
+ }
+}
+
+void QQuickRangeSliderPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickRangeSlider);
+ QQuickControlPrivate::handleMove(point);
+ QQuickRangeSliderNode *pressedNode = QQuickRangeSliderPrivate::pressedNode(touchId);
+ if (pressedNode) {
+ const qreal oldPos = pressedNode->position();
+ qreal pos = positionAt(q, pressedNode->handle(), point);
+ if (snapMode == QQuickRangeSlider::SnapAlways)
+ pos = snapPosition(q, pos);
+ if (live)
+ pressedNode->setValue(valueAt(q, pos));
+ else
+ QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos);
+
+ if (!qFuzzyCompare(pressedNode->position(), oldPos))
+ emit pressedNode->moved();
+ }
+}
+
+void QQuickRangeSliderPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickRangeSlider);
+ QQuickControlPrivate::handleRelease(point);
+ pressPoint = QPointF();
+
+ QQuickRangeSliderNode *pressedNode = QQuickRangeSliderPrivate::pressedNode(touchId);
+ if (!pressedNode)
+ return;
+ QQuickRangeSliderNodePrivate *pressedNodePrivate = QQuickRangeSliderNodePrivate::get(pressedNode);
+
+ if (q->keepMouseGrab() || q->keepTouchGrab()) {
+ const qreal oldPos = pressedNode->position();
+ qreal pos = positionAt(q, pressedNode->handle(), point);
+ if (snapMode != QQuickRangeSlider::NoSnap)
+ pos = snapPosition(q, pos);
+ qreal val = valueAt(q, pos);
+ if (!qFuzzyCompare(val, pressedNode->value()))
+ pressedNode->setValue(val);
+ else if (snapMode != QQuickRangeSlider::NoSnap)
+ pressedNodePrivate->setPosition(pos);
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+
+ if (!qFuzzyCompare(pressedNode->position(), oldPos))
+ emit pressedNode->moved();
+ }
+ pressedNode->setPressed(false);
+ pressedNodePrivate->touchId = -1;
+}
+
+void QQuickRangeSliderPrivate::handleUngrab()
+{
+ QQuickControlPrivate::handleUngrab();
+ pressPoint = QPointF();
+ first->setPressed(false);
+ second->setPressed(false);
+ QQuickRangeSliderNodePrivate::get(first)->touchId = -1;
+ QQuickRangeSliderNodePrivate::get(second)->touchId = -1;
+}
+
+void QQuickRangeSliderPrivate::updateHover(const QPointF &pos)
+{
+ Q_Q(QQuickRangeSlider);
+ QQuickItem *firstHandle = first->handle();
+ QQuickItem *secondHandle = second->handle();
+ bool firstHandleHovered = firstHandle && firstHandle->isEnabled()
+ && firstHandle->contains(q->mapToItem(firstHandle, pos));
+ bool secondHandleHovered = secondHandle && secondHandle->isEnabled()
+ && secondHandle->contains(q->mapToItem(secondHandle, pos));
+
+ if (firstHandleHovered && secondHandleHovered) {
+ // Only hover the handle with the higher Z value.
+ const bool firstHandleHasHigherZ = firstHandle->z() > secondHandle->z();
+ firstHandleHovered = firstHandleHasHigherZ;
+ secondHandleHovered = !firstHandleHasHigherZ;
+ }
+ first->setHovered(firstHandleHovered);
+ second->setHovered(secondHandleHovered);
+}
+
+void QQuickRangeSliderPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ if (item == first->handle())
+ emit first->implicitHandleWidthChanged();
+ else if (item == second->handle())
+ emit second->implicitHandleWidthChanged();
+}
+
+void QQuickRangeSliderPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ if (item == first->handle())
+ emit first->implicitHandleHeightChanged();
+ else if (item == second->handle())
+ emit second->implicitHandleHeightChanged();
+}
+
+QQuickRangeSlider::QQuickRangeSlider(QQuickItem *parent)
+ : QQuickControl(*(new QQuickRangeSliderPrivate), parent)
+{
+ Q_D(QQuickRangeSlider);
+ d->first = new QQuickRangeSliderNode(0.0, this);
+ d->second = new QQuickRangeSliderNode(1.0, this);
+
+ setFlag(QQuickItem::ItemIsFocusScope);
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickRangeSlider::~QQuickRangeSlider()
+{
+ Q_D(QQuickRangeSlider);
+ d->removeImplicitSizeListener(d->first->handle());
+ d->removeImplicitSizeListener(d->second->handle());
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::RangeSlider::from
+
+ This property holds the starting value for the range. The default value is \c 0.0.
+
+ \sa to, first.value, second.value
+*/
+qreal QQuickRangeSlider::from() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->from;
+}
+
+void QQuickRangeSlider::setFrom(qreal from)
+{
+ Q_D(QQuickRangeSlider);
+ if (qFuzzyCompare(d->from, from))
+ return;
+
+ d->from = from;
+ emit fromChanged();
+
+ if (isComponentComplete()) {
+ d->first->setValue(d->first->value());
+ d->second->setValue(d->second->value());
+ auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first);
+ auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second);
+ firstPrivate->updatePosition(true);
+ secondPrivate->updatePosition();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::RangeSlider::to
+
+ This property holds the end value for the range. The default value is \c 1.0.
+
+ \sa from, first.value, second.value
+*/
+qreal QQuickRangeSlider::to() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->to;
+}
+
+void QQuickRangeSlider::setTo(qreal to)
+{
+ Q_D(QQuickRangeSlider);
+ if (qFuzzyCompare(d->to, to))
+ return;
+
+ d->to = to;
+ emit toChanged();
+
+ if (isComponentComplete()) {
+ d->first->setValue(d->first->value());
+ d->second->setValue(d->second->value());
+ auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first);
+ auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second);
+ firstPrivate->updatePosition(true);
+ secondPrivate->updatePosition();
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty qreal QtQuick.Controls::RangeSlider::touchDragThreshold
+
+ This property holds the threshold (in logical pixels) at which a touch drag event will be initiated.
+ The mouse drag threshold won't be affected.
+ The default value is \c Qt.styleHints.startDragDistance.
+
+ \sa QStyleHints
+
+*/
+qreal QQuickRangeSlider::touchDragThreshold() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->touchDragThreshold;
+}
+
+void QQuickRangeSlider::setTouchDragThreshold(qreal touchDragThreshold)
+{
+ Q_D(QQuickRangeSlider);
+ if (d->touchDragThreshold == touchDragThreshold)
+ return;
+
+ d->touchDragThreshold = touchDragThreshold;
+ emit touchDragThresholdChanged();
+}
+
+void QQuickRangeSlider::resetTouchDragThreshold()
+{
+ setTouchDragThreshold(-1);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlmethod real QtQuick.Controls::RangeSlider::valueAt(real position)
+
+ Returns the value for the given \a position.
+
+ \sa first.value, second.value, first.position, second.position, live
+*/
+qreal QQuickRangeSlider::valueAt(qreal position) const
+{
+ Q_D(const QQuickRangeSlider);
+ const qreal value = (d->to - d->from) * position;
+ if (qFuzzyIsNull(d->stepSize))
+ return d->from + value;
+ return d->from + qRound(value / d->stepSize) * d->stepSize;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::RangeSlider::first.value
+ \qmlproperty real QtQuick.Controls::RangeSlider::first.position
+ \qmlproperty real QtQuick.Controls::RangeSlider::first.visualPosition
+ \qmlproperty Item QtQuick.Controls::RangeSlider::first.handle
+ \qmlproperty bool QtQuick.Controls::RangeSlider::first.pressed
+ \qmlproperty bool QtQuick.Controls::RangeSlider::first.hovered
+ \qmlproperty real QtQuick.Controls::RangeSlider::first.implicitHandleWidth
+ \qmlproperty real QtQuick.Controls::RangeSlider::first.implicitHandleHeight
+
+ \table
+ \header
+ \li Property
+ \li Description
+ \row
+ \li value
+ \li This property holds the value of the first handle in the range
+ \c from - \c to.
+
+ If \l from is greater than \l to, the value of the first handle
+ must be greater than the second, and vice versa.
+
+ The default value is \c 0.0.
+ \row
+ \li handle
+ \li This property holds the first handle item.
+ \row
+ \li visualPosition
+ \li This property holds the visual position of the first handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the
+ value is equal to \c {1.0 - position}. This makes the value suitable for
+ visualizing the slider, taking right-to-left support into account.
+ \row
+ \li position
+ \li This property holds the logical position of the first handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. For visualizing a slider, the right-to-left aware
+ \l {first.visualPosition}{visualPosition} should be used instead.
+ \row
+ \li pressed
+ \li This property holds whether the first handle is pressed by either touch,
+ mouse, or keys.
+ \row
+ \li hovered
+ \li This property holds whether the first handle is hovered.
+ This property was introduced in QtQuick.Controls 2.1.
+ \row
+ \li implicitHandleWidth
+ \li This property holds the implicit width of the first handle.
+ This property was introduced in QtQuick.Controls 2.5.
+ \row
+ \li implicitHandleHeight
+ \li This property holds the implicit height of the first handle.
+ This property was introduced in QtQuick.Controls 2.5.
+ \endtable
+
+ \sa first.moved(), first.increase(), first.decrease()
+*/
+QQuickRangeSliderNode *QQuickRangeSlider::first() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->first;
+}
+
+/*!
+ \qmlsignal void QtQuick.Controls::RangeSlider::first.moved()
+ \qmlsignal void QtQuick.Controls::RangeSlider::second.moved()
+ \since QtQuick.Controls 2.5
+
+ This signal is emitted when either the first or second handle has been
+ interactively moved by the user by either touch, mouse, or keys.
+
+ \sa first, second
+*/
+
+/*!
+ \qmlproperty real QtQuick.Controls::RangeSlider::second.value
+ \qmlproperty real QtQuick.Controls::RangeSlider::second.position
+ \qmlproperty real QtQuick.Controls::RangeSlider::second.visualPosition
+ \qmlproperty Item QtQuick.Controls::RangeSlider::second.handle
+ \qmlproperty bool QtQuick.Controls::RangeSlider::second.pressed
+ \qmlproperty bool QtQuick.Controls::RangeSlider::second.hovered
+ \qmlproperty real QtQuick.Controls::RangeSlider::second.implicitHandleWidth
+ \qmlproperty real QtQuick.Controls::RangeSlider::second.implicitHandleHeight
+
+ \table
+ \header
+ \li Property
+ \li Description
+ \row
+ \li value
+ \li This property holds the value of the second handle in the range
+ \c from - \c to.
+
+ If \l from is greater than \l to, the value of the first handle
+ must be greater than the second, and vice versa.
+
+ The default value is \c 0.0.
+ \row
+ \li handle
+ \li This property holds the second handle item.
+ \row
+ \li visualPosition
+ \li This property holds the visual position of the second handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the
+ value is equal to \c {1.0 - position}. This makes the value suitable for
+ visualizing the slider, taking right-to-left support into account.
+ \row
+ \li position
+ \li This property holds the logical position of the second handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. For visualizing a slider, the right-to-left aware
+ \l {second.visualPosition}{visualPosition} should be used instead.
+ \row
+ \li pressed
+ \li This property holds whether the second handle is pressed by either touch,
+ mouse, or keys.
+ \row
+ \li hovered
+ \li This property holds whether the second handle is hovered.
+ This property was introduced in QtQuick.Controls 2.1.
+ \row
+ \li implicitHandleWidth
+ \li This property holds the implicit width of the second handle.
+ This property was introduced in QtQuick.Controls 2.5.
+ \row
+ \li implicitHandleHeight
+ \li This property holds the implicit height of the second handle.
+ This property was introduced in QtQuick.Controls 2.5.
+ \endtable
+
+ \sa second.moved(), second.increase(), second.decrease()
+*/
+QQuickRangeSliderNode *QQuickRangeSlider::second() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->second;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::RangeSlider::stepSize
+
+ This property holds the step size. The default value is \c 0.0.
+
+ \sa snapMode, first.increase(), first.decrease()
+*/
+qreal QQuickRangeSlider::stepSize() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->stepSize;
+}
+
+void QQuickRangeSlider::setStepSize(qreal step)
+{
+ Q_D(QQuickRangeSlider);
+ if (qFuzzyCompare(d->stepSize, step))
+ return;
+
+ d->stepSize = step;
+ emit stepSizeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::RangeSlider::snapMode
+
+ This property holds the snap mode.
+
+ The snap mode determines how the slider handles behave with
+ regards to the \l stepSize.
+
+ Possible values:
+ \value RangeSlider.NoSnap The slider does not snap (default).
+ \value RangeSlider.SnapAlways The slider snaps while the handle is dragged.
+ \value RangeSlider.SnapOnRelease The slider does not snap while being dragged, but only after the handle is released.
+
+ For visual explanations of the various modes, see the
+ \l {Slider::}{snapMode} documentation of \l Slider.
+
+ \sa stepSize
+*/
+QQuickRangeSlider::SnapMode QQuickRangeSlider::snapMode() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->snapMode;
+}
+
+void QQuickRangeSlider::setSnapMode(SnapMode mode)
+{
+ Q_D(QQuickRangeSlider);
+ if (d->snapMode == mode)
+ return;
+
+ d->snapMode = mode;
+ emit snapModeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::RangeSlider::orientation
+
+ This property holds the orientation.
+
+ Possible values:
+ \value Qt.Horizontal Horizontal (default)
+ \value Qt.Vertical Vertical
+
+ \sa horizontal, vertical
+*/
+Qt::Orientation QQuickRangeSlider::orientation() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->orientation;
+}
+
+void QQuickRangeSlider::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickRangeSlider);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ emit orientationChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::RangeSlider::setValues(real firstValue, real secondValue)
+
+ Sets \l first.value and \l second.value with the given arguments.
+
+ If \l to is larger than \l from and \a firstValue is larger than
+ \a secondValue, firstValue will be clamped to secondValue.
+
+ If \l from is larger than \l to and secondValue is larger than
+ firstValue, secondValue will be clamped to firstValue.
+
+ This function may be necessary to set the first and second values
+ after the control has been completed, as there is a circular
+ dependency between firstValue and secondValue which can cause
+ assigned values to be clamped to each other.
+
+ \sa stepSize
+*/
+void QQuickRangeSlider::setValues(qreal firstValue, qreal secondValue)
+{
+ Q_D(QQuickRangeSlider);
+ // Restrict the values to be within to and from.
+ const qreal smaller = qMin(d->to, d->from);
+ const qreal larger = qMax(d->to, d->from);
+ firstValue = qBound(smaller, firstValue, larger);
+ secondValue = qBound(smaller, secondValue, larger);
+
+ if (d->from > d->to) {
+ // If the from and to values are reversed, the secondValue
+ // might be less than the first value, which is not allowed.
+ if (secondValue > firstValue)
+ secondValue = firstValue;
+ } else {
+ // Otherwise, clamp first to second if it's too large.
+ if (firstValue > secondValue)
+ firstValue = secondValue;
+ }
+
+ // Then set both values. If they didn't change, no change signal will be emitted.
+ QQuickRangeSliderNodePrivate *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first);
+ if (firstValue != firstPrivate->value) {
+ firstPrivate->value = firstValue;
+ emit d->first->valueChanged();
+ }
+
+ QQuickRangeSliderNodePrivate *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second);
+ if (secondValue != secondPrivate->value) {
+ secondPrivate->value = secondValue;
+ emit d->second->valueChanged();
+ }
+
+ // After we've set both values, then we can update the positions.
+ // If we don't do this last, the positions may be incorrect.
+ firstPrivate->updatePosition(true);
+ secondPrivate->updatePosition();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::RangeSlider::live
+
+ This property holds whether the slider provides live updates for the \l first.value
+ and \l second.value properties while the respective handles are dragged.
+
+ The default value is \c true.
+
+ \sa first.value, second.value
+*/
+bool QQuickRangeSlider::live() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->live;
+}
+
+void QQuickRangeSlider::setLive(bool live)
+{
+ Q_D(QQuickRangeSlider);
+ if (d->live == live)
+ return;
+
+ d->live = live;
+ emit liveChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::RangeSlider::horizontal
+ \readonly
+
+ This property holds whether the slider is horizontal.
+
+ \sa orientation
+*/
+bool QQuickRangeSlider::isHorizontal() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::RangeSlider::vertical
+ \readonly
+
+ This property holds whether the slider is vertical.
+
+ \sa orientation
+*/
+bool QQuickRangeSlider::isVertical() const
+{
+ Q_D(const QQuickRangeSlider);
+ return d->orientation == Qt::Vertical;
+}
+
+void QQuickRangeSlider::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::focusInEvent(event);
+
+ // The active focus ends up to RangeSlider when using forceActiveFocus()
+ // or QML KeyNavigation. We must forward the focus to one of the handles,
+ // because RangeSlider handles key events for the focused handle. If
+ // neither handle has active focus, RangeSlider doesn't do anything.
+ QQuickItem *handle = nextItemInFocusChain();
+ // QQuickItem::nextItemInFocusChain() only works as desired with
+ // Qt::TabFocusAllControls. otherwise pick the first handle
+ if (!handle || handle == this)
+ handle = d->first->handle();
+ if (handle)
+ handle->forceActiveFocus(event->reason());
+}
+
+void QQuickRangeSlider::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::keyPressEvent(event);
+
+ QQuickRangeSliderNode *focusNode = d->first->handle()->hasActiveFocus()
+ ? d->first : (d->second->handle()->hasActiveFocus() ? d->second : nullptr);
+ if (!focusNode)
+ return;
+
+ const qreal oldValue = focusNode->value();
+ if (d->orientation == Qt::Horizontal) {
+ if (event->key() == Qt::Key_Left) {
+ focusNode->setPressed(true);
+ if (isMirrored())
+ focusNode->increase();
+ else
+ focusNode->decrease();
+ event->accept();
+ } else if (event->key() == Qt::Key_Right) {
+ focusNode->setPressed(true);
+ if (isMirrored())
+ focusNode->decrease();
+ else
+ focusNode->increase();
+ event->accept();
+ }
+ } else {
+ if (event->key() == Qt::Key_Up) {
+ focusNode->setPressed(true);
+ focusNode->increase();
+ event->accept();
+ } else if (event->key() == Qt::Key_Down) {
+ focusNode->setPressed(true);
+ focusNode->decrease();
+ event->accept();
+ }
+ }
+ if (!qFuzzyCompare(focusNode->value(), oldValue))
+ emit focusNode->moved();
+}
+
+void QQuickRangeSlider::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverEnterEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickRangeSlider::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverMoveEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickRangeSlider::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverLeaveEvent(event);
+ d->first->setHovered(false);
+ d->second->setHovered(false);
+ event->ignore();
+}
+
+void QQuickRangeSlider::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::keyReleaseEvent(event);
+ d->first->setPressed(false);
+ d->second->setPressed(false);
+}
+
+void QQuickRangeSlider::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::mousePressEvent(event);
+ d->handleMove(event->position());
+ setKeepMouseGrab(true);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickRangeSlider::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ switch (event->type()) {
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (!d->acceptTouch(point))
+ continue;
+
+ switch (point.state()) {
+ case QEventPoint::Pressed:
+ d->handlePress(point.position());
+ break;
+ case QEventPoint::Updated:
+ if (!keepTouchGrab()) {
+ if (d->orientation == Qt::Horizontal)
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().x() - point.pressPosition().x(), Qt::XAxis, &point, qRound(d->touchDragThreshold)));
+ else
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().y() - point.pressPosition().y(), Qt::YAxis, &point, qRound(d->touchDragThreshold)));
+ }
+ if (keepTouchGrab())
+ d->handleMove(point.position());
+ break;
+ case QEventPoint::Released:
+ d->handleRelease(point.position());
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ QQuickControl::touchEvent(event);
+ break;
+ }
+}
+#endif
+
+void QQuickRangeSlider::mirrorChange()
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::mirrorChange();
+ emit d->first->visualPositionChanged();
+ emit d->second->visualPositionChanged();
+}
+
+void QQuickRangeSlider::classBegin()
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::classBegin();
+
+ QQmlContext *context = qmlContext(this);
+ if (context) {
+ QQmlEngine::setContextForObject(d->first, context);
+ QQmlEngine::setContextForObject(d->second, context);
+ }
+}
+
+void QQuickRangeSlider::componentComplete()
+{
+ Q_D(QQuickRangeSlider);
+ QQuickRangeSliderNodePrivate *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first);
+ QQuickRangeSliderNodePrivate *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second);
+ firstPrivate->executeHandle(true);
+ secondPrivate->executeHandle(true);
+
+ QQuickControl::componentComplete();
+
+ if (firstPrivate->isPendingValue || secondPrivate->isPendingValue
+ || !qFuzzyCompare(d->from, defaultFrom) || !qFuzzyCompare(d->to, defaultTo)) {
+ // Properties were set while we were loading. To avoid clamping issues that occur when setting the
+ // values of first and second overriding values set by the user, set them all at once at the end.
+ // Another reason that we must set these values here is that the from and to values might have made the old range invalid.
+ setValues(firstPrivate->isPendingValue ? firstPrivate->pendingValue : firstPrivate->value,
+ secondPrivate->isPendingValue ? secondPrivate->pendingValue : secondPrivate->value);
+
+ firstPrivate->pendingValue = 0;
+ firstPrivate->isPendingValue = false;
+ secondPrivate->pendingValue = 0;
+ secondPrivate->isPendingValue = false;
+ } else {
+ // If there was no pending data, we must still update the positions,
+ // as first.setValue()/second.setValue() won't be called as part of default construction.
+ // Don't need to ignore the second position when updating the first position here,
+ // as our default values are guaranteed to be valid.
+ firstPrivate->updatePosition();
+ secondPrivate->updatePosition();
+ }
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::RangeSlider::first.increase()
+
+ Increases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa first
+*/
+
+/*!
+ \qmlmethod void QtQuick.Controls::RangeSlider::first.decrease()
+
+ Decreases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa first
+*/
+
+/*!
+ \qmlmethod void QtQuick.Controls::RangeSlider::second.increase()
+
+ Increases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa second
+*/
+
+/*!
+ \qmlmethod void QtQuick.Controls::RangeSlider::second.decrease()
+
+ Decreases the value of the handle by stepSize, or \c 0.1 if stepSize is not defined.
+
+ \sa second
+*/
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickRangeSlider::accessibleRole() const
+{
+ return QAccessible::Slider;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickrangeslider_p.cpp"
diff --git a/src/quicktemplates2/qquickrangeslider_p.h b/src/quicktemplates2/qquickrangeslider_p.h
new file mode 100644
index 0000000000..d767228e10
--- /dev/null
+++ b/src/quicktemplates2/qquickrangeslider_p.h
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRANGESLIDER_P_H
+#define QQUICKRANGESLIDER_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickRangeSliderPrivate;
+class QQuickRangeSliderNode;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRangeSlider : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(QQuickRangeSliderNode *first READ first CONSTANT FINAL)
+ Q_PROPERTY(QQuickRangeSliderNode *second READ second CONSTANT FINAL)
+ Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION(2, 3))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION(2, 3))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal touchDragThreshold READ touchDragThreshold WRITE setTouchDragThreshold RESET resetTouchDragThreshold NOTIFY touchDragThresholdChanged FINAL REVISION(2, 5))
+ QML_NAMED_ELEMENT(RangeSlider)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickRangeSlider(QQuickItem *parent = nullptr);
+ ~QQuickRangeSlider();
+
+ qreal from() const;
+ void setFrom(qreal from);
+
+ qreal to() const;
+ void setTo(qreal to);
+
+ QQuickRangeSliderNode *first() const;
+ QQuickRangeSliderNode *second() const;
+
+ qreal stepSize() const;
+ void setStepSize(qreal step);
+
+ enum SnapMode {
+ NoSnap,
+ SnapAlways,
+ SnapOnRelease
+ };
+ Q_ENUM(SnapMode)
+
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ Q_INVOKABLE void setValues(qreal firstValue, qreal secondValue);
+
+ // 2.2 (Qt 5.9)
+ bool live() const;
+ void setLive(bool live);
+
+ // 2.3 (Qt 5.10)
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+ // 2.5 (Qt 5.12)
+ qreal touchDragThreshold() const;
+ void setTouchDragThreshold(qreal touchDragThreshold);
+ void resetTouchDragThreshold();
+ Q_REVISION(2, 5) Q_INVOKABLE qreal valueAt(qreal position) const;
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void stepSizeChanged();
+ void snapModeChanged();
+ void orientationChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void liveChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void touchDragThresholdChanged();
+
+protected:
+ void focusInEvent(QFocusEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+ void mirrorChange() override;
+ void classBegin() override;
+ void componentComplete() override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ friend class QQuickRangeSliderNode;
+
+ Q_DISABLE_COPY(QQuickRangeSlider)
+ Q_DECLARE_PRIVATE(QQuickRangeSlider)
+};
+
+class QQuickRangeSliderNodePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRangeSliderNode : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
+ Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool hovered READ isHovered WRITE setHovered NOTIFY hoveredChanged FINAL REVISION(2, 1))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal implicitHandleWidth READ implicitHandleWidth NOTIFY implicitHandleWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitHandleHeight READ implicitHandleHeight NOTIFY implicitHandleHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "handle")
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickRangeSliderNode(qreal value, QQuickRangeSlider *slider);
+ ~QQuickRangeSliderNode();
+
+ qreal value() const;
+ void setValue(qreal value);
+
+ qreal position() const;
+ qreal visualPosition() const;
+
+ QQuickItem *handle() const;
+ void setHandle(QQuickItem *handle);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ // 2.1 (Qt 5.8)
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ // 2.5 (Qt 5.12)
+ qreal implicitHandleWidth() const;
+ qreal implicitHandleHeight() const;
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+
+Q_SIGNALS:
+ void valueChanged();
+ void positionChanged();
+ void visualPositionChanged();
+ void handleChanged();
+ void pressedChanged();
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void hoveredChanged();
+ // 2.5 (Qt 5.12)
+ /*Q_REVISION(2, 5)*/ void moved();
+ /*Q_REVISION(2, 5)*/ void implicitHandleWidthChanged();
+ /*Q_REVISION(2, 5)*/ void implicitHandleHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickRangeSliderNode)
+ Q_DECLARE_PRIVATE(QQuickRangeSliderNode)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickRangeSlider)
+
+#endif // QQUICKRANGESLIDER_P_H
diff --git a/src/quicktemplates2/qquickroundbutton.cpp b/src/quicktemplates2/qquickroundbutton.cpp
new file mode 100644
index 0000000000..0f1b366cd9
--- /dev/null
+++ b/src/quicktemplates2/qquickroundbutton.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickroundbutton_p.h"
+
+#include <QtQuickTemplates2/private/qquickbutton_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype RoundButton
+ \inherits Button
+//! \instantiates QQuickRoundButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.8
+ \ingroup qtquickcontrols2-buttons
+ \brief A push-button control with rounded corners that can be clicked by the user.
+
+ \image qtquickcontrols2-roundbutton.png
+
+ RoundButton is identical to \l Button, except that it has a \l radius property
+ which allows the corners to be rounded without having to customize the
+ \l background.
+
+ \snippet qtquickcontrols2-roundbutton.qml 1
+
+ \sa {Customizing RoundButton}, {Button Controls}
+*/
+
+class QQuickRoundButtonPrivate : public QQuickButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickRoundButton)
+
+public:
+ void setRadius(qreal newRadius = -1.0);
+
+ qreal radius = 0;
+ bool explicitRadius = false;
+};
+
+void QQuickRoundButtonPrivate::setRadius(qreal newRadius)
+{
+ Q_Q(QQuickRoundButton);
+ const qreal oldRadius = radius;
+ if (newRadius < 0)
+ radius = qMax<qreal>(0, qMin<qreal>(width, height) / 2);
+ else
+ radius = newRadius;
+
+ if (!qFuzzyCompare(radius, oldRadius))
+ emit q->radiusChanged();
+}
+
+QQuickRoundButton::QQuickRoundButton(QQuickItem *parent)
+ : QQuickButton(*(new QQuickRoundButtonPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::RoundButton::radius
+
+ This property holds the radius of the button.
+
+ To create a relatively square button that has slightly rounded corners,
+ use a small value, such as \c 3.
+
+ To create a completely circular button (the default), use a value that is
+ equal to half of the width or height of the button, and make the button's
+ width and height identical.
+
+ To reset this property back to the default value, set its value to
+ \c undefined.
+*/
+qreal QQuickRoundButton::radius() const
+{
+ Q_D(const QQuickRoundButton);
+ return d->radius;
+}
+
+void QQuickRoundButton::setRadius(qreal radius)
+{
+ Q_D(QQuickRoundButton);
+ d->explicitRadius = true;
+ d->setRadius(radius);
+}
+
+void QQuickRoundButton::resetRadius()
+{
+ Q_D(QQuickRoundButton);
+ d->explicitRadius = false;
+ d->setRadius();
+}
+
+void QQuickRoundButton::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickRoundButton);
+ QQuickControl::geometryChange(newGeometry, oldGeometry);
+ if (!d->explicitRadius)
+ d->setRadius();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickroundbutton_p.cpp"
diff --git a/src/quicktemplates2/qquickroundbutton_p.h b/src/quicktemplates2/qquickroundbutton_p.h
new file mode 100644
index 0000000000..fdd46cf8f6
--- /dev/null
+++ b/src/quicktemplates2/qquickroundbutton_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKROUNDBUTTON_P_H
+#define QQUICKROUNDBUTTON_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 <QtQuickTemplates2/private/qquickbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickRoundButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRoundButton : public QQuickButton
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal radius READ radius WRITE setRadius RESET resetRadius NOTIFY radiusChanged FINAL)
+ QML_NAMED_ELEMENT(RoundButton)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickRoundButton(QQuickItem *parent = nullptr);
+
+ qreal radius() const;
+ void setRadius(qreal radius);
+ void resetRadius();
+
+Q_SIGNALS:
+ void radiusChanged();
+
+protected:
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private:
+ Q_DISABLE_COPY(QQuickRoundButton)
+ Q_DECLARE_PRIVATE(QQuickRoundButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickRoundButton)
+
+#endif // QQUICKROUNDBUTTON_P_H
diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp
new file mode 100644
index 0000000000..fbcd772dc5
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollbar.cpp
@@ -0,0 +1,1281 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickscrollbar_p.h"
+#include "qquickscrollbar_p_p.h"
+#include "qquickscrollview_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ScrollBar
+ \inherits Control
+//! \instantiates QQuickScrollBar
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-indicators
+ \brief Vertical or horizontal interactive scroll bar.
+
+ \image qtquickcontrols2-scrollbar.gif
+
+ ScrollBar is an interactive bar that can be used to scroll to a specific
+ position. A scroll bar can be either \l vertical or \l horizontal, and can
+ be attached to any \l Flickable, such as \l ListView and \l GridView.
+ It can also be used with \l ScrollView.
+
+ \code
+ Flickable {
+ // ...
+ ScrollBar.vertical: ScrollBar { }
+ }
+ \endcode
+
+ \section1 Attaching ScrollBar to a Flickable
+
+ When ScrollBar is attached \l {ScrollBar::vertical}{vertically} or
+ \l {ScrollBar::horizontal}{horizontally} to a Flickable, its geometry and
+ the following properties are automatically set and updated as appropriate:
+
+ \list
+ \li \l orientation
+ \li \l position
+ \li \l size
+ \li \l active
+ \endlist
+
+ An attached ScrollBar re-parents itself to the target Flickable. A vertically
+ attached ScrollBar resizes itself to the height of the Flickable, and positions
+ itself to either side of it based on the \l {Control::mirrored}{layout direction}.
+ A horizontally attached ScrollBar resizes itself to the width of the Flickable,
+ and positions itself to the bottom. The automatic geometry management can be disabled
+ by specifying another parent for the attached ScrollBar. This can be useful, for
+ example, if the ScrollBar should be placed outside a clipping Flickable. This is
+ demonstrated by the following example:
+
+ \code
+ Flickable {
+ id: flickable
+ clip: true
+ // ...
+ ScrollBar.vertical: ScrollBar {
+ parent: flickable.parent
+ anchors.top: flickable.top
+ anchors.left: flickable.right
+ anchors.bottom: flickable.bottom
+ }
+ }
+ \endcode
+
+ Notice that ScrollBar does not filter key events of the Flickable it is
+ attached to. The following example illustrates how to implement scrolling
+ with up and down keys:
+
+ \code
+ Flickable {
+ focus: true
+
+ Keys.onUpPressed: scrollBar.decrease()
+ Keys.onDownPressed: scrollBar.increase()
+
+ ScrollBar.vertical: ScrollBar { id: scrollBar }
+ }
+ \endcode
+
+ \section1 Binding the Active State of Horizontal and Vertical Scroll Bars
+
+ Horizontal and vertical scroll bars do not share the \l active state with
+ each other by default. In order to keep both bars visible whilst scrolling
+ to either direction, establish a two-way binding between the active states
+ as presented by the following example:
+
+ \snippet qtquickcontrols2-scrollbar-active.qml 1
+
+ \section1 Non-attached Scroll Bars
+
+ It is possible to create an instance of ScrollBar without using the
+ attached property API. This is useful when the behavior of the attached
+ scroll bar is not sufficient or a \l Flickable is not in use. In the
+ following example, horizontal and vertical scroll bars are used to
+ scroll over the text without using \l Flickable:
+
+ \snippet qtquickcontrols2-scrollbar-non-attached.qml 1
+
+ \image qtquickcontrols2-scrollbar-non-attached.png
+
+ When using a non-attached ScrollBar, the following must be done manually:
+
+ \list
+ \li Layout the scroll bar (with the \l {Item::}{x} and \l {Item::}{y} or
+ \l {Item::}{anchors} property, for example).
+ \li Set the \l size and \l position properties to determine the size and position
+ of the scroll bar in relation to the scrolled item.
+ \li Set the \l active property to determine when the scroll bar will be
+ visible.
+ \endlist
+
+ \sa ScrollIndicator, ScrollView, {Customizing ScrollBar}, {Indicator Controls}
+*/
+
+static const QQuickItemPrivate::ChangeTypes changeTypes = QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed;
+static const QQuickItemPrivate::ChangeTypes horizontalChangeTypes = changeTypes | QQuickItemPrivate::ImplicitHeight;
+static const QQuickItemPrivate::ChangeTypes verticalChangeTypes = changeTypes | QQuickItemPrivate::ImplicitWidth;
+
+QQuickScrollBarPrivate::VisualArea QQuickScrollBarPrivate::visualArea() const
+{
+ qreal visualPos = position;
+
+ if (minimumSize > size && size != 1.0)
+ visualPos = position / (1.0 - size) * (1.0 - minimumSize);
+
+ qreal visualSize = qBound<qreal>(0, qMax(size, minimumSize) + qMin<qreal>(0, visualPos),
+ qMax(0.0, 1.0 - visualPos));
+
+ visualPos = qBound<qreal>(0, visualPos, 1.0 - visualSize);
+
+ return VisualArea(visualPos, visualSize);
+}
+
+qreal QQuickScrollBarPrivate::logicalPosition(qreal position) const
+{
+ if (minimumSize > size && minimumSize != 1.0)
+ return position * (1.0 - size) / (1.0 - minimumSize);
+ return position;
+}
+
+qreal QQuickScrollBarPrivate::snapPosition(qreal position) const
+{
+ const qreal effectiveStep = stepSize * (1.0 - size);
+ if (qFuzzyIsNull(effectiveStep))
+ return position;
+
+ return qRound(position / effectiveStep) * effectiveStep;
+}
+
+qreal QQuickScrollBarPrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickScrollBar);
+ if (orientation == Qt::Horizontal)
+ return logicalPosition(point.x() - q->leftPadding()) / q->availableWidth();
+ else
+ return logicalPosition(point.y() - q->topPadding()) / q->availableHeight();
+}
+
+void QQuickScrollBarPrivate::setInteractive(bool enabled)
+{
+ Q_Q(QQuickScrollBar);
+ if (interactive == enabled)
+ return;
+
+ interactive = enabled;
+ if (interactive) {
+ q->setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ q->setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ q->setCursor(Qt::ArrowCursor);
+#endif
+ } else {
+ q->setAcceptedMouseButtons(Qt::NoButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ q->setAcceptTouchEvents(false);
+#endif
+#if QT_CONFIG(cursor)
+ q->unsetCursor();
+#endif
+ q->ungrabMouse();
+ }
+ emit q->interactiveChanged();
+}
+
+void QQuickScrollBarPrivate::updateActive()
+{
+ Q_Q(QQuickScrollBar);
+#if QT_CONFIG(quicktemplates2_hover)
+ bool hover = hovered;
+#else
+ bool hover = false;
+#endif
+ q->setActive(moving || (interactive && (pressed || hover)));
+}
+
+void QQuickScrollBarPrivate::resizeContent()
+{
+ Q_Q(QQuickScrollBar);
+ if (!contentItem)
+ return;
+
+ // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size
+ // - positive overshoot (pos + size > 1): clamp the size to 1-pos
+ const VisualArea visual = visualArea();
+
+ if (orientation == Qt::Horizontal) {
+ contentItem->setPosition(QPointF(q->leftPadding() + visual.position * q->availableWidth(), q->topPadding()));
+ contentItem->setSize(QSizeF(q->availableWidth() * visual.size, q->availableHeight()));
+ } else {
+ contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + visual.position * q->availableHeight()));
+ contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * visual.size));
+ }
+}
+
+void QQuickScrollBarPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ QQuickIndicatorButton *indicatorButton = q->decreaseVisual();
+ if (!indicatorButton || item != indicatorButton->indicator()) {
+ indicatorButton = q->increaseVisual();
+ if (!indicatorButton || item != indicatorButton->indicator())
+ return;
+ }
+ if (indicatorButton)
+ emit indicatorButton->implicitIndicatorWidthChanged();
+}
+
+void QQuickScrollBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ QQuickIndicatorButton *indicatorButton = q->decreaseVisual();
+ if (!indicatorButton || item != indicatorButton->indicator()) {
+ indicatorButton = q->increaseVisual();
+ if (!indicatorButton || item != indicatorButton->indicator())
+ return;
+ }
+ if (indicatorButton)
+ emit indicatorButton->implicitIndicatorHeightChanged();
+}
+
+void QQuickScrollBarPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::handlePress(point);
+ if (QQuickIndicatorButton *indicatorButton = q->decreaseVisual()) {
+ QQuickItem *decreaseArrow = indicatorButton->indicator();
+ if (decreaseArrow && decreaseArrow->contains(q->mapToItem(decreaseArrow, point + QPointF(0.5, 0.5)))) {
+ indicatorButton->setPressed(true);
+ q->decrease();
+ return;
+ }
+ }
+
+ if (QQuickIndicatorButton *increaseObject = q->increaseVisual()) {
+ QQuickItem *increaseArrow = increaseObject->indicator();
+ if (increaseArrow && increaseArrow->contains(q->mapToItem(increaseArrow, point + QPointF(0.5, 0.5)))) {
+ increaseObject->setPressed(true);
+ q->increase();
+ return;
+ }
+ }
+
+ offset = positionAt(point) - position;
+ qreal sz = qMax(size, logicalPosition(minimumSize));
+ if (offset < 0 || offset > sz)
+ offset = sz / 2;
+ q->setPressed(true);
+}
+
+void QQuickScrollBarPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::handleMove(point);
+
+ /*
+ * handleMove() will be called as soon as you hold the mouse button down *anywhere* on the
+ * ScrollBar, including the increase/decrease button indicator areas. So without the following
+ * early return, it would move the scrollbar handle to one of its extremeties. That would
+ * ruin the behavior we would like when clicking e.g. the "increase button": To step the
+ * scrollbar gently.
+ */
+ if (!pressed)
+ return;
+ qreal pos = qBound<qreal>(0.0, positionAt(point) - offset, 1.0 - size);
+ if (snapMode == QQuickScrollBar::SnapAlways)
+ pos = snapPosition(pos);
+ q->setPosition(pos);
+}
+
+void QQuickScrollBarPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::handleRelease(point);
+
+ if (orientation == Qt::Vertical) {
+ if (point.y() < q->topPadding() || point.y() >= (q->height() - q->bottomPadding()))
+ return;
+ } else /* orientation == Qt::Horizontal */{
+ if (point.x() < q->leftPadding() || point.x() >= (q->width() - q->rightPadding()))
+ return;
+ }
+ qreal pos = qBound<qreal>(0.0, positionAt(point) - offset, 1.0 - size);
+ if (snapMode != QQuickScrollBar::NoSnap)
+ pos = snapPosition(pos);
+ q->setPosition(pos);
+ offset = 0.0;
+ q->setPressed(false);
+}
+
+void QQuickScrollBarPrivate::handleUngrab()
+{
+ Q_Q(QQuickScrollBar);
+ QQuickControlPrivate::handleUngrab();
+ offset = 0.0;
+ q->setPressed(false);
+}
+
+void QQuickScrollBarPrivate::visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea)
+{
+ Q_Q(QQuickScrollBar);
+ if (!qFuzzyCompare(newVisualArea.size, oldVisualArea.size))
+ emit q->visualSizeChanged();
+ if (!qFuzzyCompare(newVisualArea.position, oldVisualArea.position))
+ emit q->visualPositionChanged();
+}
+
+void QQuickScrollBarPrivate::updateHover(const QPointF &pos, std::optional<bool> newHoverState)
+{
+ Q_Q(QQuickScrollBar);
+ auto updateHoverOnButton = [&](QQuickIndicatorButton *sbButton) {
+ if (sbButton) {
+ bool hovered = newHoverState.value_or(false);
+ if (!newHoverState.has_value()) {
+ if (QQuickItem *indicator = sbButton->indicator())
+ hovered = indicator->contains(q->mapToItem(indicator, pos));
+ }
+ sbButton->setHovered(hovered);
+ }
+ };
+ updateHoverOnButton(q->decreaseVisual());
+ updateHoverOnButton(q->increaseVisual());
+}
+
+QQuickScrollBar::QQuickScrollBar(QQuickItem *parent)
+ : QQuickControl(*(new QQuickScrollBarPrivate), parent)
+{
+ Q_D(QQuickScrollBar);
+ d->decreaseVisual = new QQuickIndicatorButton(this);
+ d->increaseVisual = new QQuickIndicatorButton(this);
+ setKeepMouseGrab(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickScrollBarAttached *QQuickScrollBar::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickScrollBarAttached(object);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ScrollBar::size
+
+ This property holds the size of the scroll bar, scaled to \c {0.0 - 1.0}.
+
+ \sa {Flickable::visibleArea.heightRatio}{Flickable::visibleArea}
+
+ This property is automatically set when the scroll bar is
+ \l {Attaching ScrollBar to a Flickable}{attached to a flickable}.
+
+ \sa minimumSize, visualSize
+*/
+qreal QQuickScrollBar::size() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->size;
+}
+
+void QQuickScrollBar::setSize(qreal size)
+{
+ Q_D(QQuickScrollBar);
+ if (!qt_is_finite(size) || qFuzzyCompare(d->size, size))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->size = qBound(0.0, size, 1.0);
+ if (isComponentComplete())
+ d->resizeContent();
+ emit sizeChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ScrollBar::position
+
+ This property holds the position of the scroll bar, scaled to \c {0.0 - 1.0}.
+
+ \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea}
+
+ This property is automatically set when the scroll bar is
+ \l {Attaching ScrollBar to a Flickable}{attached to a flickable}.
+
+ \sa visualPosition
+*/
+qreal QQuickScrollBar::position() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->position;
+}
+
+void QQuickScrollBar::setPosition(qreal position)
+{
+ Q_D(QQuickScrollBar);
+ if (!qt_is_finite(position) || qFuzzyCompare(d->position, position))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->position = position;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit positionChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ScrollBar::stepSize
+
+ This property holds the step size. The default value is \c 0.0.
+
+ \sa snapMode, increase(), decrease()
+*/
+qreal QQuickScrollBar::stepSize() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->stepSize;
+}
+
+void QQuickScrollBar::setStepSize(qreal step)
+{
+ Q_D(QQuickScrollBar);
+ if (!qt_is_finite(step) || qFuzzyCompare(d->stepSize, step))
+ return;
+
+ d->stepSize = step;
+ emit stepSizeChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ScrollBar::active
+
+ This property holds whether the scroll bar is active, i.e. when it's \l pressed
+ or the attached Flickable is \l {Flickable::moving}{moving}.
+
+ It is possible to keep \l {Binding the Active State of Horizontal and Vertical Scroll Bars}
+ {both horizontal and vertical bars visible} while scrolling in either direction.
+
+ This property is automatically set when the scroll bar is
+ \l {Attaching ScrollBar to a Flickable}{attached to a flickable}.
+*/
+bool QQuickScrollBar::isActive() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->active;
+}
+
+void QQuickScrollBar::setActive(bool active)
+{
+ Q_D(QQuickScrollBar);
+ if (d->active == active)
+ return;
+
+ d->active = active;
+ emit activeChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ScrollBar::pressed
+
+ This property holds whether the scroll bar is pressed.
+*/
+bool QQuickScrollBar::isPressed() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->pressed;
+}
+
+void QQuickScrollBar::setPressed(bool pressed)
+{
+ Q_D(QQuickScrollBar);
+ if (!pressed) {
+ if (QQuickIndicatorButton *button = decreaseVisual())
+ button->setPressed(false);
+ if (QQuickIndicatorButton *button = increaseVisual())
+ button->setPressed(false);
+ }
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ setAccessibleProperty("pressed", pressed);
+ d->updateActive();
+ emit pressedChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::ScrollBar::orientation
+
+ This property holds the orientation of the scroll bar.
+
+ Possible values:
+ \value Qt.Horizontal Horizontal
+ \value Qt.Vertical Vertical (default)
+
+ This property is automatically set when the scroll bar is
+ \l {Attaching ScrollBar to a Flickable}{attached to a flickable}.
+
+ \sa horizontal, vertical
+*/
+Qt::Orientation QQuickScrollBar::orientation() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->orientation;
+}
+
+void QQuickScrollBar::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickScrollBar);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit orientationChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty enumeration QtQuick.Controls::ScrollBar::snapMode
+
+ This property holds the snap mode.
+
+ Possible values:
+ \value ScrollBar.NoSnap The scrollbar does not snap (default).
+ \value ScrollBar.SnapAlways The scrollbar snaps while dragged.
+ \value ScrollBar.SnapOnRelease The scrollbar does not snap while being dragged, but only after released.
+
+ In the following table, the various modes are illustrated with animations.
+ The movement and the \l stepSize (\c 0.25) are identical in each animation.
+
+ \table
+ \header
+ \row \li \b Value \li \b Example
+ \row \li \c ScrollBar.NoSnap \li \image qtquickcontrols2-scrollbar-nosnap.gif
+ \row \li \c ScrollBar.SnapAlways \li \image qtquickcontrols2-scrollbar-snapalways.gif
+ \row \li \c ScrollBar.SnapOnRelease \li \image qtquickcontrols2-scrollbar-snaponrelease.gif
+ \endtable
+
+ \sa stepSize
+*/
+QQuickScrollBar::SnapMode QQuickScrollBar::snapMode() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->snapMode;
+}
+
+void QQuickScrollBar::setSnapMode(SnapMode mode)
+{
+ Q_D(QQuickScrollBar);
+ if (d->snapMode == mode)
+ return;
+
+ d->snapMode = mode;
+ emit snapModeChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::ScrollBar::interactive
+
+ This property holds whether the scroll bar is interactive. The default value is \c true.
+
+ A non-interactive scroll bar is visually and behaviorally similar to \l ScrollIndicator.
+ This property is useful for switching between typical mouse- and touch-orientated UIs
+ with interactive and non-interactive scroll bars, respectively.
+*/
+bool QQuickScrollBar::isInteractive() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->interactive;
+}
+
+void QQuickScrollBar::setInteractive(bool interactive)
+{
+ Q_D(QQuickScrollBar);
+ d->explicitInteractive = true;
+ d->setInteractive(interactive);
+}
+
+void QQuickScrollBar::resetInteractive()
+{
+ Q_D(QQuickScrollBar);
+ d->explicitInteractive = false;
+ d->setInteractive(true);
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty enumeration QtQuick.Controls::ScrollBar::policy
+
+ This property holds the policy of the scroll bar. The default policy is \c ScrollBar.AsNeeded.
+
+ Possible values:
+ \value ScrollBar.AsNeeded The scroll bar is only shown when the content is too large to fit.
+ \value ScrollBar.AlwaysOff The scroll bar is never shown.
+ \value ScrollBar.AlwaysOn The scroll bar is always shown.
+
+ The following example keeps the vertical scroll bar always visible:
+
+ \snippet qtquickcontrols2-scrollbar-policy.qml 1
+*/
+QQuickScrollBar::Policy QQuickScrollBar::policy() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->policy;
+}
+
+void QQuickScrollBar::setPolicy(Policy policy)
+{
+ Q_D(QQuickScrollBar);
+ if (d->policy == policy)
+ return;
+
+ d->policy = policy;
+ emit policyChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::ScrollBar::horizontal
+ \readonly
+
+ This property holds whether the scroll bar is horizontal.
+
+ \sa orientation
+*/
+bool QQuickScrollBar::isHorizontal() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::ScrollBar::vertical
+ \readonly
+
+ This property holds whether the scroll bar is vertical.
+
+ \sa orientation
+*/
+bool QQuickScrollBar::isVertical() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->orientation == Qt::Vertical;
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollBar::minimumSize
+
+ This property holds the minimum size of the scroll bar, scaled to \c {0.0 - 1.0}.
+
+ \sa size, visualSize, visualPosition
+*/
+qreal QQuickScrollBar::minimumSize() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->minimumSize;
+}
+
+void QQuickScrollBar::setMinimumSize(qreal minimumSize)
+{
+ Q_D(QQuickScrollBar);
+ if (!qt_is_finite(minimumSize) || qFuzzyCompare(d->minimumSize, minimumSize))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->minimumSize = qBound(0.0, minimumSize, 1.0);
+ if (isComponentComplete())
+ d->resizeContent();
+ emit minimumSizeChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollBar::visualSize
+
+ This property holds the effective visual size of the scroll bar,
+ which may be limited by the \l {minimumSize}{minimum size}.
+
+ \sa size, minimumSize
+*/
+qreal QQuickScrollBar::visualSize() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->visualArea().size;
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollBar::visualPosition
+
+ This property holds the effective visual position of the scroll bar,
+ which may be limited by the \l {minimumSize}{minimum size}.
+
+ \sa position, minimumSize
+*/
+qreal QQuickScrollBar::visualPosition() const
+{
+ Q_D(const QQuickScrollBar);
+ return d->visualArea().position;
+}
+
+QQuickIndicatorButton *QQuickScrollBar::decreaseVisual()
+{
+ Q_D(QQuickScrollBar);
+ return d->decreaseVisual;
+}
+
+QQuickIndicatorButton *QQuickScrollBar::increaseVisual()
+{
+ Q_D(QQuickScrollBar);
+ return d->increaseVisual;
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ScrollBar::increase()
+
+ Increases the position by \l stepSize or \c 0.1 if stepSize is \c 0.0.
+
+ \sa stepSize
+*/
+void QQuickScrollBar::increase()
+{
+ Q_D(QQuickScrollBar);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ bool wasActive = d->active;
+ setActive(true);
+ setPosition(qMin<qreal>(1.0 - d->size, d->position + step));
+ setActive(wasActive);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::ScrollBar::decrease()
+
+ Decreases the position by \l stepSize or \c 0.1 if stepSize is \c 0.0.
+
+ \sa stepSize
+*/
+void QQuickScrollBar::decrease()
+{
+ Q_D(QQuickScrollBar);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ bool wasActive = d->active;
+ setActive(true);
+ setPosition(qMax<qreal>(0.0, d->position - step));
+ setActive(wasActive);
+}
+
+void QQuickScrollBar::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickScrollBar);
+ QQuickControl::mousePressEvent(event);
+ d->handleMove(event->position());
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickScrollBar::hoverChange()
+{
+ Q_D(QQuickScrollBar);
+ d->updateActive();
+}
+
+void QQuickScrollBar::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickScrollBar);
+ QQuickControl::hoverEnterEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickScrollBar::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickScrollBar);
+ QQuickControl::hoverMoveEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickScrollBar::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickScrollBar);
+ QQuickControl::hoverLeaveEvent(event);
+
+ d->updateHover(QPoint(), false); //position is not needed when we force it to unhover
+ event->ignore();
+}
+#endif
+
+void QQuickScrollBar::classBegin()
+{
+ Q_D(QQuickScrollBar);
+ QQuickControl::classBegin();
+
+ QQmlContext *context = qmlContext(this);
+ if (context) {
+ QQmlEngine::setContextForObject(d->decreaseVisual, context);
+ QQmlEngine::setContextForObject(d->increaseVisual, context);
+ }
+}
+
+void QQuickScrollBar::componentComplete()
+{
+ Q_D(QQuickScrollBar);
+ QQuickIndicatorButtonPrivate::get(d->decreaseVisual)->executeIndicator(true);
+ QQuickIndicatorButtonPrivate::get(d->increaseVisual)->executeIndicator(true);
+
+ QQuickControl::componentComplete();
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickScrollBar::accessibilityActiveChanged(bool active)
+{
+ QQuickControl::accessibilityActiveChanged(active);
+
+ Q_D(QQuickScrollBar);
+ if (active) {
+ setAccessibleProperty("pressed", d->pressed);
+
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this)) {
+ connect(accessibleAttached, &QQuickAccessibleAttached::increaseAction, this, &QQuickScrollBar::increase);
+ connect(accessibleAttached, &QQuickAccessibleAttached::decreaseAction, this, &QQuickScrollBar::decrease);
+ }
+ } else {
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this)) {
+ disconnect(accessibleAttached, &QQuickAccessibleAttached::increaseAction, this, &QQuickScrollBar::increase);
+ disconnect(accessibleAttached, &QQuickAccessibleAttached::decreaseAction, this, &QQuickScrollBar::decrease);
+ }
+ }
+}
+
+QAccessible::Role QQuickScrollBar::accessibleRole() const
+{
+ return QAccessible::ScrollBar;
+}
+#endif
+
+void QQuickScrollBarAttachedPrivate::setFlickable(QQuickFlickable *item)
+{
+ if (flickable) {
+ // NOTE: Use removeItemChangeListener(Geometry) instead of updateOrRemoveGeometryChangeListener(Size).
+ // The latter doesn't remove the listener but only resets its types. Thus, it leaves behind a dangling
+ // pointer on destruction.
+ QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
+ QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ if (horizontal)
+ cleanupHorizontal();
+ if (vertical)
+ cleanupVertical();
+ }
+
+ flickable = item;
+
+ if (item) {
+ // Don't know how to combine these calls into one, and as long as they're separate calls,
+ // the remove* calls above need to be separate too, otherwise they will have no effect.
+ QQuickItemPrivate::get(item)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size);
+ QQuickItemPrivate::get(item)->updateOrAddItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ if (horizontal)
+ initHorizontal();
+ if (vertical)
+ initVertical();
+ }
+}
+
+void QQuickScrollBarAttachedPrivate::initHorizontal()
+{
+ Q_ASSERT(flickable && horizontal);
+
+ connect(flickable, &QQuickFlickable::movingHorizontallyChanged, this, &QQuickScrollBarAttachedPrivate::activateHorizontal);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = flickable->property("visibleArea").value<QObject *>();
+ QObject::connect(area, SIGNAL(widthRatioChanged(qreal)), horizontal, SLOT(setSize(qreal)));
+ QObject::connect(area, SIGNAL(xPositionChanged(qreal)), horizontal, SLOT(setPosition(qreal)));
+
+ // ensure that the ScrollBar is stacked above the Flickable in a ScrollView
+ QQuickItem *parent = horizontal->parentItem();
+ if (parent && parent == flickable->parentItem())
+ horizontal->stackAfter(flickable);
+
+ // If a scroll bar was previously hidden (due to e.g. setting a new contentItem
+ // on a ScrollView), we need to make sure that we un-hide it.
+ // We don't bother checking if the item is actually the old one, because
+ // if it's not, all of the things the function does (setting parent, visibility, etc.)
+ // should be no-ops anyway.
+ if (auto control = qobject_cast<QQuickControl*>(q_func()->parent()))
+ QQuickControlPrivate::unhideOldItem(control, horizontal);
+
+ layoutHorizontal();
+ horizontal->setSize(area->property("widthRatio").toReal());
+ horizontal->setPosition(area->property("xPosition").toReal());
+}
+
+void QQuickScrollBarAttachedPrivate::initVertical()
+{
+ Q_ASSERT(flickable && vertical);
+
+ connect(flickable, &QQuickFlickable::movingVerticallyChanged, this, &QQuickScrollBarAttachedPrivate::activateVertical);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = flickable->property("visibleArea").value<QObject *>();
+ QObject::connect(area, SIGNAL(heightRatioChanged(qreal)), vertical, SLOT(setSize(qreal)));
+ QObject::connect(area, SIGNAL(yPositionChanged(qreal)), vertical, SLOT(setPosition(qreal)));
+
+ // ensure that the ScrollBar is stacked above the Flickable in a ScrollView
+ QQuickItem *parent = vertical->parentItem();
+ if (parent && parent == flickable->parentItem())
+ vertical->stackAfter(flickable);
+
+ if (auto control = qobject_cast<QQuickControl*>(q_func()->parent()))
+ QQuickControlPrivate::unhideOldItem(control, vertical);
+
+ layoutVertical();
+ vertical->setSize(area->property("heightRatio").toReal());
+ vertical->setPosition(area->property("yPosition").toReal());
+}
+
+void QQuickScrollBarAttachedPrivate::cleanupHorizontal()
+{
+ Q_ASSERT(flickable && horizontal);
+
+ QQuickControlPrivate::hideOldItem(horizontal);
+ // ScrollBar.qml has a binding to visible and ScrollView.qml has a binding to parent.
+ // If we just set visible to false and parent to null, these bindings will overwrite
+ // them upon component completion as part of the binding evaluation.
+ // That's why we remove the binding completely.
+ const QQmlProperty visibleProperty(horizontal, QStringLiteral("visible"));
+ const QQmlProperty parentProperty(horizontal, QStringLiteral("parent"));
+ QQmlPropertyPrivate::removeBinding(visibleProperty);
+ QQmlPropertyPrivate::removeBinding(parentProperty);
+
+ disconnect(flickable, &QQuickFlickable::movingHorizontallyChanged, this, &QQuickScrollBarAttachedPrivate::activateHorizontal);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = flickable->property("visibleArea").value<QObject *>();
+ QObject::disconnect(area, SIGNAL(widthRatioChanged(qreal)), horizontal, SLOT(setSize(qreal)));
+ QObject::disconnect(area, SIGNAL(xPositionChanged(qreal)), horizontal, SLOT(setPosition(qreal)));
+}
+
+void QQuickScrollBarAttachedPrivate::cleanupVertical()
+{
+ Q_ASSERT(flickable && vertical);
+
+ QQuickControlPrivate::hideOldItem(vertical);
+ const QQmlProperty visibleProperty(vertical, QStringLiteral("visible"));
+ const QQmlProperty parentProperty(vertical, QStringLiteral("parent"));
+ QQmlPropertyPrivate::removeBinding(visibleProperty);
+ QQmlPropertyPrivate::removeBinding(parentProperty);
+
+ disconnect(flickable, &QQuickFlickable::movingVerticallyChanged, this, &QQuickScrollBarAttachedPrivate::activateVertical);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = flickable->property("visibleArea").value<QObject *>();
+ QObject::disconnect(area, SIGNAL(heightRatioChanged(qreal)), vertical, SLOT(setSize(qreal)));
+ QObject::disconnect(area, SIGNAL(yPositionChanged(qreal)), vertical, SLOT(setPosition(qreal)));
+}
+
+void QQuickScrollBarAttachedPrivate::activateHorizontal()
+{
+ QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(horizontal);
+ p->moving = flickable->isMovingHorizontally();
+ p->updateActive();
+}
+
+void QQuickScrollBarAttachedPrivate::activateVertical()
+{
+ QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(vertical);
+ p->moving = flickable->isMovingVertically();
+ p->updateActive();
+}
+
+// TODO: QQuickFlickable::maxXYExtent()
+class QQuickFriendlyFlickable : public QQuickFlickable
+{
+ friend class QQuickScrollBarAttachedPrivate;
+};
+
+void QQuickScrollBarAttachedPrivate::scrollHorizontal()
+{
+ if (!flickable)
+ return;
+
+ QQuickFriendlyFlickable *f = reinterpret_cast<QQuickFriendlyFlickable *>(flickable);
+
+ const qreal viewwidth = f->width();
+ const qreal maxxextent = -f->maxXExtent() + f->minXExtent();
+ const qreal cx = horizontal->position() * (maxxextent + viewwidth) - f->minXExtent();
+
+ if (!qIsNaN(cx) && !qFuzzyCompare(cx, flickable->contentX()))
+ flickable->setContentX(cx);
+}
+
+void QQuickScrollBarAttachedPrivate::scrollVertical()
+{
+ if (!flickable)
+ return;
+
+ QQuickFriendlyFlickable *f = reinterpret_cast<QQuickFriendlyFlickable *>(flickable);
+
+ const qreal viewheight = f->height();
+ const qreal maxyextent = -f->maxYExtent() + f->minYExtent();
+ const qreal cy = vertical->position() * (maxyextent + viewheight) - f->minYExtent();
+
+ if (!qIsNaN(cy) && !qFuzzyCompare(cy, flickable->contentY()))
+ flickable->setContentY(cy);
+}
+
+void QQuickScrollBarAttachedPrivate::mirrorVertical()
+{
+ layoutVertical(true);
+}
+
+void QQuickScrollBarAttachedPrivate::layoutHorizontal(bool move)
+{
+ Q_ASSERT(horizontal && flickable);
+ if (horizontal->parentItem() != flickable)
+ return;
+ horizontal->setWidth(flickable->width());
+ if (move)
+ horizontal->setY(flickable->height() - horizontal->height());
+}
+
+void QQuickScrollBarAttachedPrivate::layoutVertical(bool move)
+{
+ Q_ASSERT(vertical && flickable);
+ if (vertical->parentItem() != flickable)
+ return;
+ vertical->setHeight(flickable->height());
+ if (move)
+ vertical->setX(vertical->isMirrored() ? 0 : flickable->width() - vertical->width());
+}
+
+void QQuickScrollBarAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(change);
+ if (horizontal && horizontal->height() > 0) {
+#ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), diff.height() - horizontal->height());
+#else
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), item->height() - diff.height() - horizontal->height());
+#endif
+ if (flickable)
+ layoutHorizontal(move);
+ }
+ if (vertical && vertical->width() > 0) {
+#ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), diff.width() - vertical->width());
+#else
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), item->width() - diff.width() - vertical->width());
+#endif
+ if (flickable)
+ layoutVertical(move);
+ }
+}
+
+void QQuickScrollBarAttachedPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ if (item == vertical && flickable)
+ layoutVertical(true);
+}
+
+void QQuickScrollBarAttachedPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ if (item == horizontal && flickable)
+ layoutHorizontal(true);
+}
+
+void QQuickScrollBarAttachedPrivate::itemDestroyed(QQuickItem *item)
+{
+ if (item == flickable)
+ flickable = nullptr;
+ if (item == horizontal)
+ horizontal = nullptr;
+ if (item == vertical)
+ vertical = nullptr;
+}
+
+QQuickScrollBarAttached::QQuickScrollBarAttached(QObject *parent)
+ : QObject(*(new QQuickScrollBarAttachedPrivate), parent)
+{
+ Q_D(QQuickScrollBarAttached);
+ d->setFlickable(qobject_cast<QQuickFlickable *>(parent));
+
+ if (parent && !d->flickable && !qobject_cast<QQuickScrollView *>(parent))
+ qmlWarning(parent) << "ScrollBar must be attached to a Flickable or ScrollView";
+}
+
+QQuickScrollBarAttached::~QQuickScrollBarAttached()
+{
+ Q_D(QQuickScrollBarAttached);
+ if (d->horizontal) {
+ QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, horizontalChangeTypes);
+ d->horizontal = nullptr;
+ }
+ if (d->vertical) {
+ QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, verticalChangeTypes);
+ d->vertical = nullptr;
+ }
+ d->setFlickable(nullptr);
+}
+
+/*!
+ \qmlattachedproperty ScrollBar QtQuick.Controls::ScrollBar::horizontal
+
+ This property attaches a horizontal scroll bar to a \l Flickable.
+
+ \code
+ Flickable {
+ contentWidth: 2000
+ ScrollBar.horizontal: ScrollBar { }
+ }
+ \endcode
+
+ \sa {Attaching ScrollBar to a Flickable}
+*/
+QQuickScrollBar *QQuickScrollBarAttached::horizontal() const
+{
+ Q_D(const QQuickScrollBarAttached);
+ return d->horizontal;
+}
+
+void QQuickScrollBarAttached::setHorizontal(QQuickScrollBar *horizontal)
+{
+ Q_D(QQuickScrollBarAttached);
+ if (d->horizontal == horizontal)
+ return;
+
+ if (d->horizontal) {
+ QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, horizontalChangeTypes);
+ QObjectPrivate::disconnect(d->horizontal, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollHorizontal);
+
+ if (d->flickable)
+ d->cleanupHorizontal();
+ }
+
+ d->horizontal = horizontal;
+
+ if (horizontal) {
+ if (!horizontal->parentItem())
+ horizontal->setParentItem(qobject_cast<QQuickItem *>(parent()));
+ horizontal->setOrientation(Qt::Horizontal);
+
+ QQuickItemPrivate::get(horizontal)->addItemChangeListener(d, horizontalChangeTypes);
+ QObjectPrivate::connect(horizontal, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollHorizontal);
+
+ if (d->flickable)
+ d->initHorizontal();
+ }
+ emit horizontalChanged();
+}
+
+/*!
+ \qmlattachedproperty ScrollBar QtQuick.Controls::ScrollBar::vertical
+
+ This property attaches a vertical scroll bar to a \l Flickable.
+
+ \code
+ Flickable {
+ contentHeight: 2000
+ ScrollBar.vertical: ScrollBar { }
+ }
+ \endcode
+
+ \sa {Attaching ScrollBar to a Flickable}
+*/
+QQuickScrollBar *QQuickScrollBarAttached::vertical() const
+{
+ Q_D(const QQuickScrollBarAttached);
+ return d->vertical;
+}
+
+void QQuickScrollBarAttached::setVertical(QQuickScrollBar *vertical)
+{
+ Q_D(QQuickScrollBarAttached);
+ if (d->vertical == vertical)
+ return;
+
+ if (d->vertical) {
+ QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, verticalChangeTypes);
+ QObjectPrivate::disconnect(d->vertical, &QQuickScrollBar::mirroredChanged, d, &QQuickScrollBarAttachedPrivate::mirrorVertical);
+ QObjectPrivate::disconnect(d->vertical, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollVertical);
+
+ if (d->flickable)
+ d->cleanupVertical();
+ }
+
+ d->vertical = vertical;
+
+ if (vertical) {
+ if (!vertical->parentItem())
+ vertical->setParentItem(qobject_cast<QQuickItem *>(parent()));
+ vertical->setOrientation(Qt::Vertical);
+
+ QQuickItemPrivate::get(vertical)->addItemChangeListener(d, verticalChangeTypes);
+ QObjectPrivate::connect(vertical, &QQuickScrollBar::mirroredChanged, d, &QQuickScrollBarAttachedPrivate::mirrorVertical);
+ QObjectPrivate::connect(vertical, &QQuickScrollBar::positionChanged, d, &QQuickScrollBarAttachedPrivate::scrollVertical);
+
+ if (d->flickable)
+ d->initVertical();
+ }
+ emit verticalChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickscrollbar_p.cpp"
diff --git a/src/quicktemplates2/qquickscrollbar_p.h b/src/quicktemplates2/qquickscrollbar_p.h
new file mode 100644
index 0000000000..b7de290b24
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollbar_p.h
@@ -0,0 +1,222 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSCROLLBAR_P_H
+#define QQUICKSCROLLBAR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQuickTemplates2/private/qquickindicatorbutton_p.h>
+QT_BEGIN_NAMESPACE
+
+class QQuickScrollBarAttached;
+class QQuickScrollBarPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollBar : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged FINAL)
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive RESET resetInteractive NOTIFY interactiveChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(Policy policy READ policy WRITE setPolicy NOTIFY policyChanged FINAL REVISION(2, 2))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION(2, 3))
+ // 2.4 (Qt 5.11)
+ Q_PROPERTY(qreal minimumSize READ minimumSize WRITE setMinimumSize NOTIFY minimumSizeChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal visualSize READ visualSize NOTIFY visualSizeChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL REVISION(2, 4))
+
+ Q_PROPERTY(QQuickIndicatorButton *__decreaseVisual READ decreaseVisual CONSTANT FINAL)
+ Q_PROPERTY(QQuickIndicatorButton *__increaseVisual READ increaseVisual CONSTANT FINAL)
+
+ QML_NAMED_ELEMENT(ScrollBar)
+ QML_ATTACHED(QQuickScrollBarAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickScrollBar(QQuickItem *parent = nullptr);
+
+ static QQuickScrollBarAttached *qmlAttachedProperties(QObject *object);
+
+ qreal size() const;
+ qreal position() const;
+
+ qreal stepSize() const;
+ void setStepSize(qreal step);
+
+ bool isActive() const;
+ void setActive(bool active);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ // 2.2 (Qt 5.9)
+ enum SnapMode {
+ NoSnap,
+ SnapAlways,
+ SnapOnRelease
+ };
+ Q_ENUM(SnapMode)
+
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ bool isInteractive() const;
+ void setInteractive(bool interactive);
+ void resetInteractive();
+
+ enum Policy {
+ AsNeeded = Qt::ScrollBarAsNeeded,
+ AlwaysOff = Qt::ScrollBarAlwaysOff,
+ AlwaysOn = Qt::ScrollBarAlwaysOn
+ };
+ Q_ENUM(Policy)
+
+ Policy policy() const;
+ void setPolicy(Policy policy);
+
+ // 2.3 (Qt 5.10)
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+ // 2.4 (Qt 5.11)
+ qreal minimumSize() const;
+ void setMinimumSize(qreal minimumSize);
+
+ qreal visualSize() const;
+ qreal visualPosition() const;
+
+ QQuickIndicatorButton *decreaseVisual();
+ QQuickIndicatorButton *increaseVisual();
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+ void setSize(qreal size);
+ void setPosition(qreal position);
+
+Q_SIGNALS:
+ void sizeChanged();
+ void positionChanged();
+ void stepSizeChanged();
+ void activeChanged();
+ void pressedChanged();
+ void orientationChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void snapModeChanged();
+ Q_REVISION(2, 2) void interactiveChanged();
+ Q_REVISION(2, 2) void policyChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void minimumSizeChanged();
+ Q_REVISION(2, 4) void visualSizeChanged();
+ Q_REVISION(2, 4) void visualPositionChanged();
+
+protected:
+ void mousePressEvent(QMouseEvent *event) override;
+
+#if QT_CONFIG(quicktemplates2_hover)
+ void hoverChange() override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+#endif
+
+ void classBegin() override;
+ void componentComplete() override;
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickScrollBar)
+ Q_DECLARE_PRIVATE(QQuickScrollBar)
+};
+
+class QQuickScrollBarAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollBarAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickScrollBar *horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged FINAL)
+ Q_PROPERTY(QQuickScrollBar *vertical READ vertical WRITE setVertical NOTIFY verticalChanged FINAL)
+
+public:
+ explicit QQuickScrollBarAttached(QObject *parent = nullptr);
+ ~QQuickScrollBarAttached();
+
+ QQuickScrollBar *horizontal() const;
+ void setHorizontal(QQuickScrollBar *horizontal);
+
+ QQuickScrollBar *vertical() const;
+ void setVertical(QQuickScrollBar *vertical);
+
+Q_SIGNALS:
+ void horizontalChanged();
+ void verticalChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickScrollBarAttached)
+ Q_DECLARE_PRIVATE(QQuickScrollBarAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickScrollBar)
+QML_DECLARE_TYPEINFO(QQuickScrollBar, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKSCROLLBAR_P_H
diff --git a/src/quicktemplates2/qquickscrollbar_p_p.h b/src/quicktemplates2/qquickscrollbar_p_p.h
new file mode 100644
index 0000000000..70da611f0e
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollbar_p_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSCROLLBAR_P_P_H
+#define QQUICKSCROLLBAR_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 <QtQuickTemplates2/private/qquickscrollbar_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFlickable;
+class QQuickIndicatorButton;
+
+class QQuickScrollBarPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickScrollBar)
+
+public:
+ static QQuickScrollBarPrivate *get(QQuickScrollBar *bar)
+ {
+ return bar->d_func();
+ }
+
+ struct VisualArea
+ {
+ VisualArea(qreal pos, qreal sz)
+ : position(pos), size(sz) { }
+ qreal position = 0;
+ qreal size = 0;
+ };
+ VisualArea visualArea() const;
+
+ qreal logicalPosition(qreal position) const;
+
+ qreal snapPosition(qreal position) const;
+ qreal positionAt(const QPointF &point) const;
+ void setInteractive(bool interactive);
+ void updateActive();
+ void resizeContent() override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea);
+
+ void updateHover(const QPointF &pos, std::optional<bool> newHoverState = {});
+
+ QQuickIndicatorButton *decreaseVisual = nullptr;
+ QQuickIndicatorButton *increaseVisual = nullptr;
+ qreal size = 0;
+ qreal position = 0;
+ qreal stepSize = 0;
+ qreal offset = 0;
+ qreal minimumSize = 0;
+ bool active = false;
+ bool pressed = false;
+ bool moving = false;
+ bool interactive = true;
+ bool explicitInteractive = false;
+ Qt::Orientation orientation = Qt::Vertical;
+ QQuickScrollBar::SnapMode snapMode = QQuickScrollBar::NoSnap;
+ QQuickScrollBar::Policy policy = QQuickScrollBar::AsNeeded;
+};
+
+class QQuickScrollBarAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickScrollBarAttached)
+
+public:
+ static QQuickScrollBarAttachedPrivate *get(QQuickScrollBarAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void setFlickable(QQuickFlickable *flickable);
+
+ void initHorizontal();
+ void initVertical();
+ void cleanupHorizontal();
+ void cleanupVertical();
+ void activateHorizontal();
+ void activateVertical();
+ void scrollHorizontal();
+ void scrollVertical();
+ void mirrorVertical();
+
+ void layoutHorizontal(bool move = true);
+ void layoutVertical(bool move = true);
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QQuickFlickable *flickable = nullptr;
+ QQuickScrollBar *horizontal = nullptr;
+ QQuickScrollBar *vertical = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSCROLLBAR_P_P_H
diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp
new file mode 100644
index 0000000000..1e7efc6bde
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollindicator.cpp
@@ -0,0 +1,667 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickscrollindicator_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ScrollIndicator
+ \inherits Control
+//! \instantiates QQuickScrollIndicator
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-indicators
+ \brief Vertical or horizontal non-interactive scroll indicator.
+
+ \image qtquickcontrols2-scrollindicator.gif
+
+ ScrollIndicator is a non-interactive indicator that indicates the current scroll
+ position. A scroll indicator can be either \l vertical or \l horizontal, and can
+ be attached to any \l Flickable, such as \l ListView and \l GridView.
+
+ \code
+ Flickable {
+ // ...
+ ScrollIndicator.vertical: ScrollIndicator { }
+ }
+ \endcode
+
+ \section1 Attaching ScrollIndicator to a Flickable
+
+ \note When ScrollIndicator is attached \l {ScrollIndicator::vertical}{vertically}
+ or \l {ScrollIndicator::horizontal}{horizontally} to a Flickable, its geometry and
+ the following properties are automatically set and updated as appropriate:
+
+ \list
+ \li \l orientation
+ \li \l position
+ \li \l size
+ \li \l active
+ \endlist
+
+ An attached ScrollIndicator re-parents itself to the target Flickable. A vertically
+ attached ScrollIndicator resizes itself to the height of the Flickable, and positions
+ itself to either side of it based on the \l {Control::mirrored}{layout direction}.
+ A horizontally attached ScrollIndicator resizes itself to the width of the Flickable,
+ and positions itself to the bottom. The automatic geometry management can be disabled
+ by specifying another parent for the attached ScrollIndicator. This can be useful, for
+ example, if the ScrollIndicator should be placed outside a clipping Flickable. This is
+ demonstrated by the following example:
+
+ \code
+ Flickable {
+ id: flickable
+ clip: true
+ // ...
+ ScrollIndicator.vertical: ScrollIndicator {
+ parent: flickable.parent
+ anchors.top: flickable.top
+ anchors.left: flickable.right
+ anchors.bottom: flickable.bottom
+ }
+ }
+ \endcode
+
+ \section1 Binding the Active State of Horizontal and Vertical Scroll Indicators
+
+ Horizontal and vertical scroll indicators do not share the \l active state with
+ each other by default. In order to keep both indicators visible whilst scrolling
+ to either direction, establish a two-way binding between the active states as
+ presented by the following example:
+
+ \snippet qtquickcontrols2-scrollindicator-active.qml 1
+
+ \section1 Non-attached Scroll Indicators
+
+ It is possible to create an instance of ScrollIndicator without using the
+ attached property API. This is useful when the behavior of the attached
+ scoll indicator is not sufficient or a \l Flickable is not in use. In the
+ following example, horizontal and vertical scroll indicators are used to
+ indicate how far the user has scrolled over the text (using \l MouseArea
+ instead of \l Flickable):
+
+ \snippet qtquickcontrols2-scrollindicator-non-attached.qml 1
+
+ \image qtquickcontrols2-scrollindicator-non-attached.png
+
+ \sa ScrollBar, {Customizing ScrollIndicator}, {Indicator Controls}
+*/
+
+static const QQuickItemPrivate::ChangeTypes changeTypes = QQuickItemPrivate::Geometry | QQuickItemPrivate::Destroyed;
+static const QQuickItemPrivate::ChangeTypes horizontalChangeTypes = changeTypes | QQuickItemPrivate::ImplicitHeight;
+static const QQuickItemPrivate::ChangeTypes verticalChangeTypes = changeTypes | QQuickItemPrivate::ImplicitWidth;
+
+class QQuickScrollIndicatorPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickScrollIndicator)
+
+public:
+ struct VisualArea
+ {
+ VisualArea(qreal pos, qreal sz)
+ : position(pos), size(sz) { }
+ qreal position = 0;
+ qreal size = 0;
+ };
+ VisualArea visualArea() const;
+ void visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea);
+
+ void resizeContent() override;
+
+ qreal size = 0;
+ qreal minimumSize = 0;
+ qreal position = 0;
+ bool active = false;
+ Qt::Orientation orientation = Qt::Vertical;
+};
+
+QQuickScrollIndicatorPrivate::VisualArea QQuickScrollIndicatorPrivate::visualArea() const
+{
+ qreal visualPos = position;
+ if (minimumSize > size)
+ visualPos = position / (1.0 - size) * (1.0 - minimumSize);
+
+ qreal visualSize = qBound<qreal>(0, qMax(size, minimumSize) + qMin<qreal>(0, visualPos), 1.0 - visualPos);
+
+ visualPos = qBound<qreal>(0, visualPos, 1.0 - visualSize);
+
+ return VisualArea(visualPos, visualSize);
+}
+
+void QQuickScrollIndicatorPrivate::visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea)
+{
+ Q_Q(QQuickScrollIndicator);
+ if (!qFuzzyCompare(newVisualArea.size, oldVisualArea.size))
+ emit q->visualSizeChanged();
+ if (!qFuzzyCompare(newVisualArea.position, oldVisualArea.position))
+ emit q->visualPositionChanged();
+}
+
+void QQuickScrollIndicatorPrivate::resizeContent()
+{
+ Q_Q(QQuickScrollIndicator);
+ if (!contentItem)
+ return;
+
+ // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size
+ // - positive overshoot (pos + size > 1): clamp the size to 1-pos
+ const VisualArea visual = visualArea();
+
+ if (orientation == Qt::Horizontal) {
+ contentItem->setPosition(QPointF(q->leftPadding() + visual.position * q->availableWidth(), q->topPadding()));
+ contentItem->setSize(QSizeF(q->availableWidth() * visual.size, q->availableHeight()));
+ } else {
+ contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + visual.position * q->availableHeight()));
+ contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * visual.size));
+ }
+}
+
+QQuickScrollIndicator::QQuickScrollIndicator(QQuickItem *parent)
+ : QQuickControl(*(new QQuickScrollIndicatorPrivate), parent)
+{
+}
+
+QQuickScrollIndicatorAttached *QQuickScrollIndicator::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickScrollIndicatorAttached(object);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ScrollIndicator::size
+
+ This property holds the size of the indicator, scaled to \c {0.0 - 1.0}.
+
+ \sa {Flickable::visibleArea.heightRatio}{Flickable::visibleArea}
+
+ This property is automatically set when the scroll indicator is
+ \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}.
+
+ \sa minimumSize, visualSize
+*/
+qreal QQuickScrollIndicator::size() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->size;
+}
+
+void QQuickScrollIndicator::setSize(qreal size)
+{
+ Q_D(QQuickScrollIndicator);
+ if (qFuzzyCompare(d->size, size))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->size = size;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit sizeChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::ScrollIndicator::position
+
+ This property holds the position of the indicator, scaled to \c {0.0 - 1.0}.
+
+ This property is automatically set when the scroll indicator is
+ \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}.
+
+ \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea}, visualPosition
+*/
+qreal QQuickScrollIndicator::position() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->position;
+}
+
+void QQuickScrollIndicator::setPosition(qreal position)
+{
+ Q_D(QQuickScrollIndicator);
+ if (qFuzzyCompare(d->position, position))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->position = position;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit positionChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::ScrollIndicator::active
+
+ This property holds whether the indicator is active, that is, when the
+ attached Flickable is \l {Flickable::moving}{moving}.
+
+ It is possible to keep \l {Binding the Active State of Horizontal and Vertical Scroll Indicators}
+ {both horizontal and vertical indicators visible} while scrolling in either direction.
+
+ This property is automatically set when the scroll indicator is
+ \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}.
+*/
+bool QQuickScrollIndicator::isActive() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->active;
+}
+
+void QQuickScrollIndicator::setActive(bool active)
+{
+ Q_D(QQuickScrollIndicator);
+ if (d->active == active)
+ return;
+
+ d->active = active;
+ emit activeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::ScrollIndicator::orientation
+
+ This property holds the orientation of the indicator.
+
+ Possible values:
+ \value Qt.Horizontal Horizontal
+ \value Qt.Vertical Vertical (default)
+
+ This property is automatically set when the scroll indicator is
+ \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}.
+
+ \sa horizontal, vertical
+*/
+Qt::Orientation QQuickScrollIndicator::orientation() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->orientation;
+}
+
+void QQuickScrollIndicator::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickScrollIndicator);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit orientationChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::ScrollIndicator::horizontal
+ \readonly
+
+ This property holds whether the scroll indicator is horizontal.
+
+ \sa orientation
+*/
+bool QQuickScrollIndicator::isHorizontal() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::ScrollIndicator::vertical
+ \readonly
+
+ This property holds whether the scroll indicator is vertical.
+
+ \sa orientation
+*/
+bool QQuickScrollIndicator::isVertical() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->orientation == Qt::Vertical;
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollIndicator::minimumSize
+
+ This property holds the minimum size of the indicator, scaled to \c {0.0 - 1.0}.
+
+ \sa size, visualSize, visualPosition
+*/
+qreal QQuickScrollIndicator::minimumSize() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->minimumSize;
+}
+
+void QQuickScrollIndicator::setMinimumSize(qreal minimumSize)
+{
+ Q_D(QQuickScrollIndicator);
+ if (qFuzzyCompare(d->minimumSize, minimumSize))
+ return;
+
+ auto oldVisualArea = d->visualArea();
+ d->minimumSize = minimumSize;
+ if (isComponentComplete())
+ d->resizeContent();
+ emit minimumSizeChanged();
+ d->visualAreaChange(d->visualArea(), oldVisualArea);
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollIndicator::visualSize
+
+ This property holds the effective visual size of the indicator,
+ which may be limited by the \l {minimumSize}{minimum size}.
+
+ \sa size, minimumSize
+*/
+qreal QQuickScrollIndicator::visualSize() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->visualArea().size;
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty real QtQuick.Controls::ScrollIndicator::visualPosition
+
+ This property holds the effective visual position of the indicator,
+ which may be limited by the \l {minimumSize}{minimum size}.
+
+ \sa position, minimumSize
+*/
+qreal QQuickScrollIndicator::visualPosition() const
+{
+ Q_D(const QQuickScrollIndicator);
+ return d->visualArea().position;
+}
+
+class QQuickScrollIndicatorAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+public:
+ void activateHorizontal();
+ void activateVertical();
+
+ void layoutHorizontal(bool move = true);
+ void layoutVertical(bool move = true);
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QQuickFlickable *flickable = nullptr;
+ QQuickScrollIndicator *horizontal = nullptr;
+ QQuickScrollIndicator *vertical = nullptr;
+};
+
+void QQuickScrollIndicatorAttachedPrivate::activateHorizontal()
+{
+ horizontal->setActive(flickable->isMovingHorizontally());
+}
+
+void QQuickScrollIndicatorAttachedPrivate::activateVertical()
+{
+ vertical->setActive(flickable->isMovingVertically());
+}
+
+void QQuickScrollIndicatorAttachedPrivate::layoutHorizontal(bool move)
+{
+ Q_ASSERT(horizontal && flickable);
+ if (horizontal->parentItem() != flickable)
+ return;
+ horizontal->setWidth(flickable->width());
+ if (move)
+ horizontal->setY(flickable->height() - horizontal->height());
+}
+
+void QQuickScrollIndicatorAttachedPrivate::layoutVertical(bool move)
+{
+ Q_ASSERT(vertical && flickable);
+ if (vertical->parentItem() != flickable)
+ return;
+ vertical->setHeight(flickable->height());
+ if (move && !QQuickItemPrivate::get(vertical)->isMirrored())
+ vertical->setX(flickable->width() - vertical->width());
+}
+
+void QQuickScrollIndicatorAttachedPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(item);
+ Q_UNUSED(change);
+ if (horizontal && horizontal->height() > 0) {
+#ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), diff.height() - horizontal->height());
+#else
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), item->height() - diff.height() - horizontal->height());
+#endif
+ layoutHorizontal(move);
+ }
+ if (vertical && vertical->width() > 0) {
+#ifdef QT_QUICK_NEW_GEOMETRY_CHANGED_HANDLING // TODO: correct/rename diff to oldGeometry
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), diff.width() - vertical->width());
+#else
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), item->width() - diff.width() - vertical->width());
+#endif
+ layoutVertical(move);
+ }
+}
+
+void QQuickScrollIndicatorAttachedPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ if (item == vertical)
+ layoutVertical(true);
+}
+
+void QQuickScrollIndicatorAttachedPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ if (item == horizontal)
+ layoutHorizontal(true);
+}
+
+void QQuickScrollIndicatorAttachedPrivate::itemDestroyed(QQuickItem *item)
+{
+ if (item == horizontal)
+ horizontal = nullptr;
+ if (item == vertical)
+ vertical = nullptr;
+}
+
+QQuickScrollIndicatorAttached::QQuickScrollIndicatorAttached(QObject *parent)
+ : QObject(*(new QQuickScrollIndicatorAttachedPrivate), parent)
+{
+ Q_D(QQuickScrollIndicatorAttached);
+ d->flickable = qobject_cast<QQuickFlickable *>(parent);
+ if (d->flickable)
+ QQuickItemPrivate::get(d->flickable)->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Size);
+ else if (parent)
+ qmlWarning(parent) << "ScrollIndicator must be attached to a Flickable";
+}
+
+QQuickScrollIndicatorAttached::~QQuickScrollIndicatorAttached()
+{
+ Q_D(QQuickScrollIndicatorAttached);
+ if (d->flickable) {
+ if (d->horizontal)
+ QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, horizontalChangeTypes);
+ if (d->vertical)
+ QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d,verticalChangeTypes);
+ // NOTE: Use removeItemChangeListener(Geometry) instead of updateOrRemoveGeometryChangeListener(Size).
+ // The latter doesn't remove the listener but only resets its types. Thus, it leaves behind a dangling
+ // pointer on destruction.
+ QQuickItemPrivate::get(d->flickable)->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
+ }
+}
+
+/*!
+ \qmlattachedproperty ScrollIndicator QtQuick.Controls::ScrollIndicator::horizontal
+
+ This property attaches a horizontal scroll indicator to a \l Flickable.
+
+ \code
+ Flickable {
+ contentWidth: 2000
+ ScrollIndicator.horizontal: ScrollIndicator { }
+ }
+ \endcode
+
+ \sa {Attaching ScrollIndicator to a Flickable}
+*/
+QQuickScrollIndicator *QQuickScrollIndicatorAttached::horizontal() const
+{
+ Q_D(const QQuickScrollIndicatorAttached);
+ return d->horizontal;
+}
+
+void QQuickScrollIndicatorAttached::setHorizontal(QQuickScrollIndicator *horizontal)
+{
+ Q_D(QQuickScrollIndicatorAttached);
+ if (d->horizontal == horizontal)
+ return;
+
+ if (d->horizontal && d->flickable) {
+ QQuickItemPrivate::get(d->horizontal)->removeItemChangeListener(d, horizontalChangeTypes);
+ QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateHorizontal);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = d->flickable->property("visibleArea").value<QObject *>();
+ disconnect(area, SIGNAL(widthRatioChanged(qreal)), d->horizontal, SLOT(setSize(qreal)));
+ disconnect(area, SIGNAL(xPositionChanged(qreal)), d->horizontal, SLOT(setPosition(qreal)));
+ }
+
+ d->horizontal = horizontal;
+
+ if (horizontal && d->flickable) {
+ if (!horizontal->parentItem())
+ horizontal->setParentItem(d->flickable);
+ horizontal->setOrientation(Qt::Horizontal);
+
+ QQuickItemPrivate::get(horizontal)->addItemChangeListener(d, horizontalChangeTypes);
+ QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingHorizontallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateHorizontal);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = d->flickable->property("visibleArea").value<QObject *>();
+ connect(area, SIGNAL(widthRatioChanged(qreal)), horizontal, SLOT(setSize(qreal)));
+ connect(area, SIGNAL(xPositionChanged(qreal)), horizontal, SLOT(setPosition(qreal)));
+
+ d->layoutHorizontal();
+ horizontal->setSize(area->property("widthRatio").toReal());
+ horizontal->setPosition(area->property("xPosition").toReal());
+ }
+ emit horizontalChanged();
+}
+
+/*!
+ \qmlattachedproperty ScrollIndicator QtQuick.Controls::ScrollIndicator::vertical
+
+ This property attaches a vertical scroll indicator to a \l Flickable.
+
+ \code
+ Flickable {
+ contentHeight: 2000
+ ScrollIndicator.vertical: ScrollIndicator { }
+ }
+ \endcode
+
+ \sa {Attaching ScrollIndicator to a Flickable}
+*/
+QQuickScrollIndicator *QQuickScrollIndicatorAttached::vertical() const
+{
+ Q_D(const QQuickScrollIndicatorAttached);
+ return d->vertical;
+}
+
+void QQuickScrollIndicatorAttached::setVertical(QQuickScrollIndicator *vertical)
+{
+ Q_D(QQuickScrollIndicatorAttached);
+ if (d->vertical == vertical)
+ return;
+
+ if (d->vertical && d->flickable) {
+ QQuickItemPrivate::get(d->vertical)->removeItemChangeListener(d, verticalChangeTypes);
+ QObjectPrivate::disconnect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateVertical);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = d->flickable->property("visibleArea").value<QObject *>();
+ disconnect(area, SIGNAL(heightRatioChanged(qreal)), d->vertical, SLOT(setSize(qreal)));
+ disconnect(area, SIGNAL(yPositionChanged(qreal)), d->vertical, SLOT(setPosition(qreal)));
+ }
+
+ d->vertical = vertical;
+
+ if (vertical && d->flickable) {
+ if (!vertical->parentItem())
+ vertical->setParentItem(d->flickable);
+ vertical->setOrientation(Qt::Vertical);
+
+ QQuickItemPrivate::get(vertical)->addItemChangeListener(d, verticalChangeTypes);
+ QObjectPrivate::connect(d->flickable, &QQuickFlickable::movingVerticallyChanged, d, &QQuickScrollIndicatorAttachedPrivate::activateVertical);
+
+ // TODO: export QQuickFlickableVisibleArea
+ QObject *area = d->flickable->property("visibleArea").value<QObject *>();
+ connect(area, SIGNAL(heightRatioChanged(qreal)), vertical, SLOT(setSize(qreal)));
+ connect(area, SIGNAL(yPositionChanged(qreal)), vertical, SLOT(setPosition(qreal)));
+
+ d->layoutVertical();
+ vertical->setSize(area->property("heightRatio").toReal());
+ vertical->setPosition(area->property("yPosition").toReal());
+ }
+ emit verticalChanged();
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickScrollIndicator::touchEvent(QTouchEvent *event)
+{
+ event->ignore(); // QTBUG-61785
+}
+#endif
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickScrollIndicator::accessibleRole() const
+{
+ return QAccessible::Indicator;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickscrollindicator_p.cpp"
diff --git a/src/quicktemplates2/qquickscrollindicator_p.h b/src/quicktemplates2/qquickscrollindicator_p.h
new file mode 100644
index 0000000000..dbad6ffe43
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollindicator_p.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSCROLLINDICATOR_P_H
+#define QQUICKSCROLLINDICATOR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFlickable;
+class QQuickScrollIndicatorAttached;
+class QQuickScrollIndicatorPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollIndicator : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged FINAL)
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION(2, 3))
+ // 2.4 (Qt 5.11)
+ Q_PROPERTY(qreal minimumSize READ minimumSize WRITE setMinimumSize NOTIFY minimumSizeChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal visualSize READ visualSize NOTIFY visualSizeChanged FINAL REVISION(2, 4))
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL REVISION(2, 4))
+ QML_NAMED_ELEMENT(ScrollIndicator)
+ QML_ATTACHED(QQuickScrollIndicatorAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickScrollIndicator(QQuickItem *parent = nullptr);
+
+ static QQuickScrollIndicatorAttached *qmlAttachedProperties(QObject *object);
+
+ qreal size() const;
+ qreal position() const;
+
+ bool isActive() const;
+ void setActive(bool active);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ // 2.3 (Qt 5.10)
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+ // 2.4 (Qt 5.11)
+ qreal minimumSize() const;
+ void setMinimumSize(qreal minimumSize);
+
+ qreal visualSize() const;
+ qreal visualPosition() const;
+
+public Q_SLOTS:
+ void setSize(qreal size);
+ void setPosition(qreal position);
+
+Q_SIGNALS:
+ void sizeChanged();
+ void positionChanged();
+ void activeChanged();
+ void orientationChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void minimumSizeChanged();
+ Q_REVISION(2, 4) void visualSizeChanged();
+ Q_REVISION(2, 4) void visualPositionChanged();
+
+protected:
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickScrollIndicator)
+ Q_DECLARE_PRIVATE(QQuickScrollIndicator)
+};
+
+class QQuickScrollIndicatorAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollIndicatorAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickScrollIndicator *horizontal READ horizontal WRITE setHorizontal NOTIFY horizontalChanged FINAL)
+ Q_PROPERTY(QQuickScrollIndicator *vertical READ vertical WRITE setVertical NOTIFY verticalChanged FINAL)
+
+public:
+ explicit QQuickScrollIndicatorAttached(QObject *parent = nullptr);
+ ~QQuickScrollIndicatorAttached();
+
+ QQuickScrollIndicator *horizontal() const;
+ void setHorizontal(QQuickScrollIndicator *horizontal);
+
+ QQuickScrollIndicator *vertical() const;
+ void setVertical(QQuickScrollIndicator *vertical);
+
+Q_SIGNALS:
+ void horizontalChanged();
+ void verticalChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickScrollIndicatorAttached)
+ Q_DECLARE_PRIVATE(QQuickScrollIndicatorAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickScrollIndicator)
+QML_DECLARE_TYPEINFO(QQuickScrollIndicator, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKSCROLLINDICATOR_P_H
diff --git a/src/quicktemplates2/qquickscrollview.cpp b/src/quicktemplates2/qquickscrollview.cpp
new file mode 100644
index 0000000000..1f5adbb7ff
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollview.cpp
@@ -0,0 +1,623 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickscrollview_p.h"
+#include "qquickpane_p_p.h"
+#include "qquickscrollbar_p_p.h"
+
+#include <QtQuick/private/qquickflickable_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ScrollView
+ \inherits Pane
+//! \instantiates QQuickScrollView
+ \inqmlmodule QtQuick.Controls
+ \since 5.9
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Scrollable view.
+
+ ScrollView provides scrolling for user-defined content. It can be used to
+ either replace a \l Flickable, or to decorate an existing one.
+
+ \image qtquickcontrols2-scrollview.png
+
+ The first example demonstrates the simplest usage of ScrollView.
+
+ \snippet qtquickcontrols2-scrollview.qml file
+
+ The second example illustrates using an existing \l Flickable, that is,
+ a \l ListView.
+
+ \snippet qtquickcontrols2-scrollview-listview.qml file
+
+ \note As of Qt-6.0, ScrollView automatically clips its contents if you
+ don't use a Flickable as a child. If this is not wanted, you can
+ set your own Flickable as a child, and control the \l {Item::}{clip}
+ property on the Flickable explicitly.
+
+ \section2 Sizing
+
+ As with Flickable, there are several things to keep in mind when using
+ ScrollView:
+ \list
+ \li If only a single item is used within a ScrollView, the content size is
+ automatically calculated based on the implicit size of its contained item.
+ However, if more than one item is used (or an implicit size is not
+ provided), the \l {QtQuick.Controls::Pane::}{contentWidth} and
+ \l {QtQuick.Controls::Pane::}{contentHeight} properties must
+ be set to the combined size of its contained items.
+ \li If the content size is less than or equal to the size of the ScrollView,
+ it will not be scrollable.
+ \li If you want the ScrollView to only scroll vertically, you can bind
+ \l {QtQuick.Controls::Pane::}{contentWidth} to
+ \l {QtQuick.Controls::Control::}{availableWidth}
+ (and vice versa for contentHeight). This will let the contents fill
+ out all the available space horizontally inside the ScrollView, taking
+ any padding or scroll bars into account.
+ \endlist
+
+ \section2 Scroll Bars
+
+ The horizontal and vertical scroll bars can be accessed and customized using
+ the \l {ScrollBar::horizontal}{ScrollBar.horizontal} and \l {ScrollBar::vertical}
+ {ScrollBar.vertical} attached properties. The following example adjusts the scroll
+ bar policies so that the horizontal scroll bar is always off, and the vertical
+ scroll bar is always on.
+
+ \snippet qtquickcontrols2-scrollview-policy.qml file
+
+ \section2 Touch vs. Mouse Interaction
+
+ On touch, ScrollView enables flicking and makes the scroll bars non-interactive.
+
+ \image qtquickcontrols2-scrollindicator.gif
+
+ When interacted with a mouse device, flicking is disabled and the scroll bars
+ are interactive.
+
+ \image qtquickcontrols2-scrollbar.gif
+
+ Scroll bars can be made interactive on touch, or non-interactive when interacted
+ with a mouse device, by setting the \l {ScrollBar::}{interactive} property explicitly
+ to \c true or \c false, respectively.
+
+ \snippet qtquickcontrols2-scrollview-interactive.qml file
+
+ \sa ScrollBar, ScrollIndicator, {Customizing ScrollView}, {Container Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+class QQuickScrollViewPrivate : public QQuickPanePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickScrollView)
+
+public:
+ QQmlListProperty<QObject> contentData() override;
+ QQmlListProperty<QQuickItem> contentChildren() override;
+ QList<QQuickItem *> contentChildItems() const override;
+
+ QQuickItem *getContentItem() override;
+
+ QQuickFlickable *ensureFlickable(bool content);
+ bool setFlickable(QQuickFlickable *flickable, bool content);
+
+ void flickableContentWidthChanged();
+ void flickableContentHeightChanged();
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ QQuickScrollBar *verticalScrollBar() const;
+ QQuickScrollBar *horizontalScrollBar() const;
+
+ void setScrollBarsInteractive(bool interactive);
+
+ static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
+ static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
+ static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
+ static void contentData_clear(QQmlListProperty<QObject> *prop);
+
+ static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj);
+ static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
+ static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
+ static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+
+ bool wasTouched = false;
+ QQuickFlickable *flickable = nullptr;
+ bool flickableHasExplicitContentWidth = true;
+ bool flickableHasExplicitContentHeight = true;
+};
+
+QList<QQuickItem *> QQuickScrollViewPrivate::contentChildItems() const
+{
+ if (!flickable)
+ return QList<QQuickItem *>();
+
+ return flickable->contentItem()->childItems();
+}
+
+QQuickItem *QQuickScrollViewPrivate::getContentItem()
+{
+ if (!contentItem)
+ executeContentItem();
+ return ensureFlickable(false);
+}
+
+QQuickFlickable *QQuickScrollViewPrivate::ensureFlickable(bool content)
+{
+ Q_Q(QQuickScrollView);
+ if (!flickable) {
+ flickableHasExplicitContentWidth = false;
+ flickableHasExplicitContentHeight = false;
+ auto flickable = new QQuickFlickable(q);
+ // We almost always want to clip the flickable so that flickable
+ // contents doesn't show up outside the scrollview. The only time
+ // this is not really needed, is when the scrollview covers the whole
+ // window and the scrollbars are transient. But for that corner case, if this
+ // optimization is needed, the user can simply create his own flickable
+ // child inside the scrollview, and control clipping on it explicit.
+ flickable->setClip(true);
+ flickable->setPixelAligned(true);
+ setFlickable(flickable, content);
+ }
+ return flickable;
+}
+
+bool QQuickScrollViewPrivate::setFlickable(QQuickFlickable *item, bool content)
+{
+ Q_Q(QQuickScrollView);
+ if (item == flickable)
+ return false;
+
+ QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
+
+ if (flickable) {
+ flickable->removeEventFilter(q);
+
+ if (attached)
+ QQuickScrollBarAttachedPrivate::get(attached)->setFlickable(nullptr);
+
+ QObjectPrivate::disconnect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
+ QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
+ QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
+ }
+
+ flickable = item;
+ if (content)
+ q->setContentItem(flickable);
+
+ if (flickable) {
+ flickable->installEventFilter(q);
+ if (hasContentWidth)
+ flickable->setContentWidth(contentWidth);
+ else
+ flickableContentWidthChanged();
+ if (hasContentHeight)
+ flickable->setContentHeight(contentHeight);
+ else
+ flickableContentHeightChanged();
+
+ if (attached)
+ QQuickScrollBarAttachedPrivate::get(attached)->setFlickable(flickable);
+
+ QObjectPrivate::connect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
+ QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
+ QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
+ }
+
+ return true;
+}
+
+void QQuickScrollViewPrivate::flickableContentWidthChanged()
+{
+ Q_Q(QQuickScrollView);
+ if (!flickable || !componentComplete)
+ return;
+
+ const qreal cw = flickable->contentWidth();
+ if (qFuzzyCompare(cw, implicitContentWidth))
+ return;
+
+ flickableHasExplicitContentWidth = true;
+ implicitContentWidth = cw;
+ emit q->implicitContentWidthChanged();
+}
+
+void QQuickScrollViewPrivate::flickableContentHeightChanged()
+{
+ Q_Q(QQuickScrollView);
+ if (!flickable || !componentComplete)
+ return;
+
+ const qreal ch = flickable->contentHeight();
+ if (qFuzzyCompare(ch, implicitContentHeight))
+ return;
+
+ flickableHasExplicitContentHeight = true;
+ implicitContentHeight = ch;
+ emit q->implicitContentHeightChanged();
+}
+
+qreal QQuickScrollViewPrivate::getContentWidth() const
+{
+ if (flickable && flickableHasExplicitContentWidth)
+ return flickable->contentWidth();
+
+ // The scrollview wraps a flickable created by us, and nobody searched for it and
+ // modified its contentWidth. In that case, since the application does not control
+ // this flickable, we fall back to calculate the content width based on the child
+ // items inside it.
+ return QQuickPanePrivate::getContentWidth();
+}
+
+qreal QQuickScrollViewPrivate::getContentHeight() const
+{
+ if (flickable && flickableHasExplicitContentHeight)
+ return flickable->contentHeight();
+
+ // The scrollview wraps a flickable created by us, and nobody searched for it and
+ // modified its contentHeight. In that case, since the application does not control
+ // this flickable, we fall back to calculate the content height based on the child
+ // items inside it.
+ return QQuickPanePrivate::getContentHeight();
+}
+
+QQuickScrollBar *QQuickScrollViewPrivate::verticalScrollBar() const
+{
+ Q_Q(const QQuickScrollView);
+ QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
+ if (!attached)
+ return nullptr;
+ return attached->vertical();
+}
+
+QQuickScrollBar *QQuickScrollViewPrivate::horizontalScrollBar() const
+{
+ Q_Q(const QQuickScrollView);
+ QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
+ if (!attached)
+ return nullptr;
+ return attached->horizontal();
+}
+
+void QQuickScrollViewPrivate::setScrollBarsInteractive(bool interactive)
+{
+ QQuickScrollBar *hbar = horizontalScrollBar();
+ if (hbar) {
+ QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(hbar);
+ if (!p->explicitInteractive)
+ p->setInteractive(interactive);
+ }
+
+ QQuickScrollBar *vbar = verticalScrollBar();
+ if (vbar) {
+ QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(vbar);
+ if (!p->explicitInteractive)
+ p->setInteractive(interactive);
+ }
+}
+
+void QQuickScrollViewPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable && p->setFlickable(qobject_cast<QQuickFlickable *>(obj), true))
+ return;
+
+ QQuickFlickable *flickable = p->ensureFlickable(true);
+ Q_ASSERT(flickable);
+ QQmlListProperty<QObject> data = flickable->flickableData();
+ data.append(&data, obj);
+}
+
+qsizetype QQuickScrollViewPrivate::contentData_count(QQmlListProperty<QObject> *prop)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return 0;
+
+ QQmlListProperty<QObject> data = p->flickable->flickableData();
+ return data.count(&data);
+}
+
+QObject *QQuickScrollViewPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return nullptr;
+
+ QQmlListProperty<QObject> data = p->flickable->flickableData();
+ return data.at(&data, index);
+}
+
+void QQuickScrollViewPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return;
+
+ QQmlListProperty<QObject> data = p->flickable->flickableData();
+ return data.clear(&data);
+}
+
+void QQuickScrollViewPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ p->setFlickable(qobject_cast<QQuickFlickable *>(item), true);
+
+ QQuickFlickable *flickable = p->ensureFlickable(true);
+ Q_ASSERT(flickable);
+ QQmlListProperty<QQuickItem> children = flickable->flickableChildren();
+ children.append(&children, item);
+}
+
+qsizetype QQuickScrollViewPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return 0;
+
+ QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
+ return children.count(&children);
+}
+
+QQuickItem *QQuickScrollViewPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return nullptr;
+
+ QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
+ return children.at(&children, index);
+}
+
+void QQuickScrollViewPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
+{
+ QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
+ if (!p->flickable)
+ return;
+
+ QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
+ children.clear(&children);
+}
+
+void QQuickScrollViewPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ // a special case for width<->height dependent content (wrapping text) in ScrollView
+ if (contentWidth < 0 && !componentComplete)
+ return;
+
+ QQuickPanePrivate::itemImplicitWidthChanged(item);
+}
+
+QQuickScrollView::QQuickScrollView(QQuickItem *parent)
+ : QQuickPane(*(new QQuickScrollViewPrivate), parent)
+{
+ Q_D(QQuickScrollView);
+ d->contentWidth = -1;
+ d->contentHeight = -1;
+
+ setFiltersChildMouseEvents(true);
+ setWheelEnabled(true);
+}
+
+/*!
+ \qmlproperty list<Object> QtQuick.Controls::ScrollView::contentData
+ \qmldefault
+
+ This property holds the list of content data.
+
+ The list contains all objects that have been declared in QML as children of the view.
+
+ \note Unlike \c contentChildren, \c contentData does include non-visual QML objects.
+
+ \sa Item::data, contentChildren
+*/
+QQmlListProperty<QObject> QQuickScrollViewPrivate::contentData()
+{
+ Q_Q(QQuickScrollView);
+ return QQmlListProperty<QObject>(q, this,
+ QQuickScrollViewPrivate::contentData_append,
+ QQuickScrollViewPrivate::contentData_count,
+ QQuickScrollViewPrivate::contentData_at,
+ QQuickScrollViewPrivate::contentData_clear);
+}
+
+/*!
+ \qmlproperty list<Item> QtQuick.Controls::ScrollView::contentChildren
+
+ This property holds the list of content children.
+
+ The list contains all items that have been declared in QML as children of the view.
+
+ \note Unlike \c contentData, \c contentChildren does not include non-visual QML objects.
+
+ \sa Item::children, contentData
+*/
+QQmlListProperty<QQuickItem> QQuickScrollViewPrivate::contentChildren()
+{
+ Q_Q(QQuickScrollView);
+ return QQmlListProperty<QQuickItem>(q, this,
+ QQuickScrollViewPrivate::contentChildren_append,
+ QQuickScrollViewPrivate::contentChildren_count,
+ QQuickScrollViewPrivate::contentChildren_at,
+ QQuickScrollViewPrivate::contentChildren_clear);
+}
+
+bool QQuickScrollView::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_D(QQuickScrollView);
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ d->wasTouched = true;
+ d->setScrollBarsInteractive(false);
+ return false;
+
+ case QEvent::TouchEnd:
+ d->wasTouched = false;
+ return false;
+
+ case QEvent::MouseButtonPress:
+ // NOTE: Flickable does not handle touch events, only synthesized mouse events
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
+ d->wasTouched = false;
+ d->setScrollBarsInteractive(true);
+ return false;
+ }
+ return !d->wasTouched && item == d->flickable;
+
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonRelease:
+ if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
+ return item == d->flickable;
+ break;
+
+ case QEvent::HoverEnter:
+ case QEvent::HoverMove:
+ if (d->wasTouched && (item == d->verticalScrollBar() || item == d->horizontalScrollBar()))
+ d->setScrollBarsInteractive(true);
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+bool QQuickScrollView::eventFilter(QObject *object, QEvent *event)
+{
+ Q_D(QQuickScrollView);
+ if (event->type() == QEvent::Wheel) {
+ d->setScrollBarsInteractive(true);
+ if (!d->wheelEnabled)
+ return true;
+ }
+ return QQuickPane::eventFilter(object, event);
+}
+
+void QQuickScrollView::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickScrollView);
+ QQuickPane::keyPressEvent(event);
+ switch (event->key()) {
+ case Qt::Key_Up:
+ if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
+ vbar->decrease();
+ event->accept();
+ }
+ break;
+ case Qt::Key_Down:
+ if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
+ vbar->increase();
+ event->accept();
+ }
+ break;
+ case Qt::Key_Left:
+ if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
+ hbar->decrease();
+ event->accept();
+ }
+ break;
+ case Qt::Key_Right:
+ if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
+ hbar->increase();
+ event->accept();
+ }
+ break;
+ default:
+ event->ignore();
+ break;
+ }
+}
+
+void QQuickScrollView::componentComplete()
+{
+ Q_D(QQuickScrollView);
+ QQuickPane::componentComplete();
+ if (!d->contentItem)
+ d->ensureFlickable(true);
+}
+
+void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickScrollView);
+ if (newItem != d->flickable) {
+ // The new flickable was not created by us. In that case, we always
+ // assume/require that it has an explicit content size assigned.
+ d->flickableHasExplicitContentWidth = true;
+ d->flickableHasExplicitContentHeight = true;
+ auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(newItem);
+ if (newItem && !newItemAsFlickable)
+ qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem";
+ d->setFlickable(newItemAsFlickable, false);
+ }
+ QQuickPane::contentItemChange(newItem, oldItem);
+}
+
+void QQuickScrollView::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
+{
+ Q_D(QQuickScrollView);
+ QQuickPane::contentSizeChange(newSize, oldSize);
+ if (d->flickable) {
+ // Only set the content size on the flickable if the flickable doesn't
+ // have an explicit assignment from before. Otherwise we can end up overwriting
+ // assignments done to those properties by the application. The
+ // exception is if the application has assigned a content size
+ // directly to the scrollview, which will then win even if the
+ // application has assigned something else to the flickable.
+ if (d->hasContentWidth || !d->flickableHasExplicitContentWidth)
+ d->flickable->setContentWidth(newSize.width());
+ if (d->hasContentHeight || !d->flickableHasExplicitContentHeight)
+ d->flickable->setContentHeight(newSize.height());
+ }
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickScrollView::accessibleRole() const
+{
+ return QAccessible::Pane;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickscrollview_p.cpp"
diff --git a/src/quicktemplates2/qquickscrollview_p.h b/src/quicktemplates2/qquickscrollview_p.h
new file mode 100644
index 0000000000..7eea46ddae
--- /dev/null
+++ b/src/quicktemplates2/qquickscrollview_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSCROLLVIEW_P_H
+#define QQUICKSCROLLVIEW_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 <QtQuickTemplates2/private/qquickpane_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickScrollViewPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollView : public QQuickPane
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ScrollView)
+ QML_ADDED_IN_VERSION(2, 2)
+
+public:
+ explicit QQuickScrollView(QQuickItem *parent = nullptr);
+
+protected:
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
+ bool eventFilter(QObject *object, QEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+
+ void componentComplete() override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickScrollView)
+ Q_DECLARE_PRIVATE(QQuickScrollView)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickScrollView)
+
+#endif // QQUICKSCROLLVIEW_P_H
diff --git a/src/quicktemplates2/qquickselectionrectangle.cpp b/src/quicktemplates2/qquickselectionrectangle.cpp
new file mode 100644
index 0000000000..10573eda7c
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickselectionrectangle_p.h"
+#include "qquickselectionrectangle_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickdraghandler_p.h>
+#include <QtQuick/private/qquickhoverhandler_p.h>
+
+#include <QtQuick/private/qquicktableview_p_p.h>
+
+#include "qquickscrollview_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SelectionRectangle
+ \inherits Control
+//! \instantiates QQuickSelectionRectangle
+ \inqmlmodule QtQuick.Controls
+ \since 6.2
+ \ingroup utilities
+ \brief Used to select table cells inside a TableView.
+
+ \image qtquickcontrols2-selectionrectangle.png
+
+ SelectionRectangle is used for selecting table cells in a TableView. It lets
+ the user start a selection by doing a pointer drag inside the viewport, or by
+ doing a long press on top of a cell.
+
+ For a SelectionRectangle to be able to select cells, TableView must have
+ an ItemSelectionModel assigned. The ItemSelectionModel will store any
+ selections done on the model, and can be used for querying
+ which cells that the user has selected.
+
+ The following example shows how you can make a SelectionRectangle target
+ a TableView:
+
+ \snippet qtquickcontrols2-selectionrectangle.qml 0
+
+ \note A SelectionRectangle itself is not shown as part of a selection. Only the
+ delegates (like topLeftHandle and bottomRightHandle) are used.
+ You should also consider \l {Selecting items}{rendering the TableView delegate as selected}.
+
+ \sa TableView, TableView::selectionModel, ItemSelectionModel
+*/
+
+/*!
+ \qmlproperty Item QtQuick.Controls::SelectionRectangle::target
+
+ This property holds the TableView on which the
+ SelectionRectangle should act.
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SelectionRectangle::active
+ \readonly
+
+ This property is \c true while the user is performing a
+ selection. The selection will be active from the time the
+ the user starts to select, and until the selection is
+ removed again, for example from tapping inside the viewport.
+*/
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SelectionRectangle::dragging
+ \readonly
+
+ This property is \c true whenever the user is doing a pointer drag or
+ a handle drag to adjust the selection rectangle.
+*/
+
+/*!
+ \qmlproperty Component QtQuick.Controls::SelectionRectangle::topLeftHandle
+
+ This property holds the delegate that will be shown on the center of the
+ top-left corner of the selection rectangle. When a handle is
+ provided, the user can drag it to adjust the selection.
+
+ Set this property to \c null if you don't want a selection handle on the top-left.
+
+ \sa bottomRightHandle
+*/
+
+/*!
+ \qmlproperty Component QtQuick.Controls::SelectionRectangle::bottomRightHandle
+
+ This property holds the delegate that will be shown on the center of the
+ top-left corner of the selection rectangle. When a handle is
+ provided, the user can drag it to adjust the selection.
+
+ Set this property to \c null if you don't want a selection handle on the bottom-right.
+
+ \sa topLeftHandle
+*/
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::SelectionRectangle::selectionMode
+
+ This property holds when a selection should start.
+
+ \value SelectionRectangle.Drag A selection will start by doing a pointer drag inside the viewport
+ \value SelectionRectangle.PressAndHold A selection will start by doing a press and hold on top a cell
+ \value SelectionRectangle.Auto SelectionRectangle will choose which mode to use based on the target
+ and the platform. This normally means \c PressAndHold on touch based platforms, and \c Drag on desktop.
+ However, \c Drag will only be used if it doesn't conflict with flicking. This means that
+ TableView will need to be configured with \c interactive set to \c false, or placed
+ inside a ScrollView (where flicking, by default, is off for mouse events), for \c Drag to be chosen.
+
+ The default value is \c Auto.
+*/
+
+/*!
+ \qmlattachedproperty SelectionRectangle QtQuick::SelectionRectangle::control
+
+ This attached property holds the SelectionRectangle that manages the delegate instance.
+ It is attached to each handle instance.
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick::SelectionRectangle::dragging
+
+ This attached property will be \c true if the user is dragging on the handle.
+ It is attached to each handle instance.
+*/
+
+QQuickSelectionRectanglePrivate::QQuickSelectionRectanglePrivate()
+ : QQuickControlPrivate()
+{
+ m_tapHandler = new QQuickTapHandler();
+ m_dragHandler = new QQuickDragHandler();
+ m_dragHandler->setTarget(nullptr);
+
+ QObject::connect(&m_scrollTimer, &QTimer::timeout, [&]{
+ if (m_topLeftHandle && m_draggedHandle == m_topLeftHandle)
+ m_selectable->setSelectionStartPos(m_scrollToPoint);
+ else
+ m_selectable->setSelectionEndPos(m_scrollToPoint);
+ updateHandles();
+ const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(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));
+ });
+
+ QObject::connect(m_tapHandler, &QQuickTapHandler::tapped, [=](QEventPoint) {
+ m_selectable->clearSelection();
+ updateActiveState(false);
+ });
+
+ QObject::connect(m_tapHandler, &QQuickTapHandler::longPressed, [=]() {
+ if (handleUnderPos(m_tapHandler->point().pressPosition()) != nullptr) {
+ // Don't allow press'n'hold to start a new
+ // selection if it started on top of a handle.
+ return;
+ }
+ if (!m_alwaysAcceptPressAndHold) {
+ if (m_selectionMode == QQuickSelectionRectangle::Auto) {
+ // In Auto mode, we only accept press and hold from touch
+ if (m_tapHandler->point().device()->pointerType() != QPointingDevice::PointerType::Finger)
+ return;
+ } else if (m_selectionMode != QQuickSelectionRectangle::PressAndHold) {
+ return;
+ }
+ }
+
+ const QPointF pos = m_tapHandler->point().position();
+ m_selectable->clearSelection();
+ m_selectable->setSelectionStartPos(pos);
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ updateActiveState(true);
+ });
+
+ QObject::connect(m_dragHandler, &QQuickDragHandler::activeChanged, [=]() {
+ const QPointF startPos = m_dragHandler->centroid().pressPosition();
+ const QPointF dragPos = m_dragHandler->centroid().position();
+ if (m_dragHandler->active()) {
+ m_selectable->clearSelection();
+ m_selectable->setSelectionStartPos(startPos);
+ m_selectable->setSelectionEndPos(dragPos);
+ m_draggedHandle = nullptr;
+ updateHandles();
+ updateActiveState(true);
+ updateDraggingState(true);
+ } else {
+ m_scrollTimer.stop();
+ m_selectable->normalizeSelection();
+ updateDraggingState(false);
+ }
+ });
+
+ QObject::connect(m_dragHandler, &QQuickDragHandler::centroidChanged, [=]() {
+ if (!m_dragging)
+ return;
+ const QPointF pos = m_dragHandler->centroid().position();
+ m_selectable->setSelectionEndPos(pos);
+ updateHandles();
+ scrollTowardsPos(pos);
+ });
+}
+
+void QQuickSelectionRectanglePrivate::scrollTowardsPos(const QPointF &pos)
+{
+ m_scrollToPoint = pos;
+ if (m_scrollTimer.isActive())
+ return;
+
+ const QSizeF dist = m_selectable->scrollTowardsSelectionPoint(m_scrollToPoint, m_scrollSpeed);
+ if (!dist.isNull())
+ m_scrollTimer.start(1);
+}
+
+QQuickItem *QQuickSelectionRectanglePrivate::handleUnderPos(const QPointF &pos)
+{
+ const auto handlerTarget = m_selectable->selectionPointerHandlerTarget();
+ if (m_topLeftHandle) {
+ const QPointF localPos = m_topLeftHandle->mapFromItem(handlerTarget, pos);
+ if (m_topLeftHandle->contains(localPos))
+ return m_topLeftHandle;
+ }
+
+ if (m_bottomRightHandle) {
+ const QPointF localPos = m_bottomRightHandle->mapFromItem(handlerTarget, pos);
+ if (m_bottomRightHandle->contains(localPos))
+ return m_bottomRightHandle;
+ }
+
+ return nullptr;
+}
+
+void QQuickSelectionRectanglePrivate::updateDraggingState(bool dragging)
+{
+ if (dragging != m_dragging) {
+ m_dragging = dragging;
+ emit q_func()->draggingChanged();
+ }
+
+ if (auto attached = getAttachedObject(m_draggedHandle))
+ attached->setDragging(dragging);
+}
+
+void QQuickSelectionRectanglePrivate::updateActiveState(bool active)
+{
+ if (active == m_active)
+ return;
+
+ m_active = active;
+ emit q_func()->activeChanged();
+}
+
+QQuickItem *QQuickSelectionRectanglePrivate::createHandle(QQmlComponent *delegate, Qt::Corner corner)
+{
+ Q_Q(QQuickSelectionRectangle);
+
+ // Incubate the handle
+ QObject *obj = delegate->beginCreate(QQmlEngine::contextForObject(q));
+ QQuickItem *handleItem = qobject_cast<QQuickItem*>(obj);
+ const auto handlerTarget = m_selectable->selectionPointerHandlerTarget();
+ handleItem->setParentItem(handlerTarget);
+ if (auto attached = getAttachedObject(handleItem))
+ attached->setControl(q);
+ delegate->completeCreate();
+ if (handleItem->z() == 0)
+ handleItem->setZ(100);
+
+ // Add pointer handlers to it
+ QQuickDragHandler *dragHandler = new QQuickDragHandler();
+ dragHandler->setTarget(nullptr);
+ dragHandler->setParent(handleItem);
+ QQuickItemPrivate::get(handleItem)->addPointerHandler(dragHandler);
+
+ QQuickHoverHandler *hoverHandler = new QQuickHoverHandler();
+ hoverHandler->setTarget(nullptr);
+ hoverHandler->setParent(handleItem);
+ hoverHandler->setCursorShape(Qt::SizeFDiagCursor);
+ QQuickItemPrivate::get(handleItem)->addPointerHandler(hoverHandler);
+
+ QObject::connect(dragHandler, &QQuickDragHandler::activeChanged, [=]() {
+ if (dragHandler->active()) {
+ const QPointF localPos = dragHandler->centroid().position();
+ const QPointF pos = handleItem->mapToItem(handleItem->parentItem(), localPos);
+ if (corner == Qt::TopLeftCorner)
+ m_selectable->setSelectionStartPos(pos);
+ else
+ m_selectable->setSelectionEndPos(pos);
+
+ m_draggedHandle = handleItem;
+ updateHandles();
+ updateDraggingState(true);
+ QGuiApplication::setOverrideCursor(Qt::SizeFDiagCursor);
+ } else {
+ m_scrollTimer.stop();
+ m_selectable->normalizeSelection();
+ updateDraggingState(false);
+ QGuiApplication::restoreOverrideCursor();
+ }
+ });
+
+ QObject::connect(dragHandler, &QQuickDragHandler::centroidChanged, [=]() {
+ if (!m_dragging)
+ return;
+
+ const QPointF localPos = dragHandler->centroid().position();
+ const QPointF pos = handleItem->mapToItem(handleItem->parentItem(), localPos);
+ if (corner == Qt::TopLeftCorner)
+ m_selectable->setSelectionStartPos(pos);
+ else
+ m_selectable->setSelectionEndPos(pos);
+
+ updateHandles();
+ scrollTowardsPos(pos);
+ });
+
+ return handleItem;
+}
+
+void QQuickSelectionRectanglePrivate::updateHandles()
+{
+ if (!m_selectable)
+ return;
+
+ const QRectF rect = m_selectable->selectionRectangle().normalized();
+
+ if (!m_topLeftHandle && m_topLeftHandleDelegate)
+ m_topLeftHandle = createHandle(m_topLeftHandleDelegate, Qt::TopLeftCorner);
+
+ if (!m_bottomRightHandle && m_bottomRightHandleDelegate)
+ m_bottomRightHandle = createHandle(m_bottomRightHandleDelegate, Qt::BottomRightCorner);
+
+ if (m_topLeftHandle) {
+ m_topLeftHandle->setX(rect.x() - (m_topLeftHandle->width() / 2));
+ m_topLeftHandle->setY(rect.y() - (m_topLeftHandle->height() / 2));
+ }
+
+ if (m_bottomRightHandle) {
+ m_bottomRightHandle->setX(rect.x() + rect.width() - (m_bottomRightHandle->width() / 2));
+ m_bottomRightHandle->setY(rect.y() + rect.height() - (m_bottomRightHandle->height() / 2));
+ }
+}
+
+void QQuickSelectionRectanglePrivate::connectToTarget()
+{
+ // To support QuickSelectionRectangle::Auto, we need to listen for changes to the target
+ if (const auto flickable = qobject_cast<QQuickFlickable *>(m_target)) {
+ connect(flickable, &QQuickFlickable::interactiveChanged, this, &QQuickSelectionRectanglePrivate::updateSelectionMode);
+ }
+}
+
+void QQuickSelectionRectanglePrivate::updateSelectionMode()
+{
+ Q_Q(QQuickSelectionRectangle);
+
+ const bool enabled = q->isEnabled();
+ m_tapHandler->setEnabled(enabled);
+
+ if (m_selectionMode == QQuickSelectionRectangle::Auto) {
+ if (qobject_cast<QQuickScrollView *>(m_target->parentItem())) {
+ // ScrollView allows flicking with touch, but not with mouse. So we do
+ // the same here: you can drag to select with a mouse, but not with touch.
+ m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::Mouse);
+ m_dragHandler->setEnabled(enabled);
+ } else if (const auto flickable = qobject_cast<QQuickFlickable *>(m_target)) {
+ m_dragHandler->setEnabled(enabled && !flickable->isInteractive());
+ } else {
+ m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::Mouse);
+ m_dragHandler->setEnabled(enabled);
+ }
+ } else if (m_selectionMode == QQuickSelectionRectangle::Drag) {
+ m_dragHandler->setAcceptedDevices(QInputDevice::DeviceType::AllDevices);
+ m_dragHandler->setEnabled(enabled);
+ } else {
+ m_dragHandler->setEnabled(false);
+ }
+
+ // If you can't select using a drag, we always accept a PressAndHold
+ m_alwaysAcceptPressAndHold = !m_dragHandler->enabled();
+}
+
+QQuickSelectionRectangleAttached *QQuickSelectionRectanglePrivate::getAttachedObject(const QObject *object) const
+{
+ QObject *attachedObject = qmlAttachedPropertiesObject<QQuickSelectionRectangle>(object);
+ return static_cast<QQuickSelectionRectangleAttached *>(attachedObject);
+}
+
+// --------------------------------------------------------
+
+QQuickSelectionRectangle::QQuickSelectionRectangle(QQuickItem *parent)
+ : QQuickControl(*(new QQuickSelectionRectanglePrivate), parent)
+{
+ Q_D(QQuickSelectionRectangle);
+
+ QObject::connect(this, &QQuickItem::enabledChanged, [=]() {
+ d->m_scrollTimer.stop();
+ d->updateSelectionMode();
+ d->updateDraggingState(false);
+ d->updateActiveState(false);
+ });
+}
+
+QQuickItem *QQuickSelectionRectangle::target() const
+{
+ return d_func()->m_target;
+}
+
+void QQuickSelectionRectangle::setTarget(QQuickItem *target)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_target == target)
+ return;
+
+ if (d->m_selectable) {
+ d->m_scrollTimer.stop();
+ d->m_tapHandler->setParent(nullptr);
+ d->m_dragHandler->setParent(nullptr);
+ d->m_target->disconnect(this);
+ }
+
+ d->m_target = target;
+ d->m_selectable = nullptr;
+
+ if (d->m_target) {
+ d->m_selectable = dynamic_cast<QQuickSelectable *>(QObjectPrivate::get(d->m_target.data()));
+ if (!d->m_selectable)
+ qmlWarning(this) << "the assigned target is not supported by the control";
+ }
+
+ if (d->m_selectable) {
+ const auto handlerTarget = d->m_selectable->selectionPointerHandlerTarget();
+ d->m_dragHandler->setParent(handlerTarget);
+ d->m_tapHandler->setParent(handlerTarget);
+ QQuickItemPrivate::get(handlerTarget)->addPointerHandler(d->m_tapHandler);
+ QQuickItemPrivate::get(handlerTarget)->addPointerHandler(d->m_dragHandler);
+ d->connectToTarget();
+ d->updateSelectionMode();
+ }
+
+ emit targetChanged();
+}
+
+bool QQuickSelectionRectangle::active()
+{
+ return d_func()->m_active;
+}
+
+bool QQuickSelectionRectangle::dragging()
+{
+ return d_func()->m_dragging;
+}
+
+QQuickSelectionRectangle::SelectionMode QQuickSelectionRectangle::selectionMode() const
+{
+ return d_func()->m_selectionMode;
+}
+
+void QQuickSelectionRectangle::setSelectionMode(QQuickSelectionRectangle::SelectionMode selectionMode)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_selectionMode == selectionMode)
+ return;
+
+ d->m_selectionMode = selectionMode;
+
+ if (d->m_target)
+ d->updateSelectionMode();
+
+ emit selectionModeChanged();
+}
+
+QQmlComponent *QQuickSelectionRectangle::topLeftHandle() const
+{
+ return d_func()->m_topLeftHandleDelegate;
+}
+
+void QQuickSelectionRectangle::setTopLeftHandle(QQmlComponent *topLeftHandle)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_topLeftHandleDelegate == topLeftHandle)
+ return;
+
+ d->m_topLeftHandleDelegate = topLeftHandle;
+ emit topLeftHandleChanged();
+}
+
+QQmlComponent *QQuickSelectionRectangle::bottomRightHandle() const
+{
+ return d_func()->m_bottomRightHandleDelegate;
+}
+
+void QQuickSelectionRectangle::setBottomRightHandle(QQmlComponent *bottomRightHandle)
+{
+ Q_D(QQuickSelectionRectangle);
+ if (d->m_bottomRightHandleDelegate == bottomRightHandle)
+ return;
+
+ d->m_bottomRightHandleDelegate = bottomRightHandle;
+ emit bottomRightHandleChanged();
+}
+
+QQuickSelectionRectangleAttached *QQuickSelectionRectangle::qmlAttachedProperties(QObject *obj)
+{
+ return new QQuickSelectionRectangleAttached(obj);
+}
+
+QQuickSelectionRectangleAttached::QQuickSelectionRectangleAttached(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QQuickSelectionRectangle *QQuickSelectionRectangleAttached::control() const
+{
+ return m_control;
+}
+
+void QQuickSelectionRectangleAttached::setControl(QQuickSelectionRectangle *control)
+{
+ if (m_control == control)
+ return;
+
+ m_control = control;
+ emit controlChanged();
+}
+
+bool QQuickSelectionRectangleAttached::dragging() const
+{
+ return m_dragging;
+}
+
+void QQuickSelectionRectangleAttached::setDragging(bool dragging)
+{
+ if (m_dragging == dragging)
+ return;
+
+ m_dragging = dragging;
+ emit draggingChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickselectionrectangle_p.cpp"
diff --git a/src/quicktemplates2/qquickselectionrectangle_p.h b/src/quicktemplates2/qquickselectionrectangle_p.h
new file mode 100644
index 0000000000..57d7706440
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle_p.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSELECTIONRECTANGLE_P_H
+#define QQUICKSELECTIONRECTANGLE_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/qquickitem.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSelectionRectanglePrivate;
+class QQuickSelectable;
+class QQuickSelectionRectangleAttached;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSelectionRectangle : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(SelectionMode selectionMode READ selectionMode WRITE setSelectionMode NOTIFY selectionModeChanged FINAL)
+ Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged FINAL)
+ Q_PROPERTY(QQmlComponent *topLeftHandle READ topLeftHandle WRITE setTopLeftHandle NOTIFY topLeftHandleChanged FINAL)
+ Q_PROPERTY(QQmlComponent *bottomRightHandle READ bottomRightHandle WRITE setBottomRightHandle NOTIFY bottomRightHandleChanged FINAL)
+ Q_PROPERTY(bool active READ active NOTIFY activeChanged FINAL)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
+
+ QML_NAMED_ELEMENT(SelectionRectangle)
+ QML_ATTACHED(QQuickSelectionRectangleAttached)
+ QML_ADDED_IN_VERSION(6, 2)
+
+public:
+ enum SelectionMode {
+ Drag,
+ PressAndHold,
+ Auto
+ };
+ Q_ENUM(SelectionMode)
+
+ explicit QQuickSelectionRectangle(QQuickItem *parent = nullptr);
+
+ QQuickItem *target() const;
+ void setTarget(QQuickItem *target);
+
+ bool active();
+ bool dragging();
+
+ SelectionMode selectionMode() const;
+ void setSelectionMode(SelectionMode selectionMode);
+
+ QQmlComponent *topLeftHandle() const;
+ void setTopLeftHandle(QQmlComponent *topLeftHandle);
+ QQmlComponent *bottomRightHandle() const;
+ void setBottomRightHandle(QQmlComponent *bottomRightHandle);
+
+ static QQuickSelectionRectangleAttached *qmlAttachedProperties(QObject *obj);
+
+Q_SIGNALS:
+ void targetChanged();
+ void activeChanged();
+ void draggingChanged();
+ void topLeftHandleChanged();
+ void bottomRightHandleChanged();
+ void selectionModeChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSelectionRectangle)
+ Q_DECLARE_PRIVATE(QQuickSelectionRectangle)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSelectionRectangleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickSelectionRectangle *control READ control NOTIFY controlChanged FINAL)
+ Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged FINAL)
+
+public:
+ QQuickSelectionRectangleAttached(QObject *parent);
+
+ QQuickSelectionRectangle *control() const;
+ void setControl(QQuickSelectionRectangle *control);
+
+ bool dragging() const;
+ void setDragging(bool dragging);
+
+Q_SIGNALS:
+ void controlChanged();
+ void draggingChanged();
+
+private:
+ QPointer<QQuickSelectionRectangle> m_control;
+ bool m_dragging = false;
+
+ friend class QQuickSelectionRectanglePrivate;
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSelectionRectangle)
+
+#endif // QQUICKSELECTIONRECTANGLE_P_H
diff --git a/src/quicktemplates2/qquickselectionrectangle_p_p.h b/src/quicktemplates2/qquickselectionrectangle_p_p.h
new file mode 100644
index 0000000000..a42e9e78bc
--- /dev/null
+++ b/src/quicktemplates2/qquickselectionrectangle_p_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSELECTIONRECTANGLE_P_P_H
+#define QQUICKSELECTIONRECTANGLE_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 "qquickselectionrectangle_p.h"
+
+#include <QtCore/qpointer.h>
+#include <QtCore/qtimer.h>
+
+#include <QtQuick/private/qquickselectable_p.h>
+#include <QtQuick/private/qquicktaphandler_p.h>
+#include <QtQuick/private/qquickdraghandler_p.h>
+
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSelectionRectanglePrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSelectionRectangle)
+
+public:
+ QQuickSelectionRectanglePrivate();
+
+ void updateDraggingState(bool isDragging);
+ void updateActiveState(bool isActive);
+ void updateHandles();
+ void updateSelectionMode();
+ void connectToTarget();
+ void scrollTowardsPos(const QPointF &pos);
+ QQuickItem *handleUnderPos(const QPointF &pos);
+
+ QQuickItem *createHandle(QQmlComponent *delegate, Qt::Corner corner);
+
+ QQuickSelectionRectangleAttached *getAttachedObject(const QObject *object) const;
+
+public:
+ QPointer<QQuickItem> m_target;
+
+ QQmlComponent *m_topLeftHandleDelegate = nullptr;
+ QQmlComponent *m_bottomRightHandleDelegate = nullptr;
+ QPointer<QQuickItem> m_topLeftHandle;
+ QPointer<QQuickItem> m_bottomRightHandle;
+ QPointer<QQuickItem> m_draggedHandle = nullptr;
+
+ QQuickSelectable *m_selectable = nullptr;
+
+ QQuickTapHandler *m_tapHandler = nullptr;
+ QQuickDragHandler *m_dragHandler = nullptr;
+
+ QTimer m_scrollTimer;
+ QPointF m_scrollToPoint;
+ QSizeF m_scrollSpeed = QSizeF(1, 1);
+
+ QQuickSelectionRectangle::SelectionMode m_selectionMode = QQuickSelectionRectangle::Auto;
+ bool m_alwaysAcceptPressAndHold = false;
+
+ bool m_enabled = true;
+ bool m_active = false;
+ bool m_dragging = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSELECTIONRECTANGLE_P_P_H
diff --git a/src/quicktemplates2/qquickshortcutcontext.cpp b/src/quicktemplates2/qquickshortcutcontext.cpp
new file mode 100644
index 0000000000..9237017dfa
--- /dev/null
+++ b/src/quicktemplates2/qquickshortcutcontext.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickshortcutcontext_p_p.h"
+#include "qquickoverlay_p_p.h"
+#include "qquicktooltip_p.h"
+#include "qquickmenu_p.h"
+#include "qquickmenu_p_p.h"
+#include "qquickpopup_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQuick/qquickrendercontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcContextMatcher, "qt.quick.controls.shortcutcontext.matcher")
+
+static bool isBlockedByPopup(QQuickItem *item)
+{
+ if (!item || !item->window())
+ return false;
+
+ QQuickOverlay *overlay = QQuickOverlay::overlay(item->window());
+ const auto popups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups();
+ for (QQuickPopup *popup : popups) {
+ if (qobject_cast<QQuickToolTip *>(popup))
+ continue; // ignore tooltips (QTBUG-60492)
+ if (popup->isModal() || popup->closePolicy() & QQuickPopup::CloseOnEscape) {
+ return item != popup->popupItem() && !popup->popupItem()->isAncestorOf(item);
+ }
+ }
+
+ return false;
+}
+
+bool QQuickShortcutContext::matcher(QObject *obj, Qt::ShortcutContext context)
+{
+ QQuickItem *item = nullptr;
+ switch (context) {
+ case Qt::ApplicationShortcut:
+ return true;
+ case Qt::WindowShortcut:
+ while (obj && !obj->isWindowType()) {
+ item = qobject_cast<QQuickItem *>(obj);
+ if (item && item->window()) {
+ obj = item->window();
+ break;
+ } else if (QQuickPopup *popup = qobject_cast<QQuickPopup *>(obj)) {
+ obj = popup->window();
+ item = popup->popupItem();
+
+ if (!obj) {
+ // The popup has no associated window (yet). However, sub-menus,
+ // unlike top-level menus, will not have an associated window
+ // until their parent menu is opened. So, check if this is a sub-menu
+ // so that actions within it can grab shortcuts.
+ if (auto *menu = qobject_cast<QQuickMenu *>(popup)) {
+ auto parentMenu = QQuickMenuPrivate::get(menu)->parentMenu;
+ while (!obj && parentMenu)
+ obj = parentMenu->window();
+ }
+ }
+ break;
+ }
+ obj = obj->parent();
+ }
+ if (QWindow *renderWindow = QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow *>(obj)))
+ obj = renderWindow;
+ qCDebug(lcContextMatcher) << "obj" << obj << "focusWindow" << QGuiApplication::focusWindow()
+ << "!isBlockedByPopup(item)" << !isBlockedByPopup(item);
+ return obj && obj == QGuiApplication::focusWindow() && !isBlockedByPopup(item);
+ default:
+ return false;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickshortcutcontext_p_p.h b/src/quicktemplates2/qquickshortcutcontext_p_p.h
new file mode 100644
index 0000000000..44e63f1e0e
--- /dev/null
+++ b/src/quicktemplates2/qquickshortcutcontext_p_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSHORTCUTCONTEXT_P_P_H
+#define QQUICKSHORTCUTCONTEXT_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 <QtCore/qnamespace.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+
+struct Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickShortcutContext
+{
+ static bool matcher(QObject *object, Qt::ShortcutContext context);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSHORTCUTCONTEXT_P_P_H
diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp
new file mode 100644
index 0000000000..1aa3e43ff1
--- /dev/null
+++ b/src/quicktemplates2/qquickslider.cpp
@@ -0,0 +1,895 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickslider_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtQuick/private/qquickwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Slider
+ \inherits Control
+//! \instantiates QQuickSlider
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \brief Used to select a value by sliding a handle along a track.
+
+ \image qtquickcontrols2-slider.gif
+
+ Slider is used to select a value by sliding a handle along a track.
+
+ In the example below, custom \l from, \l value, and \l to values are set:
+
+ \code
+ Slider {
+ from: 1
+ value: 25
+ to: 100
+ }
+ \endcode
+
+ The \l position property is expressed as a fraction of the control's size,
+ in the range \c {0.0 - 1.0}. The \l visualPosition property is
+ the same, except that it is reversed in a
+ \l {Right-to-left User Interfaces}{right-to-left} application. The
+ visualPosition is useful for positioning the handle when styling Slider.
+ In the example above, \l visualPosition will be \c 0.24 in a left-to-right
+ application, and \c 0.76 in a right-to-left application.
+
+ For a slider that allows the user to select a range by providing two
+ handles, see \l RangeSlider.
+
+ \sa {Customizing Slider}, {Input Controls}
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal QtQuick.Controls::Slider::moved()
+
+ This signal is emitted when the slider has been interactively moved
+ by the user by either touch, mouse, wheel, or keys.
+*/
+
+class QQuickSliderPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSlider)
+
+public:
+ qreal snapPosition(qreal position) const;
+ qreal positionAt(const QPointF &point) const;
+ void setPosition(qreal position);
+ void updatePosition();
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void cancelHandle();
+ void executeHandle(bool complete = false);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ qreal from = 0;
+ qreal to = 1;
+ qreal value = 0;
+ qreal position = 0;
+ qreal stepSize = 0;
+ qreal touchDragThreshold = -1; // in QQuickWindowPrivate::dragOverThreshold, '-1' implies using styleHints::startDragDistance()
+ bool live = true;
+ bool pressed = false;
+ QPointF pressPoint;
+ Qt::Orientation orientation = Qt::Horizontal;
+ QQuickSlider::SnapMode snapMode = QQuickSlider::NoSnap;
+ QQuickDeferredPointer<QQuickItem> handle;
+};
+
+qreal QQuickSliderPrivate::snapPosition(qreal position) const
+{
+ const qreal range = to - from;
+ if (qFuzzyIsNull(range))
+ return position;
+
+ const qreal effectiveStep = stepSize / range;
+ if (qFuzzyIsNull(effectiveStep))
+ return position;
+
+ return qRound(position / effectiveStep) * effectiveStep;
+}
+
+qreal QQuickSliderPrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickSlider);
+ qreal pos = 0.0;
+ if (orientation == Qt::Horizontal) {
+ const qreal hw = handle ? handle->width() : 0;
+ const qreal offset = hw / 2;
+ const qreal extent = q->availableWidth() - hw;
+ if (!qFuzzyIsNull(extent)) {
+ if (q->isMirrored())
+ pos = (q->width() - point.x() - q->rightPadding() - offset) / extent;
+ else
+ pos = (point.x() - q->leftPadding() - offset) / extent;
+ }
+ } else {
+ const qreal hh = handle ? handle->height() : 0;
+ const qreal offset = hh / 2;
+ const qreal extent = q->availableHeight() - hh;
+ if (!qFuzzyIsNull(extent))
+ pos = (q->height() - point.y() - q->bottomPadding() - offset) / extent;
+ }
+ return qBound<qreal>(0.0, pos, 1.0);
+}
+
+void QQuickSliderPrivate::setPosition(qreal pos)
+{
+ Q_Q(QQuickSlider);
+ pos = qBound<qreal>(0.0, pos, 1.0);
+ if (qFuzzyCompare(position, pos))
+ return;
+
+ position = pos;
+ emit q->positionChanged();
+ emit q->visualPositionChanged();
+}
+
+void QQuickSliderPrivate::updatePosition()
+{
+ qreal pos = 0;
+ if (!qFuzzyCompare(from, to))
+ pos = (value - from) / (to - from);
+ setPosition(pos);
+}
+
+void QQuickSliderPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::handlePress(point);
+ pressPoint = point;
+ q->setPressed(true);
+}
+
+void QQuickSliderPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::handleMove(point);
+ const qreal oldPos = position;
+ qreal pos = positionAt(point);
+ if (snapMode == QQuickSlider::SnapAlways)
+ pos = snapPosition(pos);
+ if (live)
+ q->setValue(q->valueAt(pos));
+ if (!live || snapMode == QQuickSlider::NoSnap || snapMode == QQuickSlider::SnapOnRelease)
+ setPosition(pos);
+ if (!qFuzzyCompare(pos, oldPos))
+ emit q->moved();
+}
+
+void QQuickSliderPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::handleRelease(point);
+ pressPoint = QPointF();
+ const qreal oldPos = position;
+ qreal pos = positionAt(point);
+ if (snapMode != QQuickSlider::NoSnap)
+ pos = snapPosition(pos);
+ qreal val = q->valueAt(pos);
+ if (!qFuzzyCompare(val, value))
+ q->setValue(val);
+ else if (snapMode != QQuickSlider::NoSnap)
+ setPosition(pos);
+ if (!qFuzzyCompare(pos, oldPos))
+ emit q->moved();
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+ q->setPressed(false);
+}
+
+void QQuickSliderPrivate::handleUngrab()
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::handleUngrab();
+ pressPoint = QPointF();
+ q->setPressed(false);
+}
+
+static inline QString handleName() { return QStringLiteral("handle"); }
+
+void QQuickSliderPrivate::cancelHandle()
+{
+ Q_Q(QQuickSlider);
+ quickCancelDeferred(q, handleName());
+}
+
+void QQuickSliderPrivate::executeHandle(bool complete)
+{
+ Q_Q(QQuickSlider);
+ if (handle.wasExecuted())
+ return;
+
+ if (!handle || complete)
+ quickBeginDeferred(q, handleName(), handle);
+ if (complete)
+ quickCompleteDeferred(q, handleName(), handle);
+}
+
+void QQuickSliderPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ if (item == handle)
+ emit q->implicitHandleWidthChanged();
+}
+
+void QQuickSliderPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickSlider);
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ if (item == handle)
+ emit q->implicitHandleHeightChanged();
+}
+
+QQuickSlider::QQuickSlider(QQuickItem *parent)
+ : QQuickControl(*(new QQuickSliderPrivate), parent)
+{
+ setActiveFocusOnTab(true);
+#ifdef Q_OS_MACOS
+ setFocusPolicy(Qt::TabFocus);
+#else
+ setFocusPolicy(Qt::StrongFocus);
+#endif
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(quicktemplates2_multitouch)
+ setAcceptTouchEvents(true);
+#endif
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickSlider::~QQuickSlider()
+{
+ Q_D(QQuickSlider);
+ d->removeImplicitSizeListener(d->handle);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::from
+
+ This property holds the starting value for the range. The default value is \c 0.0.
+
+ \sa to, value
+*/
+qreal QQuickSlider::from() const
+{
+ Q_D(const QQuickSlider);
+ return d->from;
+}
+
+void QQuickSlider::setFrom(qreal from)
+{
+ Q_D(QQuickSlider);
+ if (qFuzzyCompare(d->from, from))
+ return;
+
+ d->from = from;
+ emit fromChanged();
+ if (isComponentComplete()) {
+ setValue(d->value);
+ d->updatePosition();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::to
+
+ This property holds the end value for the range. The default value is \c 1.0.
+
+ \sa from, value
+*/
+qreal QQuickSlider::to() const
+{
+ Q_D(const QQuickSlider);
+ return d->to;
+}
+
+void QQuickSlider::setTo(qreal to)
+{
+ Q_D(QQuickSlider);
+ if (qFuzzyCompare(d->to, to))
+ return;
+
+ d->to = to;
+ emit toChanged();
+ if (isComponentComplete()) {
+ setValue(d->value);
+ d->updatePosition();
+ }
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::value
+
+ This property holds the value in the range \c from - \c to. The default value is \c 0.0.
+
+ \sa position
+*/
+qreal QQuickSlider::value() const
+{
+ Q_D(const QQuickSlider);
+ return d->value;
+}
+
+void QQuickSlider::setValue(qreal value)
+{
+ Q_D(QQuickSlider);
+ if (isComponentComplete())
+ value = d->from > d->to ? qBound(d->to, value, d->from) : qBound(d->from, value, d->to);
+
+ if (qFuzzyCompare(d->value, value))
+ return;
+
+ d->value = value;
+ d->updatePosition();
+ emit valueChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::position
+ \readonly
+
+ This property holds the logical position of the handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. For visualizing a slider, the right-to-left aware
+ \l visualPosition should be used instead.
+
+ \sa value, visualPosition, valueAt()
+*/
+qreal QQuickSlider::position() const
+{
+ Q_D(const QQuickSlider);
+ return d->position;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::visualPosition
+ \readonly
+
+ This property holds the visual position of the handle.
+
+ The position is expressed as a fraction of the control's size, in the range
+ \c {0.0 - 1.0}. When the control is \l {Control::mirrored}{mirrored}, the
+ value is equal to \c {1.0 - position}. This makes the value suitable for
+ visualizing the slider, taking right-to-left support into account.
+
+ \sa position
+*/
+qreal QQuickSlider::visualPosition() const
+{
+ Q_D(const QQuickSlider);
+ if (d->orientation == Qt::Vertical || isMirrored())
+ return 1.0 - d->position;
+ return d->position;
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Slider::stepSize
+
+ This property holds the step size. The default value is \c 0.0.
+
+ \sa snapMode, increase(), decrease()
+*/
+qreal QQuickSlider::stepSize() const
+{
+ Q_D(const QQuickSlider);
+ return d->stepSize;
+}
+
+void QQuickSlider::setStepSize(qreal step)
+{
+ Q_D(QQuickSlider);
+ if (qFuzzyCompare(d->stepSize, step))
+ return;
+
+ d->stepSize = step;
+ emit stepSizeChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Slider::snapMode
+
+ This property holds the snap mode.
+
+ The snap mode determines how the slider handle behaves with
+ regards to the \l stepSize.
+
+ Possible values:
+ \value Slider.NoSnap The slider does not snap (default).
+ \value Slider.SnapAlways The slider snaps while the handle is dragged.
+ \value Slider.SnapOnRelease The slider does not snap while being dragged, but only after the handle is released.
+
+ In the following table, the various modes are illustrated with animations.
+ The movement of the mouse cursor and the \l stepSize (\c 0.2) are identical
+ in each animation.
+
+ \table
+ \header
+ \row \li \b Value \li \b Example
+ \row \li \c Slider.NoSnap \li \image qtquickcontrols2-slider-nosnap.gif
+ \row \li \c Slider.SnapAlways \li \image qtquickcontrols2-slider-snapalways.gif
+ \row \li \c Slider.SnapOnRelease \li \image qtquickcontrols2-slider-snaponrelease.gif
+ \endtable
+
+ \sa stepSize
+*/
+QQuickSlider::SnapMode QQuickSlider::snapMode() const
+{
+ Q_D(const QQuickSlider);
+ return d->snapMode;
+}
+
+void QQuickSlider::setSnapMode(SnapMode mode)
+{
+ Q_D(QQuickSlider);
+ if (d->snapMode == mode)
+ return;
+
+ d->snapMode = mode;
+ emit snapModeChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Slider::pressed
+
+ This property holds whether the slider is pressed by either touch, mouse,
+ or keys.
+*/
+bool QQuickSlider::isPressed() const
+{
+ Q_D(const QQuickSlider);
+ return d->pressed;
+}
+
+void QQuickSlider::setPressed(bool pressed)
+{
+ Q_D(QQuickSlider);
+ if (d->pressed == pressed)
+ return;
+
+ d->pressed = pressed;
+ setAccessibleProperty("pressed", pressed);
+ emit pressedChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Slider::horizontal
+ \readonly
+
+ This property holds whether the slider is horizontal.
+
+ \sa orientation
+*/
+bool QQuickSlider::isHorizontal() const
+{
+ Q_D(const QQuickSlider);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::Slider::vertical
+ \readonly
+
+ This property holds whether the slider is vertical.
+
+ \sa orientation
+*/
+bool QQuickSlider::isVertical() const
+{
+ Q_D(const QQuickSlider);
+ return d->orientation == Qt::Vertical;
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Slider::orientation
+
+ This property holds the orientation.
+
+ Possible values:
+ \value Qt.Horizontal Horizontal (default)
+ \value Qt.Vertical Vertical
+
+ \sa horizontal, vertical
+*/
+Qt::Orientation QQuickSlider::orientation() const
+{
+ Q_D(const QQuickSlider);
+ return d->orientation;
+}
+
+void QQuickSlider::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickSlider);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ emit orientationChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Slider::handle
+
+ This property holds the handle item.
+
+ \sa {Customizing Slider}
+*/
+QQuickItem *QQuickSlider::handle() const
+{
+ QQuickSliderPrivate *d = const_cast<QQuickSliderPrivate *>(d_func());
+ if (!d->handle)
+ d->executeHandle();
+ return d->handle;
+}
+
+void QQuickSlider::setHandle(QQuickItem *handle)
+{
+ Q_D(QQuickSlider);
+ if (d->handle == handle)
+ return;
+
+ if (!d->handle.isExecuting())
+ d->cancelHandle();
+
+ const qreal oldImplicitHandleWidth = implicitHandleWidth();
+ const qreal oldImplicitHandleHeight = implicitHandleHeight();
+
+ d->removeImplicitSizeListener(d->handle);
+ QQuickControlPrivate::hideOldItem(d->handle);
+ d->handle = handle;
+
+ if (handle) {
+ if (!handle->parentItem())
+ handle->setParentItem(this);
+ d->addImplicitSizeListener(handle);
+ }
+
+ if (!qFuzzyCompare(oldImplicitHandleWidth, implicitHandleWidth()))
+ emit implicitHandleWidthChanged();
+ if (!qFuzzyCompare(oldImplicitHandleHeight, implicitHandleHeight()))
+ emit implicitHandleHeightChanged();
+ if (!d->handle.isExecuting())
+ emit handleChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlmethod real QtQuick.Controls::Slider::valueAt(real position)
+
+ Returns the value for the given \a position.
+
+ \sa value, position
+*/
+qreal QQuickSlider::valueAt(qreal position) const
+{
+ Q_D(const QQuickSlider);
+ const qreal value = (d->to - d->from) * position;
+ if (qFuzzyIsNull(d->stepSize))
+ return d->from + value;
+ return d->from + qRound(value / d->stepSize) * d->stepSize;
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::Slider::live
+
+ This property holds whether the slider provides live updates for the \l value
+ property while the handle is dragged.
+
+ The default value is \c true.
+
+ \sa value, valueAt()
+*/
+bool QQuickSlider::live() const
+{
+ Q_D(const QQuickSlider);
+ return d->live;
+}
+
+void QQuickSlider::setLive(bool live)
+{
+ Q_D(QQuickSlider);
+ if (d->live == live)
+ return;
+
+ d->live = live;
+ emit liveChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Slider::increase()
+
+ Increases the value by \l stepSize or \c 0.1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickSlider::increase()
+{
+ Q_D(QQuickSlider);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(d->value + step);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Slider::decrease()
+
+ Decreases the value by \l stepSize or \c 0.1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickSlider::decrease()
+{
+ Q_D(QQuickSlider);
+ qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(d->value - step);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty qreal QtQuick.Controls::Slider::touchDragThreshold
+
+ This property holds the threshold (in logical pixels) at which a touch drag event will be initiated.
+ The mouse drag threshold won't be affected.
+ The default value is \c Qt.styleHints.startDragDistance.
+
+ \sa QStyleHints
+*/
+qreal QQuickSlider::touchDragThreshold() const
+{
+ Q_D(const QQuickSlider);
+ return d->touchDragThreshold;
+}
+
+void QQuickSlider::setTouchDragThreshold(qreal touchDragThreshold)
+{
+ Q_D(QQuickSlider);
+ if (d->touchDragThreshold == touchDragThreshold)
+ return;
+
+ d->touchDragThreshold = touchDragThreshold;
+ emit touchDragThresholdChanged();
+}
+
+void QQuickSlider::resetTouchDragThreshold()
+{
+ setTouchDragThreshold(-1);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Slider::implicitHandleWidth
+ \readonly
+
+ This property holds the implicit handle width.
+
+ The value is equal to \c {handle ? handle.implicitWidth : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentWidth} and
+ \l {Control::}{implicitBackgroundWidth}, to calculate the \l {Item::}{implicitWidth}.
+
+ \sa implicitHandleHeight
+*/
+qreal QQuickSlider::implicitHandleWidth() const
+{
+ Q_D(const QQuickSlider);
+ if (!d->handle)
+ return 0;
+ return d->handle->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::Slider::implicitHandleHeight
+ \readonly
+
+ This property holds the implicit handle height.
+
+ The value is equal to \c {handle ? handle.implicitHeight : 0}.
+
+ This is typically used, together with \l {Control::}{implicitContentHeight} and
+ \l {Control::}{implicitBackgroundHeight}, to calculate the \l {Item::}{implicitHeight}.
+
+ \sa implicitHandleWidth
+*/
+qreal QQuickSlider::implicitHandleHeight() const
+{
+ Q_D(const QQuickSlider);
+ if (!d->handle)
+ return 0;
+ return d->handle->implicitHeight();
+}
+
+void QQuickSlider::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickSlider);
+ QQuickControl::keyPressEvent(event);
+
+ const qreal oldValue = d->value;
+ if (d->orientation == Qt::Horizontal) {
+ if (event->key() == Qt::Key_Left) {
+ setPressed(true);
+ if (isMirrored())
+ increase();
+ else
+ decrease();
+ event->accept();
+ } else if (event->key() == Qt::Key_Right) {
+ setPressed(true);
+ if (isMirrored())
+ decrease();
+ else
+ increase();
+ event->accept();
+ }
+ } else {
+ if (event->key() == Qt::Key_Up) {
+ setPressed(true);
+ increase();
+ event->accept();
+ } else if (event->key() == Qt::Key_Down) {
+ setPressed(true);
+ decrease();
+ event->accept();
+ }
+ }
+ if (!qFuzzyCompare(d->value, oldValue))
+ emit moved();
+}
+
+void QQuickSlider::keyReleaseEvent(QKeyEvent *event)
+{
+ QQuickControl::keyReleaseEvent(event);
+ setPressed(false);
+}
+
+void QQuickSlider::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSlider);
+ QQuickControl::mousePressEvent(event);
+ d->handleMove(event->position());
+ setKeepMouseGrab(true);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickSlider::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickSlider);
+ switch (event->type()) {
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (!d->acceptTouch(point))
+ continue;
+
+ switch (point.state()) {
+ case QEventPoint::Pressed:
+ d->handlePress(point.position());
+ break;
+ case QEventPoint::Updated:
+ if (!keepTouchGrab()) {
+ if (d->orientation == Qt::Horizontal)
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(), Qt::XAxis, &point, qRound(d->touchDragThreshold)));
+ else
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().y() - d->pressPoint.y(), Qt::YAxis, &point, qRound(d->touchDragThreshold)));
+ }
+ if (keepTouchGrab())
+ d->handleMove(point.position());
+ break;
+ case QEventPoint::Released:
+ d->handleRelease(point.position());
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ QQuickControl::touchEvent(event);
+ break;
+ }
+}
+#endif
+
+#if QT_CONFIG(wheelevent)
+void QQuickSlider::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickSlider);
+ QQuickControl::wheelEvent(event);
+ if (d->wheelEnabled) {
+ const qreal oldValue = d->value;
+ const QPointF angle = event->angleDelta();
+ const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : (event->inverted() ? -angle.y() : angle.y())) / int(QWheelEvent::DefaultDeltasPerStep);
+ const qreal step = qFuzzyIsNull(d->stepSize) ? 0.1 : d->stepSize;
+ setValue(oldValue + step * delta);
+ const bool wasMoved = !qFuzzyCompare(d->value, oldValue);
+ if (wasMoved)
+ emit moved();
+ }
+}
+#endif
+
+void QQuickSlider::mirrorChange()
+{
+ QQuickControl::mirrorChange();
+ emit visualPositionChanged();
+}
+
+void QQuickSlider::componentComplete()
+{
+ Q_D(QQuickSlider);
+ d->executeHandle(true);
+ QQuickControl::componentComplete();
+ setValue(d->value);
+ d->updatePosition();
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickSlider::accessibilityActiveChanged(bool active)
+{
+ QQuickControl::accessibilityActiveChanged(active);
+
+ Q_D(QQuickSlider);
+ if (active)
+ setAccessibleProperty("pressed", d->pressed);
+}
+
+QAccessible::Role QQuickSlider::accessibleRole() const
+{
+ return QAccessible::Slider;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickslider_p.cpp"
diff --git a/src/quicktemplates2/qquickslider_p.h b/src/quicktemplates2/qquickslider_p.h
new file mode 100644
index 0000000000..ac03f7f996
--- /dev/null
+++ b/src/quicktemplates2/qquickslider_p.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSLIDER_P_H
+#define QQUICKSLIDER_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSliderPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSlider : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(qreal to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(qreal value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(qreal position READ position NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
+ Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL)
+ Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION(2, 2))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION(2, 3))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(qreal touchDragThreshold READ touchDragThreshold WRITE setTouchDragThreshold RESET resetTouchDragThreshold NOTIFY touchDragThresholdChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitHandleWidth READ implicitHandleWidth NOTIFY implicitHandleWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitHandleHeight READ implicitHandleHeight NOTIFY implicitHandleHeightChanged FINAL REVISION(2, 5))
+ Q_CLASSINFO("DeferredPropertyNames", "background,handle")
+ QML_NAMED_ELEMENT(Slider)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSlider(QQuickItem *parent = nullptr);
+ ~QQuickSlider();
+
+ qreal from() const;
+ void setFrom(qreal from);
+
+ qreal to() const;
+ void setTo(qreal to);
+
+ qreal value() const;
+ void setValue(qreal value);
+
+ qreal position() const;
+ qreal visualPosition() const;
+
+ qreal stepSize() const;
+ void setStepSize(qreal step);
+
+ enum SnapMode {
+ NoSnap,
+ SnapAlways,
+ SnapOnRelease
+ };
+ Q_ENUM(SnapMode)
+
+ SnapMode snapMode() const;
+ void setSnapMode(SnapMode mode);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ QQuickItem *handle() const;
+ void setHandle(QQuickItem *handle);
+
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) Q_INVOKABLE qreal valueAt(qreal position) const;
+
+ // 2.2 (Qt 5.9)
+ bool live() const;
+ void setLive(bool live);
+
+ // 2.3 (Qt 5.10)
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+ // 2.5 (Qt 5.12)
+ qreal touchDragThreshold() const;
+ void setTouchDragThreshold(qreal touchDragThreshold);
+ void resetTouchDragThreshold();
+
+ qreal implicitHandleWidth() const;
+ qreal implicitHandleHeight() const;
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void valueChanged();
+ void positionChanged();
+ void visualPositionChanged();
+ void stepSizeChanged();
+ void snapModeChanged();
+ void pressedChanged();
+ void orientationChanged();
+ void handleChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void moved();
+ Q_REVISION(2, 2) void liveChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void touchDragThresholdChanged();
+ Q_REVISION(2, 5) void implicitHandleWidthChanged();
+ Q_REVISION(2, 5) void implicitHandleHeightChanged();
+
+protected:
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ void mirrorChange() override;
+ void componentComplete() override;
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickSlider)
+ Q_DECLARE_PRIVATE(QQuickSlider)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSlider)
+
+#endif // QQUICKSLIDER_P_H
diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp
new file mode 100644
index 0000000000..f0d34c3659
--- /dev/null
+++ b/src/quicktemplates2/qquickspinbox.cpp
@@ -0,0 +1,1064 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 <QtQml/qqmlinfo.h>
+#include <QtQml/private/qqmllocale_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// copied from qabstractbutton.cpp
+static const int AUTO_REPEAT_DELAY = 300;
+static const int AUTO_REPEAT_INTERVAL = 100;
+
+/*!
+ \qmltype SpinBox
+ \inherits Control
+//! \instantiates QQuickSpinBox
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup input
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Allows the user to select from a set of preset values.
+
+ \image qtquickcontrols2-spinbox.png
+
+ SpinBox allows the user to choose an integer value by clicking the up
+ or down indicator buttons, or by pressing up or down on the keyboard.
+ Optionally, SpinBox can be also made \l editable, so the user can enter
+ a text value in the input field.
+
+ By default, SpinBox provides discrete values in the range of \c [0-99]
+ with a \l stepSize of \c 1.
+
+ \snippet qtquickcontrols2-spinbox.qml 1
+
+ \section2 Custom Values
+
+ \image qtquickcontrols2-spinbox-textual.png
+
+ Even though SpinBox works on integer values, it can be customized to
+ accept arbitrary input values. The following snippet demonstrates how
+ \l validator, \l textFromValue and \l valueFromText can be used to
+ customize the default behavior.
+
+ \snippet qtquickcontrols2-spinbox-textual.qml 1
+
+ In the same manner, SpinBox can be customized to accept floating point
+ numbers:
+
+ \image qtquickcontrols2-spinbox-double.png
+
+ \snippet qtquickcontrols2-spinbox-double.qml 1
+
+ \sa Tumbler, {Customizing SpinBox}, {Focus Management in Qt Quick Controls}
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal QtQuick.Controls::SpinBox::valueModified()
+
+ This signal is emitted when the spin box value has been interactively
+ modified by the user by either touch, mouse, wheel, or keys.
+ In the case of interaction via keyboard, the signal is only emitted
+ when the text has been accepted; meaning when the enter or return keys
+ are pressed, or the input field loses focus.
+*/
+
+class QQuickSpinBoxPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSpinBox)
+
+public:
+ int boundValue(int value, bool wrap) const;
+ void updateValue();
+ bool setValue(int value, bool wrap, bool modified);
+ bool stepBy(int steps, bool modified);
+ void increase(bool modified);
+ void decrease(bool modified);
+
+ int effectiveStepSize() const;
+
+ void updateDisplayText(bool modified = false);
+ void setDisplayText(const QString &displayText, bool modified = false);
+
+ bool upEnabled() const;
+ void updateUpEnabled();
+ bool downEnabled() const;
+ void updateDownEnabled();
+ void updateHover(const QPointF &pos);
+
+ void startRepeatDelay();
+ void startPressRepeat();
+ void stopPressRepeat();
+
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+ void handleUngrab() override;
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::SpinBox); }
+
+ bool editable = false;
+ bool wrap = false;
+ int from = 0;
+ int to = 99;
+ int value = 0;
+ int stepSize = 1;
+ int delayTimer = 0;
+ int repeatTimer = 0;
+ QString displayText;
+ QQuickIndicatorButton *up = nullptr;
+ QQuickIndicatorButton *down = nullptr;
+ QValidator *validator = nullptr;
+ mutable QJSValue textFromValue;
+ mutable QJSValue valueFromText;
+ Qt::InputMethodHints inputMethodHints = Qt::ImhDigitsOnly;
+};
+
+int QQuickSpinBoxPrivate::boundValue(int value, bool wrap) const
+{
+ bool inverted = from > to;
+ if (!wrap)
+ return inverted ? qBound(to, value, from) : qBound(from, value, to);
+
+ int f = inverted ? to : from;
+ int t = inverted ? from : to;
+ if (value < f)
+ value = t;
+ else if (value > t)
+ value = f;
+
+ return value;
+}
+
+void QQuickSpinBoxPrivate::updateValue()
+{
+ Q_Q(QQuickSpinBox);
+ if (contentItem) {
+ QVariant text = contentItem->property("text");
+ if (text.isValid()) {
+ int val = 0;
+ QQmlEngine *engine = qmlEngine(q);
+ if (engine && valueFromText.isCallable()) {
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+ QJSValue loc = QJSValuePrivate::fromReturnedValue(QQmlLocale::wrap(v4, locale));
+ val = valueFromText.call(QJSValueList() << text.toString() << loc).toInt();
+ } else {
+ val = locale.toInt(text.toString());
+ }
+ setValue(val, /* allowWrap = */ false, /* modified = */ true);
+ }
+ }
+}
+
+// modified indicates if the value was modified by the user and not programatically
+// this is then passed on to updateDisplayText to indicate that the user has modified
+// the value so it may need to trigger an update of the contentItem's text too
+
+bool QQuickSpinBoxPrivate::setValue(int newValue, bool allowWrap, bool modified)
+{
+ Q_Q(QQuickSpinBox);
+ int correctedValue = newValue;
+ if (q->isComponentComplete())
+ correctedValue = boundValue(newValue, allowWrap);
+
+ if (!modified && newValue == correctedValue && newValue == value)
+ return false;
+
+ const bool emitSignals = (value != correctedValue);
+ value = correctedValue;
+
+ updateDisplayText(modified);
+ updateUpEnabled();
+ updateDownEnabled();
+
+ // Only emit the signals if the corrected value is not the same as the
+ // original value to avoid unnecessary updates
+ if (emitSignals) {
+ emit q->valueChanged();
+ if (modified)
+ emit q->valueModified();
+ }
+ return true;
+}
+
+bool QQuickSpinBoxPrivate::stepBy(int steps, bool modified)
+{
+ return setValue(value + steps, wrap, modified);
+}
+
+void QQuickSpinBoxPrivate::increase(bool modified)
+{
+ setValue(value + effectiveStepSize(), wrap, modified);
+}
+
+void QQuickSpinBoxPrivate::decrease(bool modified)
+{
+ setValue(value - effectiveStepSize(), wrap, modified);
+}
+
+int QQuickSpinBoxPrivate::effectiveStepSize() const
+{
+ return from > to ? -1 * stepSize : stepSize;
+}
+
+void QQuickSpinBoxPrivate::updateDisplayText(bool modified)
+{
+ Q_Q(QQuickSpinBox);
+ QString text;
+ QQmlEngine *engine = qmlEngine(q);
+ if (engine && textFromValue.isCallable()) {
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+ QJSValue loc = QJSValuePrivate::fromReturnedValue(QQmlLocale::wrap(v4, locale));
+ text = textFromValue.call(QJSValueList() << value << loc).toString();
+ } else {
+ text = locale.toString(value);
+ }
+ setDisplayText(text, modified);
+}
+
+void QQuickSpinBoxPrivate::setDisplayText(const QString &text, bool modified)
+{
+ Q_Q(QQuickSpinBox);
+
+ if (!modified && displayText == text)
+ return;
+
+ displayText = text;
+ emit q->displayTextChanged();
+}
+
+bool QQuickSpinBoxPrivate::upEnabled() const
+{
+ const QQuickItem *upIndicator = up->indicator();
+ return upIndicator && upIndicator->isEnabled();
+}
+
+void QQuickSpinBoxPrivate::updateUpEnabled()
+{
+ QQuickItem *upIndicator = up->indicator();
+ if (!upIndicator)
+ return;
+
+ upIndicator->setEnabled(wrap || (from < to ? value < to : value > to));
+}
+
+bool QQuickSpinBoxPrivate::downEnabled() const
+{
+ const QQuickItem *downIndicator = down->indicator();
+ return downIndicator && downIndicator->isEnabled();
+}
+
+void QQuickSpinBoxPrivate::updateDownEnabled()
+{
+ QQuickItem *downIndicator = down->indicator();
+ if (!downIndicator)
+ return;
+
+ downIndicator->setEnabled(wrap || (from < to ? value > from : value < from));
+}
+
+void QQuickSpinBoxPrivate::updateHover(const QPointF &pos)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setHovered(ui && ui->isEnabled() && ui->contains(q->mapToItem(ui, pos)));
+ down->setHovered(di && di->isEnabled() && di->contains(q->mapToItem(di, pos)));
+}
+
+void QQuickSpinBoxPrivate::startRepeatDelay()
+{
+ Q_Q(QQuickSpinBox);
+ stopPressRepeat();
+ delayTimer = q->startTimer(AUTO_REPEAT_DELAY);
+}
+
+void QQuickSpinBoxPrivate::startPressRepeat()
+{
+ Q_Q(QQuickSpinBox);
+ stopPressRepeat();
+ repeatTimer = q->startTimer(AUTO_REPEAT_INTERVAL);
+}
+
+void QQuickSpinBoxPrivate::stopPressRepeat()
+{
+ Q_Q(QQuickSpinBox);
+ if (delayTimer > 0) {
+ q->killTimer(delayTimer);
+ delayTimer = 0;
+ }
+ if (repeatTimer > 0) {
+ q->killTimer(repeatTimer);
+ repeatTimer = 0;
+ }
+}
+
+void QQuickSpinBoxPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickControlPrivate::handlePress(point);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setPressed(ui && ui->isEnabled() && ui->contains(ui->mapFromItem(q, point)));
+ down->setPressed(di && di->isEnabled() && di->contains(di->mapFromItem(q, point)));
+
+ bool pressed = up->isPressed() || down->isPressed();
+ q->setAccessibleProperty("pressed", pressed);
+ if (pressed)
+ startRepeatDelay();
+}
+
+void QQuickSpinBoxPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickControlPrivate::handleMove(point);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setHovered(ui && ui->isEnabled() && ui->contains(ui->mapFromItem(q, point)));
+ up->setPressed(up->isHovered());
+ down->setHovered(di && di->isEnabled() && di->contains(di->mapFromItem(q, point)));
+ down->setPressed(down->isHovered());
+
+ bool pressed = up->isPressed() || down->isPressed();
+ q->setAccessibleProperty("pressed", pressed);
+ if (!pressed)
+ stopPressRepeat();
+}
+
+void QQuickSpinBoxPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickControlPrivate::handleRelease(point);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+
+ int oldValue = value;
+ if (up->isPressed()) {
+ up->setPressed(false);
+ if (repeatTimer <= 0 && ui && ui->contains(ui->mapFromItem(q, point)))
+ q->increase();
+ } else if (down->isPressed()) {
+ down->setPressed(false);
+ if (repeatTimer <= 0 && di && di->contains(di->mapFromItem(q, point)))
+ q->decrease();
+ }
+ if (value != oldValue)
+ emit q->valueModified();
+
+ q->setAccessibleProperty("pressed", false);
+ stopPressRepeat();
+}
+
+void QQuickSpinBoxPrivate::handleUngrab()
+{
+ Q_Q(QQuickSpinBox);
+ QQuickControlPrivate::handleUngrab();
+ up->setPressed(false);
+ down->setPressed(false);
+
+ q->setAccessibleProperty("pressed", false);
+ stopPressRepeat();
+}
+
+void QQuickSpinBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitWidthChanged(item);
+ if (item == up->indicator())
+ emit up->implicitIndicatorWidthChanged();
+ else if (item == down->indicator())
+ emit down->implicitIndicatorWidthChanged();
+}
+
+void QQuickSpinBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickControlPrivate::itemImplicitHeightChanged(item);
+ if (item == up->indicator())
+ emit up->implicitIndicatorHeightChanged();
+ else if (item == down->indicator())
+ emit down->implicitIndicatorHeightChanged();
+}
+
+QQuickSpinBox::QQuickSpinBox(QQuickItem *parent)
+ : QQuickControl(*(new QQuickSpinBoxPrivate), parent)
+{
+ Q_D(QQuickSpinBox);
+ d->up = new QQuickIndicatorButton(this);
+ d->down = new QQuickIndicatorButton(this);
+
+ setFlag(ItemIsFocusScope);
+ setFiltersChildMouseEvents(true);
+ setAcceptedMouseButtons(Qt::LeftButton);
+#if QT_CONFIG(cursor)
+ setCursor(Qt::ArrowCursor);
+#endif
+}
+
+QQuickSpinBox::~QQuickSpinBox()
+{
+ Q_D(QQuickSpinBox);
+ d->removeImplicitSizeListener(d->up->indicator());
+ d->removeImplicitSizeListener(d->down->indicator());
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::SpinBox::from
+
+ This property holds the starting value for the range. The default value is \c 0.
+
+ \sa to, value
+*/
+int QQuickSpinBox::from() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->from;
+}
+
+void QQuickSpinBox::setFrom(int from)
+{
+ Q_D(QQuickSpinBox);
+ if (d->from == from)
+ return;
+
+ d->from = from;
+ emit fromChanged();
+ if (isComponentComplete()) {
+ if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
+ d->updateUpEnabled();
+ d->updateDownEnabled();
+ }
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::SpinBox::to
+
+ This property holds the end value for the range. The default value is \c 99.
+
+ \sa from, value
+*/
+int QQuickSpinBox::to() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->to;
+}
+
+void QQuickSpinBox::setTo(int to)
+{
+ Q_D(QQuickSpinBox);
+ if (d->to == to)
+ return;
+
+ d->to = to;
+ emit toChanged();
+ if (isComponentComplete()) {
+ if (!d->setValue(d->value, /* allowWrap = */false, /* modified = */ false)) {
+ d->updateUpEnabled();
+ d->updateDownEnabled();
+ }
+ }
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::SpinBox::value
+
+ This property holds the value in the range \c from - \c to. The default value is \c 0.
+*/
+int QQuickSpinBox::value() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->value;
+}
+
+void QQuickSpinBox::setValue(int value)
+{
+ Q_D(QQuickSpinBox);
+ d->setValue(value, /* allowWrap = */ false, /* modified = */ false);
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::SpinBox::stepSize
+
+ This property holds the step size. The default value is \c 1.
+
+ \sa increase(), decrease()
+*/
+int QQuickSpinBox::stepSize() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->stepSize;
+}
+
+void QQuickSpinBox::setStepSize(int step)
+{
+ Q_D(QQuickSpinBox);
+ if (d->stepSize == step)
+ return;
+
+ d->stepSize = step;
+ emit stepSizeChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SpinBox::editable
+
+ This property holds whether the spinbox is editable. The default value is \c false.
+
+ \sa validator
+*/
+bool QQuickSpinBox::isEditable() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->editable;
+}
+
+void QQuickSpinBox::setEditable(bool editable)
+{
+ Q_D(QQuickSpinBox);
+ if (d->editable == editable)
+ return;
+
+#if QT_CONFIG(cursor)
+ if (d->contentItem) {
+ if (editable)
+ d->contentItem->setCursor(Qt::IBeamCursor);
+ else
+ d->contentItem->unsetCursor();
+ }
+#endif
+
+ d->editable = editable;
+ setAccessibleProperty("editable", editable);
+ emit editableChanged();
+}
+
+/*!
+ \qmlproperty Validator QtQuick.Controls::SpinBox::validator
+
+ This property holds the input text validator for editable spinboxes. By
+ default, SpinBox uses \l IntValidator to accept input of integer numbers.
+
+ \code
+ SpinBox {
+ id: control
+ validator: IntValidator {
+ locale: control.locale.name
+ bottom: Math.min(control.from, control.to)
+ top: Math.max(control.from, control.to)
+ }
+ }
+ \endcode
+
+ \sa editable, textFromValue, valueFromText, {Control::locale}{locale},
+ {Validating Input Text}
+*/
+QValidator *QQuickSpinBox::validator() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->validator;
+}
+
+void QQuickSpinBox::setValidator(QValidator *validator)
+{
+ Q_D(QQuickSpinBox);
+ if (d->validator == validator)
+ return;
+
+ d->validator = validator;
+ emit validatorChanged();
+}
+
+/*!
+ \qmlproperty function QtQuick.Controls::SpinBox::textFromValue
+
+ This property holds a callback function that is called whenever
+ an integer value needs to be converted to display text.
+
+ The default function can be overridden to display custom text for a given
+ value. This applies to both editable and non-editable spinboxes;
+ for example, when using the up and down buttons or a mouse wheel to
+ increment and decrement the value, the new value is converted to display
+ text using this function.
+
+ The callback function signature is \c {string function(value, locale)}.
+ The function can have one or two arguments, where the first argument
+ is the value to be converted, and the optional second argument is the
+ locale that should be used for the conversion, if applicable.
+
+ The default implementation does the conversion using
+ \l {QtQml::Number::toLocaleString()}{Number.toLocaleString}():
+
+ \code
+ textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }
+ \endcode
+
+ \note When applying a custom \c textFromValue implementation for editable
+ spinboxes, a matching \l valueFromText implementation must be provided
+ to be able to convert the custom text back to an integer value.
+
+ \sa valueFromText, validator, {Control::locale}{locale}
+*/
+QJSValue QQuickSpinBox::textFromValue() const
+{
+ Q_D(const QQuickSpinBox);
+ if (!d->textFromValue.isCallable()) {
+ QQmlEngine *engine = qmlEngine(this);
+ if (engine)
+ d->textFromValue = engine->evaluate(QStringLiteral("(function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); })"));
+ }
+ return d->textFromValue;
+}
+
+void QQuickSpinBox::setTextFromValue(const QJSValue &callback)
+{
+ Q_D(QQuickSpinBox);
+ if (!callback.isCallable()) {
+ qmlWarning(this) << "textFromValue must be a callable function";
+ return;
+ }
+ d->textFromValue = callback;
+ emit textFromValueChanged();
+}
+
+/*!
+ \qmlproperty function QtQuick.Controls::SpinBox::valueFromText
+
+ This property holds a callback function that is called whenever
+ input text needs to be converted to an integer value.
+
+ This function only needs to be overridden when \l textFromValue
+ is overridden for an editable spinbox.
+
+ The callback function signature is \c {int function(text, locale)}.
+ The function can have one or two arguments, where the first argument
+ is the text to be converted, and the optional second argument is the
+ locale that should be used for the conversion, if applicable.
+
+ The default implementation does the conversion using \l {QtQml::Locale}{Number.fromLocaleString()}:
+
+ \code
+ valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); }
+ \endcode
+
+ \note When applying a custom \l textFromValue implementation for editable
+ spinboxes, a matching \c valueFromText implementation must be provided
+ to be able to convert the custom text back to an integer value.
+
+ \sa textFromValue, validator, {Control::locale}{locale}
+*/
+QJSValue QQuickSpinBox::valueFromText() const
+{
+ Q_D(const QQuickSpinBox);
+ if (!d->valueFromText.isCallable()) {
+ QQmlEngine *engine = qmlEngine(this);
+ if (engine)
+ d->valueFromText = engine->evaluate(QStringLiteral("(function(text, locale) { return Number.fromLocaleString(locale, text); })"));
+ }
+ return d->valueFromText;
+}
+
+void QQuickSpinBox::setValueFromText(const QJSValue &callback)
+{
+ Q_D(QQuickSpinBox);
+ if (!callback.isCallable()) {
+ qmlWarning(this) << "valueFromText must be a callable function";
+ return;
+ }
+ d->valueFromText = callback;
+ emit valueFromTextChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SpinBox::up.pressed
+ \qmlproperty Item QtQuick.Controls::SpinBox::up.indicator
+ \qmlproperty bool QtQuick.Controls::SpinBox::up.hovered
+ \qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorWidth
+ \qmlproperty real QtQuick.Controls::SpinBox::up.implicitIndicatorHeight
+
+ These properties hold the up indicator item and whether it is pressed or
+ hovered. The \c up.hovered property was introduced in QtQuick.Controls 2.1,
+ and the \c up.implicitIndicatorWidth and \c up.implicitIndicatorHeight
+ properties were introduced in QtQuick.Controls 2.5.
+
+ \sa increase()
+*/
+QQuickIndicatorButton *QQuickSpinBox::up() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->up;
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SpinBox::down.pressed
+ \qmlproperty Item QtQuick.Controls::SpinBox::down.indicator
+ \qmlproperty bool QtQuick.Controls::SpinBox::down.hovered
+ \qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorWidth
+ \qmlproperty real QtQuick.Controls::SpinBox::down.implicitIndicatorHeight
+
+ These properties hold the down indicator item and whether it is pressed or
+ hovered. The \c down.hovered property was introduced in QtQuick.Controls 2.1,
+ and the \c down.implicitIndicatorWidth and \c down.implicitIndicatorHeight
+ properties were introduced in QtQuick.Controls 2.5.
+
+ \sa decrease()
+*/
+QQuickIndicatorButton *QQuickSpinBox::down() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->down;
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty flags QtQuick.Controls::SpinBox::inputMethodHints
+
+ This property provides hints to the input method about the expected content
+ of the spin box and how it should operate.
+
+ The default value is \c Qt.ImhDigitsOnly.
+
+ \include inputmethodhints.qdocinc
+*/
+Qt::InputMethodHints QQuickSpinBox::inputMethodHints() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->inputMethodHints;
+}
+
+void QQuickSpinBox::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QQuickSpinBox);
+ if (d->inputMethodHints == hints)
+ return;
+
+ d->inputMethodHints = hints;
+ emit inputMethodHintsChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty bool QtQuick.Controls::SpinBox::inputMethodComposing
+ \readonly
+
+ This property holds whether an editable spin box has partial text input from an input method.
+
+ While it is composing, an input method may rely on mouse or key events from the spin box to
+ edit or commit the partial text. This property can be used to determine when to disable event
+ handlers that may interfere with the correct operation of an input method.
+*/
+bool QQuickSpinBox::isInputMethodComposing() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->contentItem && d->contentItem->property("inputMethodComposing").toBool();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::SpinBox::wrap
+
+ This property holds whether the spinbox wraps. The default value is \c false.
+
+ If wrap is \c true, stepping past \l to changes the value to \l from and vice versa.
+*/
+bool QQuickSpinBox::wrap() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->wrap;
+}
+
+void QQuickSpinBox::setWrap(bool wrap)
+{
+ Q_D(QQuickSpinBox);
+ if (d->wrap == wrap)
+ return;
+
+ d->wrap = wrap;
+ if (d->value == d->from || d->value == d->to) {
+ d->updateUpEnabled();
+ d->updateDownEnabled();
+ }
+ emit wrapChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.4 (Qt 5.11)
+ \qmlproperty string QtQuick.Controls::SpinBox::displayText
+ \readonly
+
+ This property holds the textual value of the spinbox.
+
+ The value of the property is based on \l textFromValue and \l {Control::}
+ {locale}, and equal to:
+ \badcode
+ var text = spinBox.textFromValue(spinBox.value, spinBox.locale)
+ \endcode
+
+ \sa textFromValue
+*/
+QString QQuickSpinBox::displayText() const
+{
+ Q_D(const QQuickSpinBox);
+ return d->displayText;
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::SpinBox::increase()
+
+ Increases the value by \l stepSize, or \c 1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickSpinBox::increase()
+{
+ Q_D(QQuickSpinBox);
+ d->increase(false);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::SpinBox::decrease()
+
+ Decreases the value by \l stepSize, or \c 1 if stepSize is not defined.
+
+ \sa stepSize
+*/
+void QQuickSpinBox::decrease()
+{
+ Q_D(QQuickSpinBox);
+ d->decrease(false);
+}
+
+void QQuickSpinBox::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::focusInEvent(event);
+
+ // When an editable SpinBox gets focus, it must pass on the focus to its editor.
+ if (d->editable && d->contentItem && !d->contentItem->hasActiveFocus())
+ d->contentItem->forceActiveFocus(event->reason());
+}
+
+void QQuickSpinBox::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverEnterEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickSpinBox::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverMoveEvent(event);
+ d->updateHover(event->position());
+ event->ignore();
+}
+
+void QQuickSpinBox::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverLeaveEvent(event);
+ d->down->setHovered(false);
+ d->up->setHovered(false);
+ event->ignore();
+}
+
+void QQuickSpinBox::keyPressEvent(QKeyEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::keyPressEvent(event);
+
+ switch (event->key()) {
+ case Qt::Key_Up:
+ if (d->upEnabled()) {
+ d->increase(true);
+ d->up->setPressed(true);
+ event->accept();
+ }
+ break;
+
+ case Qt::Key_Down:
+ if (d->downEnabled()) {
+ d->decrease(true);
+ d->down->setPressed(true);
+ event->accept();
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ setAccessibleProperty("pressed", d->up->isPressed() || d->down->isPressed());
+}
+
+void QQuickSpinBox::keyReleaseEvent(QKeyEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::keyReleaseEvent(event);
+
+ if (d->editable && (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return))
+ d->updateValue();
+
+ d->up->setPressed(false);
+ d->down->setPressed(false);
+ setAccessibleProperty("pressed", false);
+}
+
+void QQuickSpinBox::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::timerEvent(event);
+ if (event->timerId() == d->delayTimer) {
+ d->startPressRepeat();
+ } else if (event->timerId() == d->repeatTimer) {
+ if (d->up->isPressed())
+ d->increase(true);
+ else if (d->down->isPressed())
+ d->decrease(true);
+ }
+}
+
+#if QT_CONFIG(wheelevent)
+void QQuickSpinBox::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::wheelEvent(event);
+ if (d->wheelEnabled) {
+ const QPointF angle = event->angleDelta();
+ const qreal delta = (qFuzzyIsNull(angle.y()) ? angle.x() : angle.y()) / int(QWheelEvent::DefaultDeltasPerStep);
+ d->stepBy(qRound(d->effectiveStepSize() * delta), true);
+ }
+}
+#endif
+
+void QQuickSpinBox::classBegin()
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::classBegin();
+
+ QQmlContext *context = qmlContext(this);
+ if (context) {
+ QQmlEngine::setContextForObject(d->up, context);
+ QQmlEngine::setContextForObject(d->down, context);
+ }
+}
+
+void QQuickSpinBox::componentComplete()
+{
+ Q_D(QQuickSpinBox);
+ QQuickIndicatorButtonPrivate::get(d->up)->executeIndicator(true);
+ QQuickIndicatorButtonPrivate::get(d->down)->executeIndicator(true);
+
+ QQuickControl::componentComplete();
+ if (!d->setValue(d->value, /* allowWrap = */ false, /* modified = */ false)) {
+ d->updateDisplayText();
+ d->updateUpEnabled();
+ d->updateDownEnabled();
+ }
+}
+
+void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::itemChange(change, value);
+ if (d->editable && change == ItemActiveFocusHasChanged && !value.boolValue)
+ d->updateValue();
+}
+
+void QQuickSpinBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickSpinBox);
+ if (QQuickTextInput *oldInput = qobject_cast<QQuickTextInput *>(oldItem))
+ disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
+
+ if (newItem) {
+ newItem->setActiveFocusOnTab(true);
+ if (d->activeFocus)
+ newItem->forceActiveFocus(d->focusReason);
+#if QT_CONFIG(cursor)
+ if (d->editable)
+ newItem->setCursor(Qt::IBeamCursor);
+#endif
+
+ if (QQuickTextInput *newInput = qobject_cast<QQuickTextInput *>(newItem))
+ connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickSpinBox::inputMethodComposingChanged);
+ }
+}
+
+void QQuickSpinBox::localeChange(const QLocale &newLocale, const QLocale &oldLocale)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::localeChange(newLocale, oldLocale);
+ d->updateDisplayText();
+}
+
+QFont QQuickSpinBox::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::SpinBox);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickSpinBox::accessibleRole() const
+{
+ return QAccessible::SpinBox;
+}
+
+void QQuickSpinBox::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::accessibilityActiveChanged(active);
+
+ if (active)
+ setAccessibleProperty("editable", d->editable);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquickspinbox_p.cpp"
diff --git a/src/quicktemplates2/qquickspinbox_p.h b/src/quicktemplates2/qquickspinbox_p.h
new file mode 100644
index 0000000000..9e64e96e32
--- /dev/null
+++ b/src/quicktemplates2/qquickspinbox_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSPINBOX_P_H
+#define QQUICKSPINBOX_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+#include <QtQml/qjsvalue.h>
+
+QT_BEGIN_NAMESPACE
+
+class QValidator;
+class QQuickSpinBoxPrivate;
+class QQuickIndicatorButton;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSpinBox : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(int from READ from WRITE setFrom NOTIFY fromChanged FINAL)
+ Q_PROPERTY(int to READ to WRITE setTo NOTIFY toChanged FINAL)
+ Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged FINAL)
+ Q_PROPERTY(int stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL)
+ Q_PROPERTY(bool editable READ isEditable WRITE setEditable NOTIFY editableChanged FINAL)
+ Q_PROPERTY(QValidator *validator READ validator WRITE setValidator NOTIFY validatorChanged FINAL)
+ Q_PROPERTY(QJSValue textFromValue READ textFromValue WRITE setTextFromValue NOTIFY textFromValueChanged FINAL)
+ Q_PROPERTY(QJSValue valueFromText READ valueFromText WRITE setValueFromText NOTIFY valueFromTextChanged FINAL)
+ Q_PROPERTY(QQuickIndicatorButton *up READ up CONSTANT FINAL)
+ Q_PROPERTY(QQuickIndicatorButton *down READ down CONSTANT FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints NOTIFY inputMethodHintsChanged FINAL REVISION(2, 2))
+ Q_PROPERTY(bool inputMethodComposing READ isInputMethodComposing NOTIFY inputMethodComposingChanged FINAL REVISION(2, 2))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap NOTIFY wrapChanged FINAL REVISION(2, 3))
+ // 2.4 (Qt 5.11)
+ Q_PROPERTY(QString displayText READ displayText NOTIFY displayTextChanged FINAL REVISION(2, 4))
+ QML_NAMED_ELEMENT(SpinBox)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSpinBox(QQuickItem *parent = nullptr);
+ ~QQuickSpinBox();
+
+ int from() const;
+ void setFrom(int from);
+
+ int to() const;
+ void setTo(int to);
+
+ int value() const;
+ void setValue(int value);
+
+ int stepSize() const;
+ void setStepSize(int step);
+
+ bool isEditable() const;
+ void setEditable(bool editable);
+
+ QValidator *validator() const;
+ void setValidator(QValidator *validator);
+
+ QJSValue textFromValue() const;
+ void setTextFromValue(const QJSValue &callback);
+
+ QJSValue valueFromText() const;
+ void setValueFromText(const QJSValue &callback);
+
+ QQuickIndicatorButton *up() const;
+ QQuickIndicatorButton *down() const;
+
+ // 2.2 (Qt 5.9)
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+
+ bool isInputMethodComposing() const;
+
+ // 2.3 (Qt 5.10)
+ bool wrap() const;
+ void setWrap(bool wrap);
+
+ // 2.4 (Qt 5.11)
+ QString displayText() const;
+
+public Q_SLOTS:
+ void increase();
+ void decrease();
+
+Q_SIGNALS:
+ void fromChanged();
+ void toChanged();
+ void valueChanged();
+ void stepSizeChanged();
+ void editableChanged();
+ void validatorChanged();
+ void textFromValueChanged();
+ void valueFromTextChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void valueModified();
+ Q_REVISION(2, 2) void inputMethodHintsChanged();
+ Q_REVISION(2, 2) void inputMethodComposingChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void wrapChanged();
+ // 2.4 (Qt 5.11)
+ Q_REVISION(2, 4) void displayTextChanged();
+
+protected:
+ void focusInEvent(QFocusEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void keyReleaseEvent(QKeyEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ void classBegin() override;
+ void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void localeChange(const QLocale &newLocale, const QLocale &oldLocale) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickSpinBox)
+ Q_DECLARE_PRIVATE(QQuickSpinBox)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSpinBox)
+
+#endif // QQUICKSPINBOX_P_H
diff --git a/src/quicktemplates2/qquicksplitview.cpp b/src/quicktemplates2/qquicksplitview.cpp
new file mode 100644
index 0000000000..24e42d8258
--- /dev/null
+++ b/src/quicktemplates2/qquicksplitview.cpp
@@ -0,0 +1,2141 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicksplitview_p.h"
+#include "qquicksplitview_p_p.h"
+#include "qquickcontentitem_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/qcborarray.h>
+#include <QtCore/qcbormap.h>
+#include <QtCore/qcborvalue.h>
+#include <QtQml/QQmlInfo>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SplitView
+ \inherits Container
+//! \instantiates QQuickSplitView
+ \inqmlmodule QtQuick.Controls
+ \since 5.13
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Lays out items with a draggable splitter between each item.
+
+ SplitView is a control that lays out items horizontally or vertically with
+ a draggable splitter between each item.
+
+ SplitView supports the following attached properties on items it manages:
+
+ \list
+ \li \l{minimumWidth}{SplitView.minimumWidth}
+ \li \l{minimumHeight}{SplitView.minimumHeight}
+ \li \l{preferredWidth}{SplitView.preferredWidth}
+ \li \l{preferredHeight}{SplitView.preferredHeight}
+ \li \l{maximumWidth}{SplitView.maximumWidth}
+ \li \l{maximumHeight}{SplitView.maximumHeight}
+ \li \l{fillWidth}{SplitView.fillWidth} (true for only one child)
+ \li \l{fillHeight}{SplitView.fillHeight} (true for only one child)
+ \endlist
+
+ In addition, each handle has the following read-only attached properties:
+
+ \list
+ \li \l{SplitHandle::hovered}{SplitHandle.hovered}
+ \li \l{SplitHandle::pressed}{SplitHandle.pressed}
+ \endlist
+
+ \note Handles should be purely visual and not handle events, as it can
+ interfere with their hovered and pressed states.
+
+ The preferred size of items in a SplitView can be specified via
+ \l{Item::}{implicitWidth} and \l{Item::}{implicitHeight} or
+ \c SplitView.preferredWidth and \c SplitView.preferredHeight:
+
+ \code
+ SplitView {
+ anchors.fill: parent
+
+ Item {
+ SplitView.preferredWidth: 50
+ }
+
+ // ...
+ }
+ \endcode
+
+ For a horizontal SplitView, it's not necessary to specify the preferred
+ height of each item, as they will be resized to the height of the view.
+ This applies in reverse for vertical views.
+
+ When a split handle is dragged, the \c SplitView.preferredWidth or
+ \c SplitView.preferredHeight property is overwritten, depending on the
+ \l orientation of the view.
+
+ To limit the size of items in a horizontal view, use the following
+ properties:
+
+ \code
+ SplitView {
+ anchors.fill: parent
+
+ Item {
+ SplitView.minimumWidth: 25
+ SplitView.preferredWidth: 50
+ SplitView.maximumWidth: 100
+ }
+
+ // ...
+ }
+ \endcode
+
+ To limit the size of items in a vertical view, use the following
+ properties:
+
+ \code
+ SplitView {
+ anchors.fill: parent
+ orientation: Qt.Vertical
+
+ Item {
+ SplitView.minimumHeight: 25
+ SplitView.preferredHeight: 50
+ SplitView.maximumHeight: 100
+ }
+
+ // ...
+ }
+ \endcode
+
+ There will always be one item (the fill item) in the SplitView that has
+ \c SplitView.fillWidth set to \c true (or \c SplitView.fillHeight, if
+ \l orientation is \c Qt.Vertical). This means that the item will get all
+ leftover space when other items have been laid out. By default, the last
+ visible child of the SplitView will have this set, but it can be changed by
+ explicitly setting \c fillWidth to \c true on another item.
+
+ A handle can belong to the item either on the left or top side, or on the
+ right or bottom side:
+
+ \list
+ \li If the fill item is to the right: the handle belongs to the left
+ item.
+ \li If the fill item is on the left: the handle belongs to the right
+ item.
+ \endlist
+
+ To create a SplitView with three items, and let the center item get
+ superfluous space, one could do the following:
+
+ \code
+ SplitView {
+ anchors.fill: parent
+ orientation: Qt.Horizontal
+
+ Rectangle {
+ implicitWidth: 200
+ SplitView.maximumWidth: 400
+ color: "lightblue"
+ Label {
+ text: "View 1"
+ anchors.centerIn: parent
+ }
+ }
+ Rectangle {
+ id: centerItem
+ SplitView.minimumWidth: 50
+ SplitView.fillWidth: true
+ color: "lightgray"
+ Label {
+ text: "View 2"
+ anchors.centerIn: parent
+ }
+ }
+ Rectangle {
+ implicitWidth: 200
+ color: "lightgreen"
+ Label {
+ text: "View 3"
+ anchors.centerIn: parent
+ }
+ }
+ }
+ \endcode
+
+ \section1 Serializing SplitView's State
+
+ The main purpose of SplitView is to allow users to easily configure the
+ size of various UI elements. In addition, the user's preferred sizes should
+ be remembered across sessions. To achieve this, the values of the \c
+ SplitView.preferredWidth and \c SplitView.preferredHeight properties can be
+ serialized using the \l saveState() and \l restoreState() functions:
+
+ \qml
+ import QtQuick.Controls
+ import Qt.labs.settings
+
+ ApplicationWindow {
+ // ...
+
+ Component.onCompleted: splitView.restoreState(settings.splitView)
+ Component.onDestruction: settings.splitView = splitView.saveState()
+
+ Settings {
+ id: settings
+ property var splitView
+ }
+
+ SplitView {
+ id: splitView
+ // ...
+ }
+ }
+ \endqml
+
+ Alternatively, the \l {Settings::}{value()} and \l {Settings::}{setValue()}
+ functions of \l Settings can be used:
+
+ \qml
+ import QtQuick.Controls
+ import Qt.labs.settings
+
+ ApplicationWindow {
+ // ...
+
+ Component.onCompleted: splitView.restoreState(settings.value("ui/splitview"))
+ Component.onDestruction: settings.setValue("ui/splitview", splitView.saveState())
+
+ Settings {
+ id: settings
+ }
+
+ SplitView {
+ id: splitView
+ // ...
+ }
+ }
+ \endqml
+
+ \sa SplitHandle, {Customizing SplitView}, {Container Controls}
+*/
+
+Q_LOGGING_CATEGORY(qlcQQuickSplitView, "qt.quick.controls.splitview")
+Q_LOGGING_CATEGORY(qlcQQuickSplitViewPointer, "qt.quick.controls.splitview.pointer")
+Q_LOGGING_CATEGORY(qlcQQuickSplitViewState, "qt.quick.controls.splitview.state")
+
+void QQuickSplitViewPrivate::updateFillIndex()
+{
+ const int count = contentModel->count();
+ const bool horizontal = isHorizontal();
+
+ qCDebug(qlcQQuickSplitView) << "looking for fillWidth/Height item amongst" << count << "items";
+
+ m_fillIndex = -1;
+ int i = 0;
+ int lastVisibleIndex = -1;
+ for (; i < count; ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(i));
+ if (!item->isVisible())
+ continue;
+
+ lastVisibleIndex = i;
+
+ const QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ if (!attached)
+ continue;
+
+ if ((horizontal && attached->fillWidth()) || (!horizontal && attached->fillHeight())) {
+ m_fillIndex = i;
+ qCDebug(qlcQQuickSplitView) << "found fillWidth/Height item at index" << m_fillIndex;
+ break;
+ }
+ }
+
+ if (m_fillIndex == -1) {
+ // If there was no item with fillWidth/fillHeight set, m_fillIndex will be -1,
+ // and we'll set it to the last visible item.
+ // If there was an item with fillWidth/fillHeight set, we were already done and this will be skipped.
+ m_fillIndex = lastVisibleIndex != -1 ? lastVisibleIndex : count - 1;
+ qCDebug(qlcQQuickSplitView) << "found no fillWidth/Height item; using last item at index" << m_fillIndex;
+ }
+}
+
+/*
+ Resizes split items according to their preferred size and any constraints.
+
+ If a split item is being resized due to a split handle being dragged,
+ it will be resized accordingly.
+
+ Items that aren't visible are skipped.
+*/
+void QQuickSplitViewPrivate::layoutResizeSplitItems(qreal &usedWidth, qreal &usedHeight, int &indexBeingResizedDueToDrag)
+{
+ const int count = contentModel->count();
+ const bool horizontal = isHorizontal();
+ for (int index = 0; index < count; ++index) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(index));
+ if (!item->isVisible()) {
+ // The item is not visible, so skip it.
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": split item " << item
+ << " at index " << index << " is not visible; skipping it and its handles (if any)";
+ continue;
+ }
+
+ const QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ const auto sizeData = effectiveSizeData(itemPrivate, attached);
+
+ const bool resizeLeftItem = m_fillIndex > m_pressedHandleIndex;
+ // True if any handle is pressed.
+ const bool isAHandlePressed = m_pressedHandleIndex != -1;
+ // True if this particular item is being resized as a result of a handle being dragged.
+ const bool isBeingResized = isAHandlePressed && ((resizeLeftItem && index == m_pressedHandleIndex)
+ || (!resizeLeftItem && index == m_nextVisibleIndexAfterPressedHandle));
+ if (isBeingResized) {
+ indexBeingResizedDueToDrag = index;
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": dragging handle for item";
+ }
+
+ const qreal size = horizontal ? width : height;
+ qreal requestedSize = 0;
+ if (isBeingResized) {
+ // Don't let the mouse go past either edge of the SplitView.
+ const qreal clampedMousePos = horizontal
+ ? qBound(qreal(0.0), m_mousePos.x(), qreal(width))
+ : qBound(qreal(0.0), m_mousePos.y(), qreal(height));
+
+ // We also need to ensure that the item's edge doesn't go too far
+ // out and hence give the item more space than is available.
+ const int firstIndex = resizeLeftItem ? m_nextVisibleIndexAfterPressedHandle : 0;
+ const int lastIndex = resizeLeftItem ? contentModel->count() - 1 : m_pressedHandleIndex;
+ const qreal accumulated = accumulatedSize(firstIndex, lastIndex);
+
+ const qreal mousePosRelativeToLeftHandleEdge = horizontal
+ ? m_pressPos.x() - m_handlePosBeforePress.x()
+ : m_pressPos.y() - m_handlePosBeforePress.y();
+
+ const QQuickItem *pressedHandleItem = m_handleItems.at(m_pressedHandleIndex);
+ const qreal pressedHandleSize = horizontal ? pressedHandleItem->width() : pressedHandleItem->height();
+
+ if (resizeLeftItem) {
+ // 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();
+ }
+
+ // The mouse can be clicked anywhere in the handle, and if we don't account for
+ // its position within the handle, the handle will jump when dragged.
+ const qreal pressedHandlePos = clampedMousePos - mousePosRelativeToLeftHandleEdge;
+
+ const qreal rightStop = size - accumulated - pressedHandleSize;
+ qreal leftStop = qMax(leftEdge, pressedHandlePos);
+ // qBound() doesn't care if min is greater than max, but we do.
+ if (leftStop > rightStop)
+ leftStop = rightStop;
+ const qreal newHandlePos = qBound(leftStop, pressedHandlePos, rightStop);
+ const qreal newItemSize = newHandlePos - leftEdge;
+
+ // Modify the preferredWidth, otherwise the original implicitWidth/preferredWidth
+ // will be used on the next layout (when it's no longer being resized).
+ if (!attached) {
+ // Force the attached object to be created since we rely on it.
+ attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, true));
+ }
+
+ /*
+ Users could conceivably respond to size changes in items by setting attached
+ SplitView properties:
+
+ onWidthChanged: if (width < 10) secondItem.SplitView.preferredWidth = 100
+
+ We handle this by doing another layout after the current layout if the
+ attached/implicit size properties are set during this layout. However, we also
+ need to set preferredWidth/Height here (for reasons mentioned in the comment above),
+ but we don't want this to count as a request for a delayed layout, so we guard against it.
+ */
+ m_ignoreNextLayoutRequest = true;
+
+ if (horizontal)
+ attached->setPreferredWidth(newItemSize);
+ else
+ attached->setPreferredHeight(newItemSize);
+
+ // We still need to use requestedWidth in the setWidth() call below,
+ // because sizeData has already been calculated and now contains an old
+ // effectivePreferredWidth value.
+ requestedSize = newItemSize;
+
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": resized (dragged) " << item
+ << " (clampedMousePos=" << clampedMousePos
+ << " pressedHandlePos=" << pressedHandlePos
+ << " accumulated=" << accumulated
+ << " leftEdge=" << leftEdge
+ << " leftStop=" << leftStop
+ << " rightStop=" << rightStop
+ << " newHandlePos=" << newHandlePos
+ << " newItemSize=" << newItemSize << ")";
+ } else { // Resizing the item on the right.
+ // The handle shouldn't cross other handles, so use the left edge of
+ // the first handle to the right as the right edge.
+ qreal rightEdge = size;
+ if (m_nextVisibleIndexAfterPressedHandle < m_handleItems.size()) {
+ const QQuickItem *rightHandle = m_handleItems.at(m_nextVisibleIndexAfterPressedHandle);
+ rightEdge = horizontal ? rightHandle->x() : rightHandle->y();
+ }
+
+ // The mouse can be clicked anywhere in the handle, and if we don't account for
+ // its position within the handle, the handle will jump when dragged.
+ const qreal pressedHandlePos = clampedMousePos - mousePosRelativeToLeftHandleEdge;
+
+ const qreal leftStop = accumulated - pressedHandleSize;
+ qreal rightStop = qMin(rightEdge - pressedHandleSize, pressedHandlePos);
+ // qBound() doesn't care if min is greater than max, but we do.
+ if (rightStop < leftStop)
+ rightStop = leftStop;
+ const qreal newHandlePos = qBound(leftStop, pressedHandlePos, rightStop);
+ const qreal newItemSize = rightEdge - (newHandlePos + pressedHandleSize);
+
+ // Modify the preferredWidth, otherwise the original implicitWidth/preferredWidth
+ // will be used on the next layout (when it's no longer being resized).
+ if (!attached) {
+ // Force the attached object to be created since we rely on it.
+ attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, true));
+ }
+
+ m_ignoreNextLayoutRequest = true;
+
+ if (horizontal)
+ attached->setPreferredWidth(newItemSize);
+ else
+ attached->setPreferredHeight(newItemSize);
+
+ // We still need to use requestedSize in the setWidth()/setHeight() call below,
+ // because sizeData has already been calculated and now contains an old
+ // effectivePreferredWidth/Height value.
+ requestedSize = newItemSize;
+
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": resized (dragged) " << item
+ << " (clampedMousePos=" << clampedMousePos
+ << " pressedHandlePos=" << pressedHandlePos
+ << " accumulated=" << accumulated
+ << " leftEdge=" << rightEdge
+ << " leftStop=" << leftStop
+ << " rightStop=" << rightStop
+ << " newHandlePos=" << newHandlePos
+ << " newItemSize=" << newItemSize << ")";
+ }
+ } else if (index != m_fillIndex) {
+ // No handle is being dragged and we're not the fill item,
+ // so set our preferred size as we normally would.
+ requestedSize = horizontal
+ ? sizeData.effectivePreferredWidth : sizeData.effectivePreferredHeight;
+ }
+
+ if (index != m_fillIndex) {
+ if (horizontal) {
+ item->setWidth(qBound(
+ sizeData.effectiveMinimumWidth,
+ requestedSize,
+ sizeData.effectiveMaximumWidth));
+ item->setHeight(height);
+ } else {
+ item->setWidth(width);
+ item->setHeight(qBound(
+ sizeData.effectiveMinimumHeight,
+ requestedSize,
+ sizeData.effectiveMaximumHeight));
+ }
+
+ 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 << ")";
+
+ // Keep track of how much space has been used so far.
+ if (horizontal)
+ usedWidth += item->width();
+ else
+ usedHeight += item->height();
+ } else if (indexBeingResizedDueToDrag != m_fillIndex) {
+ // The fill item is resized afterwards, outside of the loop.
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": skipping fill item as we resize it last";
+ }
+
+ // Also account for the size of the handle for this item (if any).
+ // We do this for the fill item too, which is why it's outside of the check above.
+ if (index < count - 1 && m_handle) {
+ QQuickItem *handleItem = m_handleItems.at(index);
+ // The handle for an item that's not visible will usually already be skipped
+ // with the item visibility check higher up, but if the view looks like this
+ // [ visible ] | [ visible (fill) ] | [ hidden ]
+ // ^
+ // hidden
+ // and we're iterating over the second item (which is visible but has no handle),
+ // we need to add an extra check for it to avoid it still taking up space.
+ if (handleItem->isVisible()) {
+ if (horizontal) {
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index
+ << ": handle takes up " << handleItem->width() << " width";
+ usedWidth += handleItem->width();
+ } else {
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index
+ << ": handle takes up " << handleItem->height() << " height";
+ usedHeight += handleItem->height();
+ }
+ } else {
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << index << ": handle is not visible; skipping it";
+ }
+ }
+ }
+}
+
+/*
+ Resizes the fill item by giving it the remaining space
+ after all other items have been resized.
+
+ Items that aren't visible are skipped.
+*/
+void QQuickSplitViewPrivate::layoutResizeFillItem(QQuickItem *fillItem,
+ qreal &usedWidth, qreal &usedHeight, int indexBeingResizedDueToDrag)
+{
+ // Only bother resizing if it it's visible. Also, if it's being resized due to a drag,
+ // then we've already set its size in layoutResizeSplitItems(), so no need to do it here.
+ if (!fillItem->isVisible() || indexBeingResizedDueToDrag == m_fillIndex) {
+ qCDebug(qlcQQuickSplitView).nospace() << m_fillIndex << ": - fill item " << fillItem
+ << " is not visible or was already resized due to a drag;"
+ << " skipping it and its handles (if any)";
+ return;
+ }
+
+ const QQuickItemPrivate *fillItemPrivate = QQuickItemPrivate::get(fillItem);
+ const QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(fillItem, false));
+ const auto fillSizeData = effectiveSizeData(fillItemPrivate, attached);
+ if (isHorizontal()) {
+ fillItem->setWidth(qBound(
+ fillSizeData.effectiveMinimumWidth,
+ width - usedWidth,
+ fillSizeData.effectiveMaximumWidth));
+ fillItem->setHeight(height);
+ } else {
+ fillItem->setWidth(width);
+ fillItem->setHeight(qBound(
+ fillSizeData.effectiveMinimumHeight,
+ height - usedHeight,
+ fillSizeData.effectiveMaximumHeight));
+ }
+
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << m_fillIndex
+ << ": resized split fill item " << fillItem << " (effective"
+ << " minW=" << fillSizeData.effectiveMinimumWidth
+ << ", minH=" << fillSizeData.effectiveMinimumHeight
+ << ", maxW=" << fillSizeData.effectiveMaximumWidth
+ << ", maxH=" << fillSizeData.effectiveMaximumHeight << ")";
+}
+
+/*
+ Positions items by laying them out in a row or column.
+
+ Items that aren't visible are skipped.
+*/
+void QQuickSplitViewPrivate::layoutPositionItems(const QQuickItem *fillItem)
+{
+ const bool horizontal = isHorizontal();
+ const int count = contentModel->count();
+ qreal usedWidth = 0;
+ qreal usedHeight = 0;
+
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(i));
+ if (!item->isVisible()) {
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << i << ": split item " << item
+ << " is not visible; skipping it and its handles (if any)";
+ continue;
+ }
+
+ // Position the item.
+ if (horizontal) {
+ item->setX(usedWidth);
+ item->setY(0);
+ } else {
+ item->setX(0);
+ item->setY(usedHeight);
+ }
+
+ // Keep track of how much space has been used so far.
+ if (horizontal)
+ usedWidth += item->width();
+ else
+ usedHeight += item->height();
+
+ if (Q_UNLIKELY(qlcQQuickSplitView().isDebugEnabled())) {
+ const QQuickItemPrivate *fillItemPrivate = QQuickItemPrivate::get(fillItem);
+ const QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(fillItem, false));
+ const auto sizeData = effectiveSizeData(fillItemPrivate, attached);
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << i << ": positioned "
+ << (i == m_fillIndex ? "fill item " : "item ") << item << " (effective"
+ << " minW=" << sizeData.effectiveMinimumWidth
+ << ", minH=" << sizeData.effectiveMinimumHeight
+ << ", prfW=" << sizeData.effectivePreferredWidth
+ << ", prfH=" << sizeData.effectivePreferredHeight
+ << ", maxW=" << sizeData.effectiveMaximumWidth
+ << ", maxH=" << sizeData.effectiveMaximumHeight << ")";
+ }
+
+ // Position the handle for this item (if any).
+ if (i < count - 1 && m_handle) {
+ // Position the handle.
+ QQuickItem *handleItem = m_handleItems.at(i);
+ handleItem->setX(horizontal ? usedWidth : 0);
+ handleItem->setY(horizontal ? 0 : usedHeight);
+
+ if (horizontal)
+ usedWidth += handleItem->width();
+ else
+ usedHeight += handleItem->height();
+
+ qCDebug(qlcQQuickSplitView).nospace() << " - " << i << ": positioned handle " << handleItem;
+ }
+ }
+}
+
+void QQuickSplitViewPrivate::requestLayout()
+{
+ Q_Q(QQuickSplitView);
+ q->polish();
+}
+
+void QQuickSplitViewPrivate::layout()
+{
+ if (!componentComplete)
+ return;
+
+ if (m_layingOut)
+ return;
+
+ const int count = contentModel->count();
+ if (count <= 0)
+ return;
+
+ Q_ASSERT_X(m_fillIndex < count, Q_FUNC_INFO, qPrintable(
+ QString::fromLatin1("m_fillIndex is %1 but our count is %2").arg(m_fillIndex).arg(count)));
+
+ Q_ASSERT_X(!m_handle || m_handleItems.size() == count - 1, Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "Expected %1 handle items, but there are %2").arg(count - 1).arg(m_handleItems.size())));
+
+ // We allow mouse events to instantly trigger layouts, whereas with e.g.
+ // attached properties being set, we require a delayed layout.
+ // To prevent recursive calls during mouse events, we need this guard.
+ QBoolBlocker guard(m_layingOut, true);
+
+ const bool horizontal = isHorizontal();
+ qCDebug(qlcQQuickSplitView) << "laying out" << count << "split items"
+ << (horizontal ? "horizontally" : "vertically") << "in SplitView" << q_func();
+
+ qreal usedWidth = 0;
+ qreal usedHeight = 0;
+ int indexBeingResizedDueToDrag = -1;
+
+ qCDebug(qlcQQuickSplitView) << " resizing:";
+
+ // First, resize the items. We need to do this first because otherwise fill
+ // items would take up all of the remaining space as soon as they are encountered.
+ layoutResizeSplitItems(usedWidth, usedHeight, indexBeingResizedDueToDrag);
+
+ qCDebug(qlcQQuickSplitView).nospace()
+ << " - (remaining width=" << width - usedWidth
+ << " remaining height=" << height - usedHeight << ")";
+
+ // Give the fill item the remaining space.
+ QQuickItem *fillItem = qobject_cast<QQuickItem*>(contentModel->object(m_fillIndex));
+ layoutResizeFillItem(fillItem, usedWidth, usedHeight, indexBeingResizedDueToDrag);
+
+ qCDebug(qlcQQuickSplitView) << " positioning:";
+
+ // Position the items.
+ layoutPositionItems(fillItem);
+
+ qCDebug(qlcQQuickSplitView).nospace() << "finished layouting";
+}
+
+void QQuickSplitViewPrivate::createHandles()
+{
+ Q_ASSERT(m_handle);
+ // A handle only makes sense if there are two items on either side.
+ if (contentModel->count() <= 1)
+ return;
+
+ // Create new handle items if there aren't enough.
+ const int count = contentModel->count() - 1;
+ qCDebug(qlcQQuickSplitView) << "creating" << count << "handles";
+ m_handleItems.reserve(count);
+ for (int i = 0; i < count; ++i)
+ createHandleItem(i);
+}
+
+void QQuickSplitViewPrivate::createHandleItem(int index)
+{
+ Q_Q(QQuickSplitView);
+ if (contentModel->count() <= 1)
+ return;
+
+ qCDebug(qlcQQuickSplitView) << "- creating handle for split item at index" << index
+ << "from handle component" << m_handle;
+
+ // If we don't use the correct context, it won't be possible to refer to
+ // the control's id from within the delegate.
+ QQmlContext *creationContext = m_handle->creationContext();
+ // The component might not have been created in QML, in which case
+ // the creation context will be null and we have to create it ourselves.
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext, q);
+ context->setContextObject(q);
+ QQuickItem *handleItem = qobject_cast<QQuickItem*>(m_handle->beginCreate(context));
+ if (handleItem) {
+ qCDebug(qlcQQuickSplitView) << "- successfully created handle item" << handleItem << "for split item at index" << index;
+
+ // Insert the item to our list of items *before* its parent is set to us,
+ // so that we can avoid it being added as a content item by checking
+ // if it is in the list in isContent().
+ m_handleItems.insert(index, handleItem);
+
+ handleItem->setParentItem(q);
+ // Handles must have priority for press events, so we need to set this.
+ handleItem->setAcceptedMouseButtons(Qt::LeftButton);
+ handleItem->setKeepMouseGrab(true);
+#if QT_CONFIG(cursor)
+ updateCursorHandle(handleItem);
+#endif
+ m_handle->completeCreate();
+ resizeHandle(handleItem);
+ }
+}
+
+void QQuickSplitViewPrivate::removeExcessHandles()
+{
+ int excess = m_handleItems.size() - qMax(0, contentModel->count() - 1);
+ qCDebug(qlcQQuickSplitView) << "removing" << excess << "excess handles from the end of our list";
+ for (; excess > 0; --excess) {
+ QQuickItem *handleItem = m_handleItems.takeLast();
+ delete handleItem;
+ }
+}
+
+qreal QQuickSplitViewPrivate::accumulatedSize(int firstIndex, int lastIndex) const
+{
+ qreal size = 0.0;
+ const bool horizontal = isHorizontal();
+ for (int i = firstIndex; i <= lastIndex; ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(i));
+ if (item->isVisible()) {
+ if (i != m_fillIndex) {
+ size += horizontal ? item->width() : item->height();
+ } else {
+ // If the fill item has a minimum size specified, we must respect it.
+ const QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ if (attached) {
+ const QQuickSplitViewAttachedPrivate *attachedPrivate
+ = QQuickSplitViewAttachedPrivate::get(attached);
+ if (horizontal && attachedPrivate->m_isMinimumWidthSet)
+ size += attachedPrivate->m_minimumWidth;
+ else if (!horizontal && attachedPrivate->m_isMinimumHeightSet)
+ size += attachedPrivate->m_minimumHeight;
+ }
+ }
+ }
+
+ // Only add the handle's width if there's actually a handle for this split item index.
+ if (i < lastIndex || lastIndex < contentModel->count() - 1) {
+ const QQuickItem *handleItem = m_handleItems.at(i);
+ if (handleItem->isVisible())
+ size += horizontal ? handleItem->width() : handleItem->height();
+ }
+ }
+ return size;
+}
+
+qreal effectiveMinimumWidth(const QQuickSplitViewAttachedPrivate *attachedPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isMinimumWidthSet ? attachedPrivate->m_minimumWidth : 0;
+}
+
+qreal effectiveMinimumHeight(const QQuickSplitViewAttachedPrivate *attachedPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isMinimumHeightSet ? attachedPrivate->m_minimumHeight : 0;
+}
+
+qreal effectivePreferredWidth(const QQuickSplitViewAttachedPrivate *attachedPrivate,
+ const QQuickItemPrivate *itemPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isPreferredWidthSet
+ ? attachedPrivate->m_preferredWidth : itemPrivate->implicitWidth;
+}
+
+qreal effectivePreferredHeight(const QQuickSplitViewAttachedPrivate *attachedPrivate,
+ const QQuickItemPrivate *itemPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isPreferredHeightSet
+ ? attachedPrivate->m_preferredHeight : itemPrivate->implicitHeight;
+}
+
+qreal effectiveMaximumWidth(const QQuickSplitViewAttachedPrivate *attachedPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isMaximumWidthSet
+ ? attachedPrivate->m_maximumWidth : std::numeric_limits<qreal>::infinity();
+}
+
+qreal effectiveMaximumHeight(const QQuickSplitViewAttachedPrivate *attachedPrivate)
+{
+ return attachedPrivate && attachedPrivate->m_isMaximumHeightSet
+ ? attachedPrivate->m_maximumHeight : std::numeric_limits<qreal>::infinity();
+}
+
+// We don't just take an index, because the item and attached properties object
+// will both be used outside of this function by calling code, so save some
+// time by not accessing them twice.
+QQuickSplitViewPrivate::EffectiveSizeData QQuickSplitViewPrivate::effectiveSizeData(
+ const QQuickItemPrivate *itemPrivate, const QQuickSplitViewAttached *attached) const
+{
+ EffectiveSizeData data;
+ const QQuickSplitViewAttachedPrivate *attachedPrivate = attached ? QQuickSplitViewAttachedPrivate::get(attached) : nullptr;
+ data.effectiveMinimumWidth = effectiveMinimumWidth(attachedPrivate);
+ data.effectiveMinimumHeight = effectiveMinimumHeight(attachedPrivate);
+ data.effectivePreferredWidth = effectivePreferredWidth(attachedPrivate, itemPrivate);
+ data.effectivePreferredHeight = effectivePreferredHeight(attachedPrivate, itemPrivate);
+ data.effectiveMaximumWidth = effectiveMaximumWidth(attachedPrivate);
+ data.effectiveMaximumHeight = effectiveMaximumHeight(attachedPrivate);
+ return data;
+}
+
+int QQuickSplitViewPrivate::handleIndexForSplitIndex(int splitIndex) const
+{
+ // If it's the first and only item in the view, it doesn't have a handle,
+ // so return -1: splitIndex (0) - 1.
+ // If it's the last item in the view, it doesn't have a handle, so use
+ // the handle for the previous item.
+ return splitIndex == contentModel->count() - 1 ? splitIndex - 1 : splitIndex;
+}
+
+void QQuickSplitViewPrivate::destroyHandles()
+{
+ qCDebug(qlcQQuickSplitView) << "destroying" << m_handleItems.size() << "handles";
+ qDeleteAll(m_handleItems);
+ m_handleItems.clear();
+}
+
+void QQuickSplitViewPrivate::resizeHandle(QQuickItem *handleItem)
+{
+ const bool horizontal = isHorizontal();
+ handleItem->setWidth(horizontal ? handleItem->implicitWidth() : width);
+ handleItem->setHeight(horizontal ? height : handleItem->implicitHeight());
+}
+
+void QQuickSplitViewPrivate::resizeHandles()
+{
+ for (QQuickItem *handleItem : m_handleItems)
+ resizeHandle(handleItem);
+}
+
+#if QT_CONFIG(cursor)
+void QQuickSplitViewPrivate::updateCursorHandle(QQuickItem *handleItem)
+{
+ handleItem->setCursor(isHorizontal() ? Qt::SplitHCursor : Qt::SplitVCursor);
+}
+#endif
+
+void QQuickSplitViewPrivate::updateHandleVisibilities()
+{
+ // If this is the first item that is visible, we won't have any
+ // handles yet, because we don't create a handle if we only have one item.
+ if (m_handleItems.isEmpty())
+ return;
+
+ // If the visibility/children change makes any item the last (right/bottom-most)
+ // visible item, we don't want to display a handle for it either:
+ // [ visible (fill) ] | [ hidden ] | [ hidden ]
+ // ^ ^
+ // hidden hidden
+ const int count = contentModel->count();
+ int lastVisibleItemIndex = -1;
+ for (int i = count - 1; i >= 0; --i) {
+ const QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(i));
+ if (item->isVisible()) {
+ lastVisibleItemIndex = i;
+ break;
+ }
+ }
+
+ for (int i = 0; i < count - 1; ++i) {
+ const QQuickItem *item = qobject_cast<QQuickItem*>(contentModel->object(i));
+ QQuickItem *handleItem = m_handleItems.at(i);
+ if (i != lastVisibleItemIndex)
+ handleItem->setVisible(item->isVisible());
+ else
+ handleItem->setVisible(false);
+ qCDebug(qlcQQuickSplitView) << "set visible property of handle" << handleItem << "at index"
+ << i << "to" << handleItem->isVisible();
+ }
+}
+
+void QQuickSplitViewPrivate::updateHoveredHandle(QQuickItem *hoveredItem)
+{
+ qCDebug(qlcQQuickSplitViewPointer) << "updating hovered handle after" << hoveredItem << "was hovered";
+
+ const int oldHoveredHandleIndex = m_hoveredHandleIndex;
+ m_hoveredHandleIndex = m_handleItems.indexOf(hoveredItem);
+ if (m_hoveredHandleIndex == oldHoveredHandleIndex)
+ return;
+
+ // First, clear the hovered flag of any previously-hovered handle.
+ if (oldHoveredHandleIndex != -1) {
+ QQuickItem *oldHoveredHandle = m_handleItems.at(oldHoveredHandleIndex);
+ QQuickSplitHandleAttached *oldHoveredHandleAttached = qobject_cast<QQuickSplitHandleAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(oldHoveredHandle, true));
+ QQuickSplitHandleAttachedPrivate::get(oldHoveredHandleAttached)->setHovered(false);
+ qCDebug(qlcQQuickSplitViewPointer) << "handle item at index" << oldHoveredHandleIndex << "is no longer hovered";
+ }
+
+ if (m_hoveredHandleIndex != -1) {
+ QQuickSplitHandleAttached *handleAttached = qobject_cast<QQuickSplitHandleAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(hoveredItem, true));
+ QQuickSplitHandleAttachedPrivate::get(handleAttached)->setHovered(true);
+ qCDebug(qlcQQuickSplitViewPointer) << "handle item at index" << m_hoveredHandleIndex << "is now hovered";
+ } else {
+ qCDebug(qlcQQuickSplitViewPointer) << "either there is no hovered item or" << hoveredItem << "is not a handle";
+ }
+}
+
+void QQuickSplitViewPrivate::setResizing(bool resizing)
+{
+ Q_Q(QQuickSplitView);
+ if (resizing == m_resizing)
+ return;
+
+ m_resizing = resizing;
+ emit q->resizingChanged();
+}
+
+bool QQuickSplitViewPrivate::isHorizontal() const
+{
+ return m_orientation == Qt::Horizontal;
+}
+
+QQuickItem *QQuickSplitViewPrivate::getContentItem()
+{
+ Q_Q(QQuickSplitView);
+ if (QQuickItem *item = QQuickContainerPrivate::getContentItem())
+ return item;
+
+ return new QQuickContentItem(q);
+}
+
+void QQuickSplitViewPrivate::handlePress(const QPointF &point)
+{
+ Q_Q(QQuickSplitView);
+ QQuickContainerPrivate::handlePress(point);
+
+ QQuickItem *pressedItem = q->childAt(point.x(), point.y());
+ const int pressedHandleIndex = m_handleItems.indexOf(pressedItem);
+ if (pressedHandleIndex != -1) {
+ m_pressedHandleIndex = pressedHandleIndex;
+ m_pressPos = point;
+ m_mousePos = point;
+
+ const QQuickItem *leftOrTopItem = qobject_cast<QQuickItem*>(contentModel->object(m_pressedHandleIndex));
+ // Find the first item to the right/bottom of this one that is visible.
+ QQuickItem *rightOrBottomItem = nullptr;
+ m_nextVisibleIndexAfterPressedHandle = -1;
+ for (int i = m_pressedHandleIndex + 1; i < contentModel->count(); ++i) {
+ auto nextItem = qobject_cast<QQuickItem*>(contentModel->object(i));
+ if (nextItem->isVisible()) {
+ rightOrBottomItem = nextItem;
+ m_nextVisibleIndexAfterPressedHandle = i;
+ break;
+ }
+ }
+ Q_ASSERT_X(rightOrBottomItem, Q_FUNC_INFO, qPrintable(QString::fromLatin1(
+ "Failed to find a visible item to the right/bottom of the one that was pressed at index %1; this shouldn't happen")
+ .arg(m_pressedHandleIndex)));
+
+ const bool isHorizontal = m_orientation == Qt::Horizontal;
+ m_leftOrTopItemSizeBeforePress = isHorizontal ? leftOrTopItem->width() : leftOrTopItem->height();
+ m_rightOrBottomItemSizeBeforePress = isHorizontal ? rightOrBottomItem->width() : rightOrBottomItem->height();
+ m_handlePosBeforePress = pressedItem->position();
+
+
+ // Force the attached object to be created since we rely on it.
+ QQuickSplitHandleAttached *handleAttached = qobject_cast<QQuickSplitHandleAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(pressedItem, true));
+ QQuickSplitHandleAttachedPrivate::get(handleAttached)->setPressed(true);
+
+ setResizing(true);
+
+ qCDebug(qlcQQuickSplitViewPointer).nospace() << "handled press -"
+ << " left/top index=" << m_pressedHandleIndex << ","
+ << " size before press=" << m_leftOrTopItemSizeBeforePress << ","
+ << " item=" << leftOrTopItem
+ << " right/bottom index=" << m_nextVisibleIndexAfterPressedHandle << ","
+ << " size before press=" << m_rightOrBottomItemSizeBeforePress
+ << " item=" << rightOrBottomItem;
+ }
+}
+
+void QQuickSplitViewPrivate::handleMove(const QPointF &point)
+{
+ QQuickContainerPrivate::handleMove(point);
+
+ if (m_pressedHandleIndex != -1) {
+ m_mousePos = point;
+ // Don't request layouts for input events because we want
+ // resizing to be as responsive and smooth as possible.
+ updatePolish();
+ }
+}
+
+void QQuickSplitViewPrivate::handleRelease(const QPointF &point)
+{
+ QQuickContainerPrivate::handleRelease(point);
+
+ if (m_pressedHandleIndex != -1) {
+ QQuickItem *pressedHandle = m_handleItems.at(m_pressedHandleIndex);
+ QQuickSplitHandleAttached *handleAttached = qobject_cast<QQuickSplitHandleAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(pressedHandle, true));
+ QQuickSplitHandleAttachedPrivate::get(handleAttached)->setPressed(false);
+ }
+
+ setResizing(false);
+
+ m_pressedHandleIndex = -1;
+ m_pressPos = QPointF();
+ m_mousePos = QPointF();
+ m_handlePosBeforePress = QPointF();
+ m_leftOrTopItemSizeBeforePress = 0.0;
+ m_rightOrBottomItemSizeBeforePress = 0.0;
+}
+
+void QQuickSplitViewPrivate::itemVisibilityChanged(QQuickItem *item)
+{
+ const int itemIndex = contentModel->indexOf(item, nullptr);
+ Q_ASSERT(itemIndex != -1);
+
+ qCDebug(qlcQQuickSplitView) << "visible property of split item"
+ << item << "at index" << itemIndex << "changed to" << item->isVisible();
+
+ // The visibility of an item just changed, so we need to update the visibility
+ // of the corresponding handle (if one exists).
+
+ const int handleIndex = handleIndexForSplitIndex(itemIndex);
+ if (handleIndex != -1) {
+ QQuickItem *handleItem = m_handleItems.at(handleIndex);
+ handleItem->setVisible(item->isVisible());
+
+ qCDebug(qlcQQuickSplitView) << "set visible property of handle item"
+ << handleItem << "at index" << handleIndex << "to" << item->isVisible();
+ }
+
+ updateHandleVisibilities();
+ updateFillIndex();
+ requestLayout();
+}
+
+void QQuickSplitViewPrivate::itemImplicitWidthChanged(QQuickItem *)
+{
+ requestLayout();
+}
+
+void QQuickSplitViewPrivate::itemImplicitHeightChanged(QQuickItem *)
+{
+ requestLayout();
+}
+
+void QQuickSplitViewPrivate::updatePolish()
+{
+ layout();
+}
+
+QQuickSplitViewPrivate *QQuickSplitViewPrivate::get(QQuickSplitView *splitView)
+{
+ return splitView->d_func();
+}
+
+QQuickSplitView::QQuickSplitView(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickSplitViewPrivate), parent)
+{
+ Q_D(QQuickSplitView);
+ d->changeTypes |= QQuickItemPrivate::Visibility;
+
+ setFiltersChildMouseEvents(true);
+}
+
+QQuickSplitView::QQuickSplitView(QQuickSplitViewPrivate &dd, QQuickItem *parent)
+ : QQuickContainer(dd, parent)
+{
+ Q_D(QQuickSplitView);
+ d->changeTypes |= QQuickItemPrivate::Visibility;
+
+ setFiltersChildMouseEvents(true);
+}
+
+QQuickSplitView::~QQuickSplitView()
+{
+ Q_D(QQuickSplitView);
+ for (int i = 0; i < d->contentModel->count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(d->contentModel->object(i));
+ d->removeImplicitSizeListener(item);
+ }
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::SplitView::orientation
+
+ This property holds the orientation of the SplitView.
+
+ The orientation determines how the split items are laid out:
+
+ Possible values:
+ \value Qt.Horizontal The items are laid out horizontally (default).
+ \value Qt.Vertical The items are laid out vertically.
+*/
+Qt::Orientation QQuickSplitView::orientation() const
+{
+ Q_D(const QQuickSplitView);
+ return d->m_orientation;
+}
+
+void QQuickSplitView::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickSplitView);
+ if (orientation == d->m_orientation)
+ return;
+
+ d->m_orientation = orientation;
+ d->resizeHandles();
+#if QT_CONFIG(cursor)
+ for (QQuickItem *handleItem : d->m_handleItems)
+ d->updateCursorHandle(handleItem);
+#endif
+ d->requestLayout();
+ emit orientationChanged();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::SplitView::resizing
+ \readonly
+
+ This property is \c true when the user is resizing
+ split items by dragging on the splitter handles.
+*/
+bool QQuickSplitView::isResizing() const
+{
+ Q_D(const QQuickSplitView);
+ return d->m_resizing;
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::SplitView::handle
+
+ This property holds the handle component.
+
+ An instance of this component will be instantiated \c {count - 1}
+ times, as long as \c count is greater than than \c {1}.
+
+ The following table explains how each handle will be resized
+ depending on the orientation of the split view:
+
+ \table
+ \header
+ \li Orientation
+ \li Handle Width
+ \li Handle Height
+ \row
+ \li \c Qt.Horizontal
+ \li \c implicitWidth
+ \li The \c height of the SplitView.
+ \row
+ \li \c Qt.Vertical
+ \li The \c width of the SplitView.
+ \li \c implicitHeight
+ \endtable
+
+ To change the size of the handle for mouse and touch events without
+ changing its visual size, use a \l {Item::}{containmentMask}:
+
+ \snippet qtquickcontrols2-splitview-handle-containmentmask.qml 1
+
+ \sa {Customizing SplitView}
+*/
+QQmlComponent *QQuickSplitView::handle()
+{
+ Q_D(const QQuickSplitView);
+ return d->m_handle;
+}
+
+void QQuickSplitView::setHandle(QQmlComponent *handle)
+{
+ Q_D(QQuickSplitView);
+ if (handle == d->m_handle)
+ return;
+
+ qCDebug(qlcQQuickSplitView) << "setting handle" << handle;
+
+ if (d->m_handle)
+ d->destroyHandles();
+
+ d->m_handle = handle;
+
+ if (d->m_handle) {
+ d->createHandles();
+ d->updateHandleVisibilities();
+ }
+
+ d->requestLayout();
+
+ emit handleChanged();
+}
+
+bool QQuickSplitView::isContent(QQuickItem *item) const
+{
+ Q_D(const QQuickSplitView);
+ if (!qmlContext(item))
+ return false;
+
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return false;
+
+ return !d->m_handleItems.contains(item);
+}
+
+QQuickSplitViewAttached *QQuickSplitView::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSplitViewAttached(object);
+}
+
+/*!
+ \qmlmethod var QtQuick.Controls::SplitView::saveState()
+
+ Saves the preferred sizes of split items into a byte array and returns it.
+
+ \sa {Serializing SplitView's State}, restoreState()
+*/
+QVariant QQuickSplitView::saveState()
+{
+ Q_D(QQuickSplitView);
+ qCDebug(qlcQQuickSplitViewState) << "saving state for split items in" << this;
+
+ // Save the preferred sizes of each split item.
+ QCborArray cborArray;
+ for (int i = 0; i < d->contentModel->count(); ++i) {
+ const QQuickItem *item = qobject_cast<QQuickItem*>(d->contentModel->object(i));
+ const QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ // Don't serialise stuff if we don't need to. If a split item was given a preferred
+ // size in QML or it was dragged, it will have an attached object and either
+ // m_isPreferredWidthSet or m_isPreferredHeightSet (or both) will be true,
+ // so items without these can be skipped. We write the index of each item
+ // that has data so that we know which item to set it on when restoring.
+ if (!attached)
+ continue;
+
+ const QQuickSplitViewAttachedPrivate *attachedPrivate = QQuickSplitViewAttachedPrivate::get(attached);
+ if (!attachedPrivate->m_isPreferredWidthSet && !attachedPrivate->m_isPreferredHeightSet)
+ continue;
+
+ QCborMap cborMap;
+ cborMap[QLatin1String("index")] = i;
+ if (attachedPrivate->m_isPreferredWidthSet) {
+ cborMap[QLatin1String("preferredWidth")] = static_cast<double>(attachedPrivate->m_preferredWidth);
+
+ qCDebug(qlcQQuickSplitViewState).nospace() << "- wrote preferredWidth of "
+ << attachedPrivate->m_preferredWidth << " for split item " << item << " at index " << i;
+ }
+ if (attachedPrivate->m_isPreferredHeightSet) {
+ cborMap[QLatin1String("preferredHeight")] = static_cast<double>(attachedPrivate->m_preferredHeight);
+
+ qCDebug(qlcQQuickSplitViewState).nospace() << "- wrote preferredHeight of "
+ << attachedPrivate->m_preferredHeight << " for split item " << item << " at index " << i;
+ }
+
+ cborArray.append(cborMap);
+ }
+
+ const QByteArray byteArray = cborArray.toCborValue().toCbor();
+ qCDebug(qlcQQuickSplitViewState) << "the resulting byte array is:" << byteArray;
+ return QVariant(byteArray);
+}
+
+/*!
+ \qmlmethod bool QtQuick.Controls::SplitView::restoreState(state)
+
+ Reads the preferred sizes from \a state and applies them to the split items.
+
+ Returns \c true if the state was successfully restored, otherwise \c false.
+
+ \sa {Serializing SplitView's State}, saveState()
+*/
+bool QQuickSplitView::restoreState(const QVariant &state)
+{
+ const QByteArray cborByteArray = state.toByteArray();
+ Q_D(QQuickSplitView);
+ if (cborByteArray.isEmpty())
+ return false;
+
+ QCborParserError parserError;
+ const QCborValue cborValue(QCborValue::fromCbor(cborByteArray, &parserError));
+ if (parserError.error != QCborError::NoError) {
+ qmlWarning(this) << "Error reading SplitView state:" << parserError.errorString();
+ return false;
+ }
+
+ qCDebug(qlcQQuickSplitViewState) << "restoring state for split items of" << this
+ << "from the following string:" << state;
+
+ const QCborArray cborArray(cborValue.toArray());
+ const int ourCount = d->contentModel->count();
+ // This could conceivably happen if items were removed from the SplitView since the state was last saved.
+ if (cborArray.size() > ourCount) {
+ qmlWarning(this) << "Error reading SplitView state: expected "
+ << ourCount << " or less split items but got " << cborArray.size();
+ return false;
+ }
+
+ for (auto it = cborArray.constBegin(); it != cborArray.constEnd(); ++it) {
+ QCborMap cborMap(it->toMap());
+ const int splitItemIndex = cborMap.value(QLatin1String("index")).toInteger();
+ const bool isPreferredWidthSet = cborMap.contains(QLatin1String("preferredWidth"));
+ const bool isPreferredHeightSet = cborMap.contains(QLatin1String("preferredHeight"));
+
+ QQuickItem *item = qobject_cast<QQuickItem*>(d->contentModel->object(splitItemIndex));
+ // If the split item does not have a preferred size specified in QML, it could still have
+ // been resized via dragging before it was saved. In this case, it won't have an
+ // attached object upon application startup, so we create it.
+ QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, true));
+ if (isPreferredWidthSet) {
+ const qreal preferredWidth = cborMap.value(QLatin1String("preferredWidth")).toDouble();
+ attached->setPreferredWidth(preferredWidth);
+ }
+ if (isPreferredHeightSet) {
+ const qreal preferredHeight = cborMap.value(QLatin1String("preferredHeight")).toDouble();
+ attached->setPreferredHeight(preferredHeight);
+ }
+
+ const QQuickSplitViewAttachedPrivate *attachedPrivate = QQuickSplitViewAttachedPrivate::get(attached);
+ qCDebug(qlcQQuickSplitViewState).nospace()
+ << "- restored the following state for split item " << item << " at index " << splitItemIndex
+ << ": preferredWidthSet=" << attachedPrivate->m_isPreferredWidthSet
+ << " preferredWidth=" << attachedPrivate->m_preferredWidth
+ << " preferredHeightSet=" << attachedPrivate->m_isPreferredHeightSet
+ << " preferredHeight=" << attachedPrivate->m_preferredHeight;
+ }
+
+ return true;
+}
+
+void QQuickSplitView::componentComplete()
+{
+ Q_D(QQuickSplitView);
+ QQuickControl::componentComplete();
+ d->resizeHandles();
+ d->updateFillIndex();
+ d->updatePolish();
+}
+
+void QQuickSplitView::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSplitView);
+ QQuickContainer::hoverMoveEvent(event);
+
+ QQuickItem *hoveredItem = childAt(event->position().toPoint().x(), event->position().toPoint().y());
+ d->updateHoveredHandle(hoveredItem);
+}
+
+void QQuickSplitView::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_UNUSED(event);
+ Q_D(QQuickSplitView);
+ // If SplitView is no longer hovered (e.g. visible set to false), clear handle hovered value
+ d->updateHoveredHandle(nullptr);
+}
+
+bool QQuickSplitView::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ Q_D(QQuickSplitView);
+ qCDebug(qlcQQuickSplitViewPointer) << "childMouseEventFilter called with" << item << event;
+
+ if (Q_LIKELY(event->isPointerEvent())) {
+ auto *pointerEvent = static_cast<QPointerEvent *>(event);
+ const auto &eventPoint = pointerEvent->points().first();
+ const QPointF point = mapFromItem(item, eventPoint.position());
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ d->handlePress(point);
+ // Keep the mouse grab if this item belongs to the handle,
+ // otherwise this event can be stolen e.g. Flickable if we're inside it.
+ if (d->m_pressedHandleIndex != -1)
+ item->setKeepMouseGrab(true);
+ break;
+ case QEvent::MouseButtonRelease:
+ d->handleRelease(point);
+ break;
+ case QEvent::MouseMove:
+ d->handleMove(point);
+ break;
+ case QEvent::TouchBegin:
+ if (pointerEvent->pointCount() == 1) {
+ d->handlePress(point);
+ // We filter the event on behalf of item, but we want the item
+ // to be the exclusive grabber so that we can continue to filter
+ // touch events for it.
+ if (d->m_pressedHandleIndex != -1) {
+ item->setKeepTouchGrab(true);
+ pointerEvent->setExclusiveGrabber(eventPoint, item);
+ }
+ }
+ break;
+ case QEvent::TouchEnd:
+ if (pointerEvent->pointCount() == 1)
+ d->handleRelease(point);
+ break;
+ case QEvent::TouchUpdate:
+ if (pointerEvent->pointCount() == 1)
+ d->handleMove(point);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // If this event belongs to the handle, filter it. (d->m_pressedHandleIndex != -1) means that
+ // we press or move the handle, so we don't need to propagate it further.
+ if (d->m_pressedHandleIndex != -1)
+ return true;
+
+ return QQuickContainer::childMouseEventFilter(item, event);
+}
+
+void QQuickSplitView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickSplitView);
+ QQuickControl::geometryChange(newGeometry, oldGeometry);
+ d->resizeHandles();
+ d->requestLayout();
+}
+
+void QQuickSplitView::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickSplitView);
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return;
+
+ const int count = d->contentModel->count();
+ qCDebug(qlcQQuickSplitView).nospace() << "split item " << item << " added at index " << index
+ << "; there are now " << count << " items";
+
+ QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ if (attached)
+ QQuickSplitViewAttachedPrivate::get(attached)->setView(this);
+
+ // Only need to add handles if we have more than one split item.
+ if (count > 1) {
+ // If the item was added at the end, it shouldn't get a handle;
+ // the handle always goes to the split item on the left.
+ d->createHandleItem(index < count - 1 ? index : index - 1);
+ }
+
+ d->addImplicitSizeListener(item);
+
+ d->updateHandleVisibilities();
+ d->updateFillIndex();
+ d->requestLayout();
+}
+
+void QQuickSplitView::itemMoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickSplitView);
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return;
+
+ qCDebug(qlcQQuickSplitView) << "split item" << item << "moved to index" << index;
+
+ d->updateHandleVisibilities();
+ d->updateFillIndex();
+ d->requestLayout();
+}
+
+void QQuickSplitView::itemRemoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickSplitView);
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return;
+
+ qCDebug(qlcQQuickSplitView).nospace() << "split item " << item << " removed from index " << index
+ << "; there are now " << d->contentModel->count() << " items";
+
+ // Clear hovered/pressed handle if there are any.
+ if (d->m_hoveredHandleIndex != -1 || d->m_pressedHandleIndex != -1) {
+ const int handleIndex = d->m_hoveredHandleIndex != -1 ? d->m_hoveredHandleIndex : d->m_pressedHandleIndex;
+ QQuickItem *itemHandle = d->m_handleItems.at(handleIndex);
+ QQuickSplitHandleAttached *handleAttached = qobject_cast<QQuickSplitHandleAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitHandleAttached>(itemHandle, false));
+ if (handleAttached) {
+ auto handleAttachedPrivate = QQuickSplitHandleAttachedPrivate::get(handleAttached);
+ handleAttachedPrivate->setHovered(false);
+ handleAttachedPrivate->setPressed(false);
+ }
+
+ d->m_hoveredHandleIndex = -1;
+ d->m_pressedHandleIndex = -1;
+ }
+
+ // Unset any attached properties since the item is no longer owned by us.
+ QQuickSplitViewAttached *attached = qobject_cast<QQuickSplitViewAttached*>(
+ qmlAttachedPropertiesObject<QQuickSplitView>(item, false));
+ if (attached)
+ QQuickSplitViewAttachedPrivate::get(attached)->setView(this);
+
+ d->removeImplicitSizeListener(item);
+
+ d->removeExcessHandles();
+ d->updateHandleVisibilities();
+ d->updateFillIndex();
+ d->requestLayout();
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickSplitView::accessibleRole() const
+{
+ return QAccessible::Pane;
+}
+#endif
+
+QQuickSplitViewAttached::QQuickSplitViewAttached(QObject *parent)
+ : QObject(*(new QQuickSplitViewAttachedPrivate), parent)
+{
+ Q_D(QQuickSplitViewAttached);
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (!item) {
+ qmlWarning(parent) << "SplitView: attached properties can only be used on Items";
+ return;
+ }
+
+ if (QQuickItemPrivate::get(item)->isTransparentForPositioner())
+ return;
+
+ d->m_splitItem = item;
+
+ // Child items get added to SplitView's contentItem, so we have to ensure
+ // that exists first before trying to set m_splitView.
+ // Apparently, in some cases it's normal for the parent item
+ // to not exist until shortly after this constructor has run.
+ if (!item->parentItem())
+ return;
+
+ // This will get hit when attached SplitView properties are imperatively set
+ // on an item that previously had none set, for example.
+ QQuickSplitView *splitView = qobject_cast<QQuickSplitView*>(item->parentItem()->parentItem());
+ if (!splitView) {
+ qmlWarning(parent) << "SplitView: attached properties must be accessed through a direct child of SplitView";
+ return;
+ }
+
+ d->setView(splitView);
+}
+
+/*!
+ \qmlattachedproperty SplitView QtQuick.Controls::SplitView::view
+
+ This attached property holds the split view of the item it is
+ attached to, or \c null if the item is not in a split view.
+*/
+QQuickSplitView *QQuickSplitViewAttached::view() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_splitView;
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::minimumWidth
+
+ This attached property controls the minimum width of the split item.
+ The \l preferredWidth is bound within the \l minimumWidth and
+ \l maximumWidth. A split item cannot be dragged to be smaller than
+ its \c minimumWidth.
+
+ The default value is \c 0. To reset this property to its default value,
+ set it to \c undefined.
+
+ \sa maximumWidth, preferredWidth, fillWidth, minimumHeight
+*/
+qreal QQuickSplitViewAttached::minimumWidth() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_minimumWidth;
+}
+
+void QQuickSplitViewAttached::setMinimumWidth(qreal width)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isMinimumWidthSet = true;
+ if (qFuzzyCompare(width, d->m_minimumWidth))
+ return;
+
+ d->m_minimumWidth = width;
+ d->requestLayoutView();
+ emit minimumWidthChanged();
+}
+
+void QQuickSplitViewAttached::resetMinimumWidth()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectiveMinimumWidth = effectiveMinimumWidth(d);
+
+ d->m_isMinimumWidthSet = false;
+ d->m_minimumWidth = -1;
+
+ const qreal newEffectiveMinimumWidth = effectiveMinimumWidth(d);
+ if (qFuzzyCompare(newEffectiveMinimumWidth, oldEffectiveMinimumWidth))
+ return;
+
+ d->requestLayoutView();
+ emit minimumWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::minimumHeight
+
+ This attached property controls the minimum height of the split item.
+ The \l preferredHeight is bound within the \l minimumHeight and
+ \l maximumHeight. A split item cannot be dragged to be smaller than
+ its \c minimumHeight.
+
+ The default value is \c 0. To reset this property to its default value,
+ set it to \c undefined.
+
+ \sa maximumHeight, preferredHeight, fillHeight, minimumWidth
+*/
+qreal QQuickSplitViewAttached::minimumHeight() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_minimumHeight;
+}
+
+void QQuickSplitViewAttached::setMinimumHeight(qreal height)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isMinimumHeightSet = true;
+ if (qFuzzyCompare(height, d->m_minimumHeight))
+ return;
+
+ d->m_minimumHeight = height;
+ d->requestLayoutView();
+ emit minimumHeightChanged();
+}
+
+void QQuickSplitViewAttached::resetMinimumHeight()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectiveMinimumHeight = effectiveMinimumHeight(d);
+
+ d->m_isMinimumHeightSet = false;
+ d->m_minimumHeight = -1;
+
+ const qreal newEffectiveMinimumHeight = effectiveMinimumHeight(d);
+ if (qFuzzyCompare(newEffectiveMinimumHeight, oldEffectiveMinimumHeight))
+ return;
+
+ d->requestLayoutView();
+ emit minimumHeightChanged();
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::preferredWidth
+
+ This attached property controls the preferred width of the split item. The
+ preferred width will be used as the size of the item, and will be bound
+ within the \l minimumWidth and \l maximumWidth. If the preferred width
+ is not set, the item's \l {Item::}{implicitWidth} will be used.
+
+ When a split item is resized, the preferredWidth will be set in order
+ to keep track of the new size.
+
+ By default, this property is not set, and therefore
+ \l {Item::}{implicitWidth} will be used instead. To reset this property to
+ its default value, set it to \c undefined.
+
+ \note Do not set the \l{Item::}{width} property of a split item, as it will be
+ overwritten upon each layout of the SplitView.
+
+ \sa minimumWidth, maximumWidth, fillWidth, preferredHeight
+*/
+qreal QQuickSplitViewAttached::preferredWidth() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_preferredWidth;
+}
+
+void QQuickSplitViewAttached::setPreferredWidth(qreal width)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isPreferredWidthSet = true;
+ // Make sure that we clear this flag now, before we emit the change signals
+ // which could cause another setter to be called.
+ auto splitViewPrivate = d->m_splitView ? QQuickSplitViewPrivate::get(d->m_splitView) : nullptr;
+ const bool ignoreNextLayoutRequest = splitViewPrivate && splitViewPrivate->m_ignoreNextLayoutRequest;
+ if (splitViewPrivate)
+ splitViewPrivate->m_ignoreNextLayoutRequest = false;
+
+ if (qFuzzyCompare(width, d->m_preferredWidth))
+ return;
+
+ d->m_preferredWidth = width;
+
+ if (!ignoreNextLayoutRequest) {
+ // We are currently in the middle of performing a layout, and the user (not our internal code)
+ // changed the preferred width of one of the split items, so request another layout.
+ d->requestLayoutView();
+ }
+
+ emit preferredWidthChanged();
+}
+
+void QQuickSplitViewAttached::resetPreferredWidth()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectivePreferredWidth = effectivePreferredWidth(
+ d, QQuickItemPrivate::get(d->m_splitItem));
+
+ d->m_isPreferredWidthSet = false;
+ d->m_preferredWidth = -1;
+
+ const qreal newEffectivePreferredWidth = effectivePreferredWidth(
+ d, QQuickItemPrivate::get(d->m_splitItem));
+ if (qFuzzyCompare(newEffectivePreferredWidth, oldEffectivePreferredWidth))
+ return;
+
+ d->requestLayoutView();
+ emit preferredWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::preferredHeight
+
+ This attached property controls the preferred height of the split item. The
+ preferred height will be used as the size of the item, and will be bound
+ within the \l minimumHeight and \l maximumHeight. If the preferred height
+ is not set, the item's \l{Item::}{implicitHeight} will be used.
+
+ When a split item is resized, the preferredHeight will be set in order
+ to keep track of the new size.
+
+ By default, this property is not set, and therefore
+ \l{Item::}{implicitHeight} will be used instead. To reset this property to
+ its default value, set it to \c undefined.
+
+ \note Do not set the \l{Item::}{height} property of a split item, as it will be
+ overwritten upon each layout of the SplitView.
+
+ \sa minimumHeight, maximumHeight, fillHeight, preferredWidth
+*/
+qreal QQuickSplitViewAttached::preferredHeight() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_preferredHeight;
+}
+
+void QQuickSplitViewAttached::setPreferredHeight(qreal height)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isPreferredHeightSet = true;
+ // Make sure that we clear this flag now, before we emit the change signals
+ // which could cause another setter to be called.
+ auto splitViewPrivate = d->m_splitView ? QQuickSplitViewPrivate::get(d->m_splitView) : nullptr;
+ const bool ignoreNextLayoutRequest = splitViewPrivate && splitViewPrivate->m_ignoreNextLayoutRequest;
+ if (splitViewPrivate)
+ splitViewPrivate->m_ignoreNextLayoutRequest = false;
+
+ if (qFuzzyCompare(height, d->m_preferredHeight))
+ return;
+
+ d->m_preferredHeight = height;
+
+ if (!ignoreNextLayoutRequest) {
+ // We are currently in the middle of performing a layout, and the user (not our internal code)
+ // changed the preferred height of one of the split items, so request another layout.
+ d->requestLayoutView();
+ }
+
+ emit preferredHeightChanged();
+}
+
+void QQuickSplitViewAttached::resetPreferredHeight()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectivePreferredHeight = effectivePreferredHeight(
+ d, QQuickItemPrivate::get(d->m_splitItem));
+
+ d->m_isPreferredHeightSet = false;
+ d->m_preferredHeight = -1;
+
+ const qreal newEffectivePreferredHeight = effectivePreferredHeight(
+ d, QQuickItemPrivate::get(d->m_splitItem));
+ if (qFuzzyCompare(newEffectivePreferredHeight, oldEffectivePreferredHeight))
+ return;
+
+ d->requestLayoutView();
+ emit preferredHeightChanged();
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::maximumWidth
+
+ This attached property controls the maximum width of the split item.
+ The \l preferredWidth is bound within the \l minimumWidth and
+ \l maximumWidth. A split item cannot be dragged to be larger than
+ its \c maximumWidth.
+
+ The default value is \c Infinity. To reset this property to its default
+ value, set it to \c undefined.
+
+ \sa minimumWidth, preferredWidth, fillWidth, maximumHeight
+*/
+qreal QQuickSplitViewAttached::maximumWidth() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_maximumWidth;
+}
+
+void QQuickSplitViewAttached::setMaximumWidth(qreal width)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isMaximumWidthSet = true;
+ if (qFuzzyCompare(width, d->m_maximumWidth))
+ return;
+
+ d->m_maximumWidth = width;
+ d->requestLayoutView();
+ emit maximumWidthChanged();
+}
+
+void QQuickSplitViewAttached::resetMaximumWidth()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectiveMaximumWidth = effectiveMaximumWidth(d);
+
+ d->m_isMaximumWidthSet = false;
+ d->m_maximumWidth = -1;
+
+ const qreal newEffectiveMaximumWidth = effectiveMaximumWidth(d);
+ if (qFuzzyCompare(newEffectiveMaximumWidth, oldEffectiveMaximumWidth))
+ return;
+
+ d->requestLayoutView();
+ emit maximumWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::SplitView::maximumHeight
+
+ This attached property controls the maximum height of the split item.
+ The \l preferredHeight is bound within the \l minimumHeight and
+ \l maximumHeight. A split item cannot be dragged to be larger than
+ its \c maximumHeight.
+
+ The default value is \c Infinity. To reset this property to its default
+ value, set it to \c undefined.
+
+ \sa minimumHeight, preferredHeight, fillHeight, maximumWidth
+*/
+qreal QQuickSplitViewAttached::maximumHeight() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_maximumHeight;
+}
+
+void QQuickSplitViewAttached::setMaximumHeight(qreal height)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isMaximumHeightSet = true;
+ if (qFuzzyCompare(height, d->m_maximumHeight))
+ return;
+
+ d->m_maximumHeight = height;
+ d->requestLayoutView();
+ emit maximumHeightChanged();
+}
+
+void QQuickSplitViewAttached::resetMaximumHeight()
+{
+ Q_D(QQuickSplitViewAttached);
+ const qreal oldEffectiveMaximumHeight = effectiveMaximumHeight(d);
+
+ d->m_isMaximumHeightSet = false;
+ d->m_maximumHeight = -1;
+
+ const qreal newEffectiveMaximumHeight = effectiveMaximumHeight(d);
+ if (qFuzzyCompare(newEffectiveMaximumHeight, oldEffectiveMaximumHeight))
+ return;
+
+ d->requestLayoutView();
+ emit maximumHeightChanged();
+}
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SplitView::fillWidth
+
+ This attached property controls whether the item takes the remaining space
+ in the split view after all other items have been laid out.
+
+ By default, the last visible child of the split view will have this set,
+ but it can be changed by explicitly setting \c fillWidth to \c true on
+ another item.
+
+ The width of a split item with \c fillWidth set to \c true is still
+ restricted within its \l minimumWidth and \l maximumWidth.
+
+ \sa minimumWidth, preferredWidth, maximumWidth, fillHeight
+*/
+bool QQuickSplitViewAttached::fillWidth() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_fillWidth;
+}
+
+void QQuickSplitViewAttached::setFillWidth(bool fill)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isFillWidthSet = true;
+ if (fill == d->m_fillWidth)
+ return;
+
+ d->m_fillWidth = fill;
+ if (d->m_splitView && d->m_splitView->orientation() == Qt::Horizontal)
+ QQuickSplitViewPrivate::get(d->m_splitView)->updateFillIndex();
+ d->requestLayoutView();
+ emit fillWidthChanged();
+}
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SplitView::fillHeight
+
+ This attached property controls whether the item takes the remaining space
+ in the split view after all other items have been laid out.
+
+ By default, the last visible child of the split view will have this set,
+ but it can be changed by explicitly setting \c fillHeight to \c true on
+ another item.
+
+ The height of a split item with \c fillHeight set to \c true is still
+ restricted within its \l minimumHeight and \l maximumHeight.
+
+ \sa minimumHeight, preferredHeight, maximumHeight, fillWidth
+*/
+bool QQuickSplitViewAttached::fillHeight() const
+{
+ Q_D(const QQuickSplitViewAttached);
+ return d->m_fillHeight;
+}
+
+void QQuickSplitViewAttached::setFillHeight(bool fill)
+{
+ Q_D(QQuickSplitViewAttached);
+ d->m_isFillHeightSet = true;
+ if (fill == d->m_fillHeight)
+ return;
+
+ d->m_fillHeight = fill;
+ if (d->m_splitView && d->m_splitView->orientation() == Qt::Vertical)
+ QQuickSplitViewPrivate::get(d->m_splitView)->updateFillIndex();
+ d->requestLayoutView();
+ emit fillHeightChanged();
+}
+
+QQuickSplitViewAttachedPrivate::QQuickSplitViewAttachedPrivate()
+ : m_fillWidth(false)
+ , m_fillHeight(false)
+ , m_isFillWidthSet(false)
+ , m_isFillHeightSet(false)
+ , m_isMinimumWidthSet(false)
+ , m_isMinimumHeightSet(false)
+ , m_isPreferredWidthSet(false)
+ , m_isPreferredHeightSet(false)
+ , m_isMaximumWidthSet(false)
+ , m_isMaximumHeightSet(false)
+ , m_minimumWidth(0)
+ , m_minimumHeight(0)
+ , m_preferredWidth(-1)
+ , m_preferredHeight(-1)
+ , m_maximumWidth(std::numeric_limits<qreal>::infinity())
+ , m_maximumHeight(std::numeric_limits<qreal>::infinity())
+{
+}
+
+void QQuickSplitViewAttachedPrivate::setView(QQuickSplitView *newView)
+{
+ Q_Q(QQuickSplitViewAttached);
+ if (newView == m_splitView)
+ return;
+
+ m_splitView = newView;
+ qCDebug(qlcQQuickSplitView) << "set SplitView" << newView << "on attached object" << this;
+ emit q->viewChanged();
+}
+
+void QQuickSplitViewAttachedPrivate::requestLayoutView()
+{
+ if (m_splitView)
+ QQuickSplitViewPrivate::get(m_splitView)->requestLayout();
+}
+
+QQuickSplitViewAttachedPrivate *QQuickSplitViewAttachedPrivate::get(QQuickSplitViewAttached *attached)
+{
+ return attached->d_func();
+}
+
+const QQuickSplitViewAttachedPrivate *QQuickSplitViewAttachedPrivate::get(const QQuickSplitViewAttached *attached)
+{
+ return attached->d_func();
+}
+
+QQuickSplitHandleAttachedPrivate::QQuickSplitHandleAttachedPrivate()
+ : m_hovered(false)
+ , m_pressed(false)
+{
+}
+
+void QQuickSplitHandleAttachedPrivate::setHovered(bool hovered)
+{
+ Q_Q(QQuickSplitHandleAttached);
+ if (hovered == m_hovered)
+ return;
+
+ m_hovered = hovered;
+ emit q->hoveredChanged();
+}
+
+void QQuickSplitHandleAttachedPrivate::setPressed(bool pressed)
+{
+ Q_Q(QQuickSplitHandleAttached);
+ if (pressed == m_pressed)
+ return;
+
+ m_pressed = pressed;
+ emit q->pressedChanged();
+}
+
+QQuickSplitHandleAttachedPrivate *QQuickSplitHandleAttachedPrivate::get(QQuickSplitHandleAttached *attached)
+{
+ return attached->d_func();
+}
+
+const QQuickSplitHandleAttachedPrivate *QQuickSplitHandleAttachedPrivate::get(const QQuickSplitHandleAttached *attached)
+{
+ return attached->d_func();
+}
+
+QQuickSplitHandleAttached::QQuickSplitHandleAttached(QObject *parent)
+ : QObject(*(new QQuickSplitHandleAttachedPrivate), parent)
+{
+}
+
+/*!
+ \qmltype SplitHandle
+ \inherits QtObject
+//! \instantiates QQuickSplitHandleAttached
+ \inqmlmodule QtQuick.Controls
+ \since 5.13
+ \brief Provides attached properties for SplitView handles.
+
+ SplitHandle provides attached properties for \l SplitView handles.
+
+ For split items themselves, use the attached \l SplitView properties.
+
+ \sa SplitView
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SplitHandle::hovered
+
+ This attached property holds whether the split handle is hovered.
+
+ \sa pressed
+*/
+bool QQuickSplitHandleAttached::isHovered() const
+{
+ Q_D(const QQuickSplitHandleAttached);
+ return d->m_hovered;
+}
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SplitHandle::pressed
+
+ This attached property holds whether the split handle is pressed.
+
+ \sa hovered
+*/
+bool QQuickSplitHandleAttached::isPressed() const
+{
+ Q_D(const QQuickSplitHandleAttached);
+ return d->m_pressed;
+}
+
+QQuickSplitHandleAttached *QQuickSplitHandleAttached::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSplitHandleAttached(object);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicksplitview_p.cpp"
diff --git a/src/quicktemplates2/qquicksplitview_p.h b/src/quicktemplates2/qquicksplitview_p.h
new file mode 100644
index 0000000000..5d8f8a3175
--- /dev/null
+++ b/src/quicktemplates2/qquicksplitview_p.h
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSPLITVIEW_P_H
+#define QQUICKSPLITVIEW_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtQml/qqmllist.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSplitViewPrivate;
+class QQuickSplitViewAttached;
+class QQuickSplitViewAttachedPrivate;
+class QQuickSplitHandleAttached;
+class QQuickSplitHandleAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSplitView : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(bool resizing READ isResizing NOTIFY resizingChanged)
+ Q_PROPERTY(QQmlComponent *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL)
+ QML_NAMED_ELEMENT(SplitView)
+ QML_ATTACHED(QQuickSplitViewAttached)
+ QML_ADDED_IN_VERSION(2, 13)
+
+public:
+ explicit QQuickSplitView(QQuickItem *parent = nullptr);
+ ~QQuickSplitView() override;
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ bool isResizing() const;
+
+ QQmlComponent *handle();
+ void setHandle(QQmlComponent *handle);
+
+ bool isContent(QQuickItem *item) const override;
+
+ static QQuickSplitViewAttached *qmlAttachedProperties(QObject *object);
+
+ // Based on the same code in QMainWindow.
+ enum VersionMarkers {
+ VersionMarker = 0xff
+ };
+ Q_INVOKABLE QVariant saveState();
+ Q_INVOKABLE bool restoreState(const QVariant &state);
+
+Q_SIGNALS:
+ void orientationChanged();
+ void resizingChanged();
+ void handleChanged();
+
+protected:
+ QQuickSplitView(QQuickSplitViewPrivate &dd, QQuickItem *parent);
+
+ void componentComplete() override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+ bool childMouseEventFilter(QQuickItem *item, QEvent *event) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemMoved(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickSplitView)
+ Q_DECLARE_PRIVATE(QQuickSplitView)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSplitViewAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickSplitView *view READ view NOTIFY viewChanged FINAL)
+ Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth
+ RESET resetMinimumWidth NOTIFY minimumWidthChanged FINAL)
+ Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight
+ RESET resetMinimumHeight NOTIFY minimumHeightChanged FINAL)
+ Q_PROPERTY(qreal preferredWidth READ preferredWidth WRITE setPreferredWidth
+ RESET resetPreferredWidth NOTIFY preferredWidthChanged FINAL)
+ Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight
+ RESET resetPreferredHeight NOTIFY preferredHeightChanged FINAL)
+ Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth
+ RESET resetMaximumWidth NOTIFY maximumWidthChanged FINAL)
+ Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight
+ RESET resetMaximumHeight 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)
+
+public:
+ explicit QQuickSplitViewAttached(QObject *parent = nullptr);
+
+ QQuickSplitView *view() const;
+
+ qreal minimumWidth() const;
+ void setMinimumWidth(qreal width);
+ void resetMinimumWidth();
+
+ qreal minimumHeight() const;
+ void setMinimumHeight(qreal height);
+ void resetMinimumHeight();
+
+ qreal preferredWidth() const;
+ void setPreferredWidth(qreal width);
+ void resetPreferredWidth();
+
+ qreal preferredHeight() const;
+ void setPreferredHeight(qreal height);
+ void resetPreferredHeight();
+
+ qreal maximumWidth() const;
+ void setMaximumWidth(qreal width);
+ void resetMaximumWidth();
+
+ qreal maximumHeight() const;
+ void setMaximumHeight(qreal height);
+ void resetMaximumHeight();
+
+ bool fillWidth() const;
+ void setFillWidth(bool fill);
+
+ bool fillHeight() const;
+ void setFillHeight(bool fill);
+
+Q_SIGNALS:
+ void viewChanged();
+ void minimumWidthChanged();
+ void minimumHeightChanged();
+ void preferredWidthChanged();
+ void preferredHeightChanged();
+ void maximumWidthChanged();
+ void maximumHeightChanged();
+ void fillWidthChanged();
+ void fillHeightChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSplitViewAttached)
+ Q_DECLARE_PRIVATE(QQuickSplitViewAttached)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSplitHandleAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL)
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+ QML_NAMED_ELEMENT(SplitHandle)
+ QML_ATTACHED(QQuickSplitHandleAttached)
+ QML_UNCREATABLE("")
+ QML_ADDED_IN_VERSION(2, 13)
+
+public:
+ explicit QQuickSplitHandleAttached(QObject *parent = nullptr);
+
+ bool isHovered() const;
+ bool isPressed() const;
+
+ static QQuickSplitHandleAttached *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void hoveredChanged();
+ void pressedChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSplitHandleAttached)
+ Q_DECLARE_PRIVATE(QQuickSplitHandleAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSplitView)
+QML_DECLARE_TYPEINFO(QQuickSplitView, QML_HAS_ATTACHED_PROPERTIES)
+
+QML_DECLARE_TYPE(QQuickSplitHandleAttached)
+QML_DECLARE_TYPEINFO(QQuickSplitHandleAttached, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKSPLITVIEW_P_H
diff --git a/src/quicktemplates2/qquicksplitview_p_p.h b/src/quicktemplates2/qquicksplitview_p_p.h
new file mode 100644
index 0000000000..fdf27f5002
--- /dev/null
+++ b/src/quicktemplates2/qquicksplitview_p_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSPLITVIEW_P_P_H
+#define QQUICKSPLITVIEW_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 <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSplitView;
+class QQuickSplitViewAttached;
+class QQuickSplitHandleAttached;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSplitViewPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSplitView)
+
+public:
+ void updateFillIndex();
+ void layoutResizeSplitItems(qreal &usedWidth, qreal &usedHeight, int &indexBeingResizedDueToDrag);
+ void layoutResizeFillItem(QQuickItem *fillItem, qreal &usedWidth, qreal &usedHeight, int indexBeingResizedDueToDrag);
+ void layoutPositionItems(const QQuickItem *fillItem);
+ void requestLayout();
+ void layout();
+ void createHandles();
+ void createHandleItem(int index);
+ void removeExcessHandles();
+ void destroyHandles();
+ void resizeHandle(QQuickItem *handleItem);
+ void resizeHandles();
+#if QT_CONFIG(cursor)
+ void updateCursorHandle(QQuickItem *handleItem);
+#endif
+ void updateHandleVisibilities();
+ void updateHoveredHandle(QQuickItem *hoveredItem);
+ void setResizing(bool resizing);
+
+ bool isHorizontal() const;
+ qreal accumulatedSize(int firstIndex, int lastIndex) const;
+
+ struct EffectiveSizeData {
+ qreal effectiveMinimumWidth;
+ qreal effectiveMinimumHeight;
+ qreal effectivePreferredWidth;
+ qreal effectivePreferredHeight;
+ qreal effectiveMaximumWidth;
+ qreal effectiveMaximumHeight;
+ };
+
+ EffectiveSizeData effectiveSizeData(const QQuickItemPrivate *itemPrivate,
+ const QQuickSplitViewAttached *attached) const;
+
+ int handleIndexForSplitIndex(int splitIndex) const;
+
+ QQuickItem *getContentItem() override;
+ void handlePress(const QPointF &point) override;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+
+ void itemVisibilityChanged(QQuickItem *item) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void updatePolish() override;
+
+ static QQuickSplitViewPrivate *get(QQuickSplitView *splitView);
+
+ Qt::Orientation m_orientation = Qt::Horizontal;
+ QQmlComponent *m_handle = nullptr;
+ QList<QQuickItem*> m_handleItems;
+ int m_hoveredHandleIndex = -1;
+ int m_pressedHandleIndex = -1;
+ int m_nextVisibleIndexAfterPressedHandle = -1;
+ QPointF m_pressPos;
+ QPointF m_mousePos;
+ QPointF m_handlePosBeforePress;
+ qreal m_leftOrTopItemSizeBeforePress = 0.0;
+ qreal m_rightOrBottomItemSizeBeforePress = 0.0;
+ int m_fillIndex = -1;
+ bool m_layingOut = false;
+ bool m_ignoreNextLayoutRequest = false;
+ bool m_resizing = false;
+};
+
+class QQuickSplitViewAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSplitViewAttached)
+
+public:
+ QQuickSplitViewAttachedPrivate();
+
+ void setView(QQuickSplitView *newView);
+ void requestLayoutView();
+
+ static QQuickSplitViewAttachedPrivate *get(QQuickSplitViewAttached *attached);
+ static const QQuickSplitViewAttachedPrivate *get(const QQuickSplitViewAttached *attached);
+
+ QQuickItem *m_splitItem = nullptr;
+ QQuickSplitView *m_splitView = nullptr;
+
+ unsigned m_fillWidth : 1;
+ unsigned m_fillHeight : 1;
+ unsigned m_isFillWidthSet : 1;
+ unsigned m_isFillHeightSet : 1;
+ unsigned m_isMinimumWidthSet : 1;
+ unsigned m_isMinimumHeightSet : 1;
+ unsigned m_isPreferredWidthSet : 1;
+ unsigned m_isPreferredHeightSet : 1;
+ unsigned m_isMaximumWidthSet : 1;
+ unsigned m_isMaximumHeightSet : 1;
+ qreal m_minimumWidth;
+ qreal m_minimumHeight;
+ qreal m_preferredWidth;
+ qreal m_preferredHeight;
+ qreal m_maximumWidth;
+ qreal m_maximumHeight;
+};
+
+class QQuickSplitHandleAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSplitHandleAttached)
+
+public:
+ QQuickSplitHandleAttachedPrivate();
+
+ void setHovered(bool hovered);
+ void setPressed(bool pressed);
+
+ static QQuickSplitHandleAttachedPrivate *get(QQuickSplitHandleAttached *attached);
+ static const QQuickSplitHandleAttachedPrivate *get(const QQuickSplitHandleAttached *attached);
+
+ unsigned m_hovered : 1;
+ unsigned m_pressed : 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSPLITVIEW_P_P_H
diff --git a/src/quicktemplates2/qquickstackelement.cpp b/src/quicktemplates2/qquickstackelement.cpp
new file mode 100644
index 0000000000..cf644a16fa
--- /dev/null
+++ b/src/quicktemplates2/qquickstackelement.cpp
@@ -0,0 +1,341 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstackelement_p_p.h"
+#include "qquickstackview_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlincubator.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQml/private/qqmlcomponent_p.h>
+#include <QtQml/private/qqmlengine_p.h>
+#include <QtQml/private/qqmlincubator_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static QQuickStackViewAttached *attachedStackObject(QQuickStackElement *element)
+{
+ QQuickStackViewAttached *attached = qobject_cast<QQuickStackViewAttached *>(qmlAttachedPropertiesObject<QQuickStackView>(element->item, false));
+ if (attached)
+ QQuickStackViewAttachedPrivate::get(attached)->element = element;
+ return attached;
+}
+
+class QQuickStackIncubator : public QQmlIncubator
+{
+public:
+ QQuickStackIncubator(QQuickStackElement *element)
+ : QQmlIncubator(Synchronous),
+ element(element)
+ {
+ }
+
+protected:
+ void setInitialState(QObject *object) override
+ {
+ auto privIncubator = QQmlIncubatorPrivate::get(this);
+ element->incubate(object, privIncubator->requiredProperties());
+ }
+
+private:
+ QQuickStackElement *element;
+};
+
+QQuickStackElement::QQuickStackElement()
+ : QQuickItemViewTransitionableItem(nullptr)
+{
+}
+
+QQuickStackElement::~QQuickStackElement()
+{
+ if (item)
+ QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+
+ if (ownComponent)
+ delete component;
+
+ QQuickStackViewAttached *attached = attachedStackObject(this);
+ if (item) {
+ if (ownItem) {
+ item->setParentItem(nullptr);
+ item->deleteLater();
+ item = nullptr;
+ } else {
+ setVisible(false);
+ if (!widthValid)
+ item->resetWidth();
+ if (!heightValid)
+ item->resetHeight();
+ if (item->parentItem() != originalParent) {
+ item->setParentItem(originalParent);
+ } else {
+ if (attached)
+ QQuickStackViewAttachedPrivate::get(attached)->itemParentChanged(item, nullptr);
+ }
+ }
+ }
+
+ if (attached)
+ emit attached->removed();
+
+ delete context;
+}
+
+QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view, QString *error)
+{
+ QUrl url(str);
+ if (!url.isValid()) {
+ *error = QStringLiteral("invalid url: ") + str;
+ return nullptr;
+ }
+
+ if (url.isRelative())
+ url = qmlContext(view)->resolvedUrl(url);
+
+ QQuickStackElement *element = new QQuickStackElement;
+ element->component = new QQmlComponent(qmlEngine(view), url, view);
+ element->ownComponent = true;
+ return element;
+}
+
+QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackView *view, QString *error)
+{
+ Q_UNUSED(view);
+ QQmlComponent *component = qobject_cast<QQmlComponent *>(object);
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!component && !item) {
+ *error = QQmlMetaType::prettyTypeName(object) + QStringLiteral(" is not supported. Must be Item or Component.");
+ return nullptr;
+ }
+
+ QQuickStackElement *element = new QQuickStackElement;
+ element->component = qobject_cast<QQmlComponent *>(object);
+ element->item = qobject_cast<QQuickItem *>(object);
+ if (element->item)
+ element->originalParent = element->item->parentItem();
+ return element;
+}
+
+bool QQuickStackElement::load(QQuickStackView *parent)
+{
+ setView(parent);
+ if (!item) {
+ ownItem = true;
+
+ if (component->isLoading()) {
+ QObject::connect(component, &QQmlComponent::statusChanged, [this](QQmlComponent::Status status) {
+ if (status == QQmlComponent::Ready)
+ load(view);
+ else if (status == QQmlComponent::Error)
+ QQuickStackViewPrivate::get(view)->warn(component->errorString().trimmed());
+ });
+ return true;
+ }
+
+ QQmlContext *creationContext = component->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(parent);
+ context = new QQmlContext(creationContext, parent);
+ context->setContextObject(parent);
+
+ QQuickStackIncubator incubator(this);
+ component->create(incubator, context);
+ if (component->isError())
+ QQuickStackViewPrivate::get(parent)->warn(component->errorString().trimmed());
+ } else {
+ RequiredProperties noRequiredProperties {};
+ initialize(noRequiredProperties);
+ }
+ return item;
+}
+
+void QQuickStackElement::incubate(QObject *object, RequiredProperties &requiredProperties)
+{
+ item = qmlobject_cast<QQuickItem *>(object);
+ if (item) {
+ QQmlEngine::setObjectOwnership(item, QQmlEngine::CppOwnership);
+ item->setParent(view);
+ initialize(requiredProperties);
+ }
+}
+
+void QQuickStackElement::initialize(RequiredProperties &requiredProperties)
+{
+ if (!item || init)
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!(widthValid = p->widthValid()))
+ item->setWidth(view->width());
+ if (!(heightValid = p->heightValid()))
+ item->setHeight(view->height());
+ item->setParentItem(view);
+
+ if (!properties.isUndefined()) {
+ QQmlEngine *engine = qmlEngine(view);
+ Q_ASSERT(engine);
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
+ Q_ASSERT(v4);
+ QV4::Scope scope(v4);
+ QV4::ScopedValue ipv(scope, properties.value());
+ QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());
+ QV4::ScopedValue qmlObject(scope, QV4::QObjectWrapper::wrap(v4, item));
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, qmlObject, ipv, requiredProperties, item);
+ properties.clear();
+ }
+
+ if (!requiredProperties.empty()) {
+ QString error;
+ for (const auto &property: requiredProperties) {
+ error += QLatin1String("Property %1 was marked as required but not set.\n")
+ .arg(property.propertyName);
+ }
+ QQuickStackViewPrivate::get(view)->warn(error);
+ item = nullptr;
+ } else {
+ p->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ }
+
+ init = true;
+}
+
+void QQuickStackElement::setIndex(int value)
+{
+ if (index == value)
+ return;
+
+ index = value;
+ QQuickStackViewAttached *attached = attachedStackObject(this);
+ if (attached)
+ emit attached->indexChanged();
+}
+
+void QQuickStackElement::setView(QQuickStackView *value)
+{
+ if (view == value)
+ return;
+
+ view = value;
+ QQuickStackViewAttached *attached = attachedStackObject(this);
+ if (attached)
+ emit attached->viewChanged();
+}
+
+void QQuickStackElement::setStatus(QQuickStackView::Status value)
+{
+ if (status == value)
+ return;
+
+ status = value;
+ QQuickStackViewAttached *attached = attachedStackObject(this);
+ if (!attached)
+ return;
+
+ switch (value) {
+ case QQuickStackView::Inactive:
+ emit attached->deactivated();
+ break;
+ case QQuickStackView::Deactivating:
+ emit attached->deactivating();
+ break;
+ case QQuickStackView::Activating:
+ emit attached->activating();
+ break;
+ case QQuickStackView::Active:
+ emit attached->activated();
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ emit attached->statusChanged();
+}
+
+void QQuickStackElement::setVisible(bool visible)
+{
+ QQuickStackViewAttached *attached = attachedStackObject(this);
+ if (!item || (attached && QQuickStackViewAttachedPrivate::get(attached)->explicitVisible))
+ return;
+
+ item->setVisible(visible);
+}
+
+void QQuickStackElement::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
+{
+ if (transitioner)
+ transitioner->transitionNextReposition(this, type, asTarget);
+}
+
+bool QQuickStackElement::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds)
+{
+ if (transitioner) {
+ if (item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
+ // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors
+ if (anchors && (anchors->fill() || anchors->centerIn()))
+ qmlWarning(item) << "StackView has detected conflicting anchors. Transitions may not execute properly.";
+ }
+
+ // TODO: add force argument to QQuickItemViewTransitionableItem::prepareTransition()?
+ nextTransitionToSet = true;
+ nextTransitionFromSet = true;
+ nextTransitionFrom += QPointF(1, 1);
+ return QQuickItemViewTransitionableItem::prepareTransition(transitioner, index, viewBounds);
+ }
+ return false;
+}
+
+void QQuickStackElement::startTransition(QQuickItemViewTransitioner *transitioner, QQuickStackView::Status status)
+{
+ setStatus(status);
+ if (transitioner)
+ QQuickItemViewTransitionableItem::startTransition(transitioner, index);
+}
+
+void QQuickStackElement::completeTransition(QQuickTransition *quickTransition)
+{
+ QQuickItemViewTransitionableItem::completeTransition(quickTransition);
+}
+
+void QQuickStackElement::itemDestroyed(QQuickItem *)
+{
+ item = nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickstackelement_p_p.h b/src/quicktemplates2/qquickstackelement_p_p.h
new file mode 100644
index 0000000000..1c7cd5632b
--- /dev/null
+++ b/src/quicktemplates2/qquickstackelement_p_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTACKELEMENT_P_P_H
+#define QQUICKSTACKELEMENT_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 <QtQuickTemplates2/private/qquickstackview_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQml/private/qv4persistent_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlContext;
+class QQmlComponent;
+struct QQuickStackTransition;
+class RequiredProperties;
+
+class QQuickStackElement : public QQuickItemViewTransitionableItem, public QQuickItemChangeListener
+{
+ QQuickStackElement();
+
+public:
+ ~QQuickStackElement();
+
+ static QQuickStackElement *fromString(const QString &str, QQuickStackView *view, QString *error);
+ static QQuickStackElement *fromObject(QObject *object, QQuickStackView *view, QString *error);
+
+ bool load(QQuickStackView *parent);
+ void incubate(QObject *object, RequiredProperties &requiredProperties);
+ void initialize(RequiredProperties &requiredProperties);
+
+ void setIndex(int index);
+ void setView(QQuickStackView *view);
+ void setStatus(QQuickStackView::Status status);
+ void setVisible(bool visible);
+
+ void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget);
+ bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds);
+ void startTransition(QQuickItemViewTransitioner *transitioner, QQuickStackView::Status status);
+ void completeTransition(QQuickTransition *quickTransition);
+
+ void itemDestroyed(QQuickItem *item) override;
+
+ int index = -1;
+ bool init = false;
+ bool removal = false;
+ bool ownItem = false;
+ bool ownComponent = false;
+ bool widthValid = false;
+ bool heightValid = false;
+ QQmlContext *context = nullptr;
+ QQmlComponent *component = nullptr;
+ QQuickStackView *view = nullptr;
+ QPointer<QQuickItem> originalParent;
+ QQuickStackView::Status status = QQuickStackView::Inactive;
+ QV4::PersistentValue properties;
+ QV4::PersistentValue qmlCallingContext;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTACKELEMENT_P_P_H
diff --git a/src/quicktemplates2/qquickstacktransition.cpp b/src/quicktemplates2/qquickstacktransition.cpp
new file mode 100644
index 0000000000..a0192d1be1
--- /dev/null
+++ b/src/quicktemplates2/qquickstacktransition.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstacktransition_p_p.h"
+#include "qquickstackelement_p_p.h"
+#include "qquickstackview_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static QQuickStackTransition exitTransition(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ QQuickStackTransition st;
+ st.status = QQuickStackView::Deactivating;
+ st.element = element;
+
+ const QQuickItemViewTransitioner *transitioner = QQuickStackViewPrivate::get(view)->transitioner;
+
+ switch (operation) {
+ case QQuickStackView::PushTransition:
+ st.type = QQuickItemViewTransitioner::AddTransition;
+ if (transitioner)
+ st.transition = transitioner->addDisplacedTransition;
+ break;
+ case QQuickStackView::ReplaceTransition:
+ st.type = QQuickItemViewTransitioner::MoveTransition;
+ if (transitioner)
+ st.transition = transitioner->moveDisplacedTransition;
+ break;
+ case QQuickStackView::PopTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::RemoveTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->removeTransition;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ return st;
+}
+
+static QQuickStackTransition enterTransition(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ QQuickStackTransition st;
+ st.status = QQuickStackView::Activating;
+ st.element = element;
+
+ const QQuickItemViewTransitioner *transitioner = QQuickStackViewPrivate::get(view)->transitioner;
+
+ switch (operation) {
+ case QQuickStackView::PushTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::AddTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->addTransition;
+ break;
+ case QQuickStackView::ReplaceTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::MoveTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->moveTransition;
+ break;
+ case QQuickStackView::PopTransition:
+ st.type = QQuickItemViewTransitioner::RemoveTransition;
+ if (transitioner)
+ st.transition = transitioner->removeDisplacedTransition;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ return st;
+}
+
+static QQuickStackView::Operation operationTransition(QQuickStackView::Operation operation, QQuickStackView::Operation transition)
+{
+ if (operation == QQuickStackView::Immediate || operation == QQuickStackView::Transition)
+ return transition;
+ return operation;
+}
+
+QQuickStackTransition QQuickStackTransition::popExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::PopTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::popEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::PopTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::pushExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::PushTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::pushEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::PushTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::replaceExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::ReplaceTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::replaceEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::ReplaceTransition), element, view);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickstacktransition_p_p.h b/src/quicktemplates2/qquickstacktransition_p_p.h
new file mode 100644
index 0000000000..3a08fb4a68
--- /dev/null
+++ b/src/quicktemplates2/qquickstacktransition_p_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTACKTRANSITION_P_P_H
+#define QQUICKSTACKTRANSITION_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 <QtQuickTemplates2/private/qquickstackview_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStackElement;
+
+struct QQuickStackTransition
+{
+ static QQuickStackTransition popExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition popEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ static QQuickStackTransition pushExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition pushEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ static QQuickStackTransition replaceExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition replaceEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ bool target = false;
+ QQuickStackView::Status status = QQuickStackView::Inactive;
+ QQuickItemViewTransitioner::TransitionType type = QQuickItemViewTransitioner::NoTransition;
+ QRectF viewBounds;
+ QQuickStackElement *element = nullptr;
+ QQuickTransition *transition = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTACKTRANSITION_P_P_H
diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp
new file mode 100644
index 0000000000..016b45a7bc
--- /dev/null
+++ b/src/quicktemplates2/qquickstackview.cpp
@@ -0,0 +1,1404 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstackview_p.h"
+#include "qquickstackview_p_p.h"
+#include "qquickstackelement_p_p.h"
+#include "qquickstacktransition_p_p.h"
+
+#include <QtCore/qscopedvaluerollback.h>
+#include <QtQml/qjsvalue.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlinfo.h>
+
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype StackView
+ \inherits Control
+//! \instantiates QQuickStackView
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-navigation
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Provides a stack-based navigation model.
+
+ \image qtquickcontrols2-stackview-wireframe.png
+
+ StackView can be used with a set of inter-linked information pages. For
+ example, an email application with separate views to list the latest emails,
+ view a specific email, and list/view the attachments. The email list view
+ is pushed onto the stack as users open an email, and popped out as they
+ choose to go back.
+
+ The following snippet demonstrates a simple use case, where the \c mainView
+ is pushed onto and popped out of the stack on relevant button click:
+
+ \qml
+ ApplicationWindow {
+ title: qsTr("Hello World")
+ width: 640
+ height: 480
+ visible: true
+
+ StackView {
+ id: stack
+ initialItem: mainView
+ anchors.fill: parent
+ }
+
+ Component {
+ id: mainView
+
+ Row {
+ spacing: 10
+
+ Button {
+ text: "Push"
+ onClicked: stack.push(mainView)
+ }
+ Button {
+ text: "Pop"
+ enabled: stack.depth > 1
+ onClicked: stack.pop()
+
+ }
+ Text {
+ text: stack.depth
+ }
+ }
+ }
+ }
+ \endqml
+
+ \section1 Using StackView in an Application
+
+ Using StackView in an application is as simple as adding it as a child to
+ a Window. The stack is usually anchored to the edges of the window, except
+ at the top or bottom where it might be anchored to a status bar, or some
+ other similar UI component. The stack can then be used by invoking its
+ navigation methods. The first item to show in the StackView is the one
+ that was assigned to \l initialItem, or the topmost item if \l initialItem
+ is not set.
+
+ \section1 Basic Navigation
+
+ StackView supports three primary navigation operations: push(), pop(), and
+ replace(). These correspond to classic stack operations where "push" adds
+ an item to the top of a stack, "pop" removes the top item from the
+ stack, and "replace" is like a pop followed by a push, which replaces the
+ topmost item with the new item. The topmost item in the stack
+ corresponds to the one that is \l{StackView::currentItem}{currently}
+ visible on screen. Logically, "push" navigates forward or deeper into the
+ application UI, "pop" navigates backward, and "replace" replaces the
+ \l currentItem.
+
+ \section2 Pushing Items
+
+ In the following animation, three \l Label controls are pushed onto a
+ stack view with the \l push() function:
+
+ \image qtquickcontrols2-stackview-push.gif
+
+ The stack now contains the following items: \c [A, B, C].
+
+ \note When the stack is empty, a push() operation will not have a
+ transition animation because there is nothing to transition from (typically
+ on application start-up).
+
+ \section2 Popping Items
+
+ Continuing on from the example above, the topmost item on the stack is
+ removed with a call to \l pop():
+
+ \image qtquickcontrols2-stackview-pop.gif
+
+ The stack now contains the following items: \c [A, B].
+
+ \note A pop() operation on a stack with depth 1 or 0 does nothing. In such
+ cases, the stack can be emptied using the \l clear() method.
+
+ \section3 Unwinding Items via Pop
+
+ Sometimes, it is necessary to go back more than a single step in the stack.
+ For example, to return to a "main" item or some kind of section item in the
+ application. In such cases, it is possible to specify an item as a
+ parameter for pop(). This is called an "unwind" operation, where the stack
+ unwinds till the specified item. If the item is not found, stack unwinds
+ until it is left with one item, which becomes the \l currentItem. To
+ explicitly unwind to the bottom of the stack, it is recommended to use
+ \l{pop()}{pop(null)}, although any non-existent item will do.
+
+ In the following animation, we unwind the stack to the first item by
+ calling \c pop(null):
+
+ \image qtquickcontrols2-stackview-unwind.gif
+
+ The stack now contains a single item: \c [A].
+
+ \section2 Replacing Items
+
+ In the following animation, we \l replace the topmost item with \c D:
+
+ \image qtquickcontrols2-stackview-replace.gif
+
+ The stack now contains the following items: \c [A, B, D].
+
+ \section1 Deep Linking
+
+ \e{Deep linking} means launching an application into a particular state. For
+ example, a newspaper application could be launched into showing a
+ particular article, bypassing the topmost item. In terms of StackView, deep linking means the ability to modify
+ the state of the stack, so much so that it is possible to push a set of
+ items to the top of the stack, or to completely reset the stack to a given
+ state.
+
+ The API for deep linking in StackView is the same as for basic navigation.
+ Pushing an array instead of a single item adds all the items in that array
+ to the stack. The transition animation, however, is applied only for the
+ last item in the array. The normal semantics of push() apply for deep
+ linking, that is, it adds whatever is pushed onto the stack.
+
+ \note Only the last item of the array is loaded. The rest of the items are
+ loaded only when needed, either on subsequent calls to pop or on request to
+ get an item using get().
+
+ This gives us the following result, given the stack [A, B, C]:
+
+ \list
+ \li \l{push()}{push([D, E, F])} => [A, B, C, D, E, F] - "push" transition
+ animation between C and F
+ \li \l{replace()}{replace([D, E, F])} => [A, B, D, E, F] - "replace"
+ transition animation between C and F
+ \li \l{clear()} followed by \l{push()}{push([D, E, F])} => [D, E, F] - no
+ transition animation for pushing items as the stack was empty.
+ \endlist
+
+ \section1 Finding Items
+
+ An Item for which the application does not have a reference can be found
+ by calling find(). The method needs a callback function, which is invoked
+ for each item in the stack (starting at the top) until a match is found.
+ If the callback returns \c true, find() stops and returns the matching
+ item, otherwise \c null is returned.
+
+ The code below searches the stack for an item named "order_id" and unwinds
+ to that item.
+
+ \badcode
+ stackView.pop(stackView.find(function(item) {
+ return item.name == "order_id";
+ }));
+ \endcode
+
+ You can also get to an item in the stack using \l {get()}{get(index)}.
+
+ \badcode
+ previousItem = stackView.get(myItem.StackView.index - 1));
+ \endcode
+
+ \section1 Transitions
+
+ For each push or pop operation, different transition animations are applied
+ to entering and exiting items. These animations define how the entering item
+ should animate in, and the exiting item should animate out. The animations
+ can be customized by assigning different \l{Transition}s for the
+ \l pushEnter, \l pushExit, \l popEnter, \l popExit, \l replaceEnter, and
+ \l replaceExit properties of StackView.
+
+ \note The transition animations affect each others' transitional behavior.
+ Customizing the animation for one and leaving the other may give unexpected
+ results.
+
+ The following snippet defines a simple fade transition for push and pop
+ operations:
+
+ \qml
+ StackView {
+ id: stackview
+ anchors.fill: parent
+
+ pushEnter: Transition {
+ PropertyAnimation {
+ property: "opacity"
+ from: 0
+ to:1
+ duration: 200
+ }
+ }
+ pushExit: Transition {
+ PropertyAnimation {
+ property: "opacity"
+ from: 1
+ to:0
+ duration: 200
+ }
+ }
+ popEnter: Transition {
+ PropertyAnimation {
+ property: "opacity"
+ from: 0
+ to:1
+ duration: 200
+ }
+ }
+ popExit: Transition {
+ PropertyAnimation {
+ property: "opacity"
+ from: 1
+ to:0
+ duration: 200
+ }
+ }
+ }
+ \endqml
+
+ \note Using anchors on the items added to a StackView is not supported.
+ Typically push, pop, and replace transitions animate the position,
+ which is not possible when anchors are applied. Notice that this
+ only applies to the root of the item. Using anchors for its children
+ works as expected.
+
+ \section1 Item Ownership
+
+ StackView only takes ownership of items that it creates itself. This means
+ that any item pushed onto a StackView will never be destroyed by the
+ StackView; only items that StackView creates from \l {Component}{Components}
+ or \l [QML] {url}{URLs} are destroyed by the StackView. To illustrate this,
+ the messages in the example below will only be printed when the StackView
+ is destroyed, not when the items are popped off the stack:
+
+ \qml
+ Component {
+ id: itemComponent
+
+ Item {
+ Component.onDestruction: print("Destroying second item")
+ }
+ }
+
+ StackView {
+ initialItem: Item {
+ Component.onDestruction: print("Destroying initial item")
+ }
+
+ Component.onCompleted: push(itemComponent.createObject(window))
+ }
+ \endqml
+
+ However, both of the items created from the URL and Component in the
+ following example will be destroyed by the StackView when they are popped
+ off of it:
+
+ \qml
+ Component {
+ id: itemComponent
+
+ Item {
+ Component.onDestruction: print("Destroying second item")
+ }
+ }
+
+ StackView {
+ initialItem: "Item1.qml"
+
+ Component.onCompleted: push(itemComponent)
+ }
+ \endqml
+
+ \section1 Size
+
+ StackView does not inherit an implicit size from items that are pushed onto
+ it. This means that using it as the \l {Popup::}{contentItem} of a
+ \l Dialog, for example, will not work as expected:
+
+ \code
+ Dialog {
+ StackView {
+ initialItem: Rectangle {
+ width: 200
+ height: 200
+ color: "salmon"
+ }
+ }
+ }
+ \endcode
+
+ There are several ways to ensure that StackView has a size in this
+ situation:
+
+ \list
+ \li Set \l[QtQuick]{Item::}{implicitWidth} and
+ \l[QtQuick]{Item::}{implicitHeight} on the StackView itself.
+ \li Set \l[QtQuick]{Item::}{implicitWidth} and
+ \l[QtQuick]{Item::}{implicitHeight} on the \l Rectangle.
+ \li Set \l {Popup::}{contentWidth} and \l {Popup::}{contentHeight} on
+ the Dialog.
+ \li Give the Dialog a size.
+ \endlist
+
+ \sa {Customizing StackView}, {Navigating with StackView}, {Navigation Controls},
+ {Container Controls}, {Focus Management in Qt Quick Controls}
+*/
+
+QQuickStackView::QQuickStackView(QQuickItem *parent)
+ : QQuickControl(*(new QQuickStackViewPrivate), parent)
+{
+ setFlag(ItemIsFocusScope);
+}
+
+QQuickStackView::~QQuickStackView()
+{
+ Q_D(QQuickStackView);
+ if (d->transitioner) {
+ d->transitioner->setChangeListener(nullptr);
+ delete d->transitioner;
+ }
+ qDeleteAll(d->removing);
+ qDeleteAll(d->removed);
+ qDeleteAll(d->elements);
+}
+
+QQuickStackViewAttached *QQuickStackView::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickStackViewAttached(object);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::StackView::busy
+ \readonly
+ This property holds whether a transition is running.
+*/
+bool QQuickStackView::isBusy() const
+{
+ Q_D(const QQuickStackView);
+ return d->busy;
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::StackView::depth
+ \readonly
+ This property holds the number of items currently pushed onto the stack.
+*/
+int QQuickStackView::depth() const
+{
+ Q_D(const QQuickStackView);
+ return d->elements.count();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::StackView::currentItem
+ \readonly
+ This property holds the current top-most item in the stack.
+*/
+QQuickItem *QQuickStackView::currentItem() const
+{
+ Q_D(const QQuickStackView);
+ return d->currentItem;
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::StackView::get(index, behavior)
+
+ Returns the item at position \a index in the stack, or \c null if the index
+ is out of bounds.
+
+ Supported \a behavior values:
+ \value StackView.DontLoad The item is not forced to load (and \c null is returned if not yet loaded).
+ \value StackView.ForceLoad The item is forced to load.
+*/
+QQuickItem *QQuickStackView::get(int index, LoadBehavior behavior)
+{
+ Q_D(QQuickStackView);
+ QQuickStackElement *element = d->elements.value(index);
+ if (element) {
+ if (behavior == ForceLoad)
+ element->load(this);
+ return element->item;
+ }
+ return nullptr;
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::StackView::find(callback, behavior)
+
+ Search for a specific item inside the stack. The \a callback function is called
+ for each item in the stack (with the item and index as arguments) until the callback
+ function returns \c true. The return value is the item found. For example:
+
+ \code
+ stackView.find(function(item, index) {
+ return item.isTheOne
+ })
+ \endcode
+
+ Supported \a behavior values:
+ \value StackView.DontLoad Unloaded items are skipped (the callback function is not called for them).
+ \value StackView.ForceLoad Unloaded items are forced to load.
+*/
+QQuickItem *QQuickStackView::find(const QJSValue &callback, LoadBehavior behavior)
+{
+ Q_D(QQuickStackView);
+ QJSValue func(callback);
+ QQmlEngine *engine = qmlEngine(this);
+ if (!engine || !func.isCallable()) // TODO: warning?
+ return nullptr;
+
+ for (int i = d->elements.count() - 1; i >= 0; --i) {
+ QQuickStackElement *element = d->elements.at(i);
+ if (behavior == ForceLoad)
+ element->load(this);
+ if (element->item) {
+ QJSValue rv = func.call(QJSValueList() << engine->newQObject(element->item) << i);
+ if (rv.toBool())
+ return element->item;
+ }
+ }
+
+ return nullptr;
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::StackView::push(item, properties, operation)
+
+ Pushes an \a item onto the stack using an optional \a operation, and
+ optionally applies a set of \a properties on the item. The item can be
+ an \l Item, \l Component, or a \l [QML] url. Returns the item that became
+ current.
+
+ StackView creates an instance automatically if the pushed item is a \l Component,
+ or a \l [QML] url, and the instance will be destroyed when it is popped
+ off the stack. See \l {Item Ownership} for more information.
+
+ The optional \a properties argument specifies a map of initial
+ property values for the pushed item. For dynamically created items, these values
+ are applied before the creation is finalized. This is more efficient than setting
+ property values after creation, particularly where large sets of property values
+ are defined, and also allows property bindings to be set up (using \l{Qt::binding}
+ {Qt.binding()}) before the item is created.
+
+ Pushing a single item:
+ \code
+ stackView.push(rect)
+
+ // or with properties:
+ stackView.push(rect, {"color": "red"})
+ \endcode
+
+ Multiple items can be pushed at the same time either by passing them as
+ additional arguments, or as an array. The last item becomes the current
+ item. Each item can be followed by a set of properties to apply.
+
+ Passing a variable amount of arguments:
+ \code
+ stackView.push(rect1, rect2, rect3)
+
+ // or with properties:
+ stackView.push(rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"})
+ \endcode
+
+ Pushing an array of items:
+ \code
+ stackView.push([rect1, rect2, rect3])
+
+ // or with properties:
+ stackView.push([rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}])
+ \endcode
+
+ An \a operation can be optionally specified as the last argument. Supported
+ operations:
+
+ \value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
+
+ If no operation is provided, \c PushTransition will be used.
+
+ \note Items that already exist in the stack are not pushed.
+
+ \sa initialItem, {Pushing Items}
+*/
+void QQuickStackView::push(QQmlV4Function *args)
+{
+ Q_D(QQuickStackView);
+ const QString operationName = QStringLiteral("push");
+ if (d->modifyingElements) {
+ d->warnOfInterruption(operationName);
+ return;
+ }
+
+ QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true);
+ QScopedValueRollback<QString> operationNameRollback(d->operation, operationName);
+ if (args->length() <= 0) {
+ d->warn(QStringLiteral("missing arguments"));
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ Operation operation = d->elements.isEmpty() ? Immediate : PushTransition;
+ QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+
+ QStringList errors;
+ QList<QQuickStackElement *> elements = d->parseElements(0, args, &errors);
+ // Remove any items that are already in the stack, as they can't be in two places at once.
+ for (int i = 0; i < elements.size(); ) {
+ QQuickStackElement *element = elements.at(i);
+ if (element->item && d->findElement(element->item))
+ elements.removeAt(i);
+ else
+ ++i;
+ }
+
+ if (!errors.isEmpty() || elements.isEmpty()) {
+ if (!errors.isEmpty()) {
+ for (const QString &error : qAsConst(errors))
+ d->warn(error);
+ } else {
+ d->warn(QStringLiteral("nothing to push"));
+ }
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QQuickStackElement *exit = nullptr;
+ if (!d->elements.isEmpty())
+ exit = d->elements.top();
+
+ int oldDepth = d->elements.count();
+ if (d->pushElements(elements)) {
+ d->depthChange(d->elements.count(), oldDepth);
+ QQuickStackElement *enter = d->elements.top();
+ d->startTransition(QQuickStackTransition::pushEnter(operation, enter, this),
+ QQuickStackTransition::pushExit(operation, exit, this),
+ operation == Immediate);
+ d->setCurrentItem(enter);
+ }
+
+ if (d->currentItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem));
+ args->setReturnValue(rv->asReturnedValue());
+ } else {
+ args->setReturnValue(QV4::Encode::null());
+ }
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::StackView::pop(item, operation)
+
+ Pops one or more items off the stack. Returns the last item removed from the stack.
+
+ If the \a item argument is specified, all items down to (but not
+ including) \a item will be popped. If \a item is \c null, all
+ items down to (but not including) the first item is popped.
+ If not specified, only the current item is popped.
+
+ \note A pop() operation on a stack with depth 1 or 0 does nothing. In such
+ cases, the stack can be emptied using the \l clear() method.
+
+ \include qquickstackview.qdocinc pop-ownership
+
+ An \a operation can be optionally specified as the last argument. Supported
+ operations:
+
+ \value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
+
+ If no operation is provided, \c PopTransition will be used.
+
+ Examples:
+ \code
+ stackView.pop()
+ stackView.pop(someItem, StackView.Immediate)
+ stackView.pop(StackView.Immediate)
+ stackView.pop(null)
+ \endcode
+
+ \sa clear(), {Popping Items}, {Unwinding Items via Pop}
+*/
+void QQuickStackView::pop(QQmlV4Function *args)
+{
+ Q_D(QQuickStackView);
+ const QString operationName = QStringLiteral("pop");
+ if (d->modifyingElements) {
+ d->warnOfInterruption(operationName);
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true);
+ QScopedValueRollback<QString> operationNameRollback(d->operation, operationName);
+ int argc = args->length();
+ if (d->elements.count() <= 1 || argc > 2) {
+ if (argc > 2)
+ d->warn(QStringLiteral("too many arguments"));
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ int oldDepth = d->elements.count();
+ QQuickStackElement *exit = d->elements.pop();
+ QQuickStackElement *enter = d->elements.top();
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ if (argc > 0) {
+ QV4::ScopedValue value(scope, (*args)[0]);
+ if (value->isNull()) {
+ enter = d->elements.value(0);
+ } else if (const QV4::QObjectWrapper *o = value->as<QV4::QObjectWrapper>()) {
+ QQuickItem *item = qobject_cast<QQuickItem *>(o->object());
+ enter = d->findElement(item);
+ if (!enter) {
+ if (item != d->currentItem)
+ d->warn(QStringLiteral("unknown argument: ") + value->toQString()); // TODO: safe?
+ args->setReturnValue(QV4::Encode::null());
+ d->elements.push(exit); // restore
+ return;
+ }
+ }
+ }
+
+ Operation operation = PopTransition;
+ if (argc > 0) {
+ QV4::ScopedValue lastArg(scope, (*args)[argc - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+ }
+
+ QQuickItem *previousItem = nullptr;
+
+ if (d->popElements(enter)) {
+ if (exit) {
+ exit->removal = true;
+ d->removing.insert(exit);
+ previousItem = exit->item;
+ }
+ d->depthChange(d->elements.count(), oldDepth);
+ d->startTransition(QQuickStackTransition::popExit(operation, exit, this),
+ QQuickStackTransition::popEnter(operation, enter, this),
+ operation == Immediate);
+ d->setCurrentItem(enter);
+ }
+
+ if (previousItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, previousItem));
+ args->setReturnValue(rv->asReturnedValue());
+ } else {
+ args->setReturnValue(QV4::Encode::null());
+ }
+}
+
+/*!
+ \qmlmethod Item QtQuick.Controls::StackView::replace(target, item, properties, operation)
+
+ Replaces one or more items on the stack with the specified \a item and
+ optional \a operation, and optionally applies a set of \a properties on the
+ item. The item can be an \l Item, \l Component, or a \l [QML] url.
+ Returns the item that became current.
+
+ \include qquickstackview.qdocinc pop-ownership
+
+ If the \a target argument is specified, all items down to the \a target
+ item will be replaced. If \a target is \c null, all items in the stack
+ will be replaced. If not specified, only the top item will be replaced.
+
+ StackView creates an instance automatically if the replacing item is a \l Component,
+ or a \l [QML] url. The optional \a properties argument specifies a map of initial
+ property values for the replacing item. For dynamically created items, these values
+ are applied before the creation is finalized. This is more efficient than setting
+ property values after creation, particularly where large sets of property values
+ are defined, and also allows property bindings to be set up (using \l{Qt::binding}
+ {Qt.binding()}) before the item is created.
+
+ Replace the top item:
+ \code
+ stackView.replace(rect)
+
+ // or with properties:
+ stackView.replace(rect, {"color": "red"})
+ \endcode
+
+ Multiple items can be replaced at the same time either by passing them as
+ additional arguments, or as an array. Each item can be followed by a set
+ of properties to apply.
+
+ Passing a variable amount of arguments:
+ \code
+ stackView.replace(rect1, rect2, rect3)
+
+ // or with properties:
+ stackView.replace(rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"})
+ \endcode
+
+ Replacing an array of items:
+ \code
+ stackView.replace([rect1, rect2, rect3])
+
+ // or with properties:
+ stackView.replace([rect1, {"color": "red"}, rect2, {"color": "green"}, rect3, {"color": "blue"}])
+ \endcode
+
+ An \a operation can be optionally specified as the last argument. Supported
+ operations:
+
+ \value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
+
+ If no operation is provided, \c ReplaceTransition will be used.
+
+ The following example illustrates the use of push and pop transitions with replace().
+
+ \code
+ StackView {
+ id: stackView
+
+ initialItem: Component {
+ id: page
+
+ Page {
+ Row {
+ spacing: 20
+ anchors.centerIn: parent
+
+ Button {
+ text: "<"
+ onClicked: stackView.replace(page, StackView.PopTransition)
+ }
+ Button {
+ text: ">"
+ onClicked: stackView.replace(page, StackView.PushTransition)
+ }
+ }
+ }
+ }
+ }
+ \endcode
+
+ \sa push(), {Replacing Items}
+*/
+void QQuickStackView::replace(QQmlV4Function *args)
+{
+ Q_D(QQuickStackView);
+ const QString operationName = QStringLiteral("replace");
+ if (d->modifyingElements) {
+ d->warnOfInterruption(operationName);
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true);
+ QScopedValueRollback<QString> operationNameRollback(d->operation, operationName);
+ if (args->length() <= 0) {
+ d->warn(QStringLiteral("missing arguments"));
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ QV4::Scope scope(v4);
+
+ Operation operation = d->elements.isEmpty() ? Immediate : ReplaceTransition;
+ QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
+ if (lastArg->isInt32())
+ operation = static_cast<Operation>(lastArg->toInt32());
+
+ QQuickStackElement *target = nullptr;
+ QV4::ScopedValue firstArg(scope, (*args)[0]);
+ if (firstArg->isNull())
+ target = d->elements.value(0);
+ else if (!firstArg->isInt32())
+ target = d->findElement(firstArg);
+
+ QStringList errors;
+ QList<QQuickStackElement *> elements = d->parseElements(target ? 1 : 0, args, &errors);
+ if (!errors.isEmpty() || elements.isEmpty()) {
+ if (!errors.isEmpty()) {
+ for (const QString &error : qAsConst(errors))
+ d->warn(error);
+ } else {
+ d->warn(QStringLiteral("nothing to push"));
+ }
+ args->setReturnValue(QV4::Encode::null());
+ return;
+ }
+
+ int oldDepth = d->elements.count();
+ QQuickStackElement* exit = nullptr;
+ if (!d->elements.isEmpty())
+ exit = d->elements.pop();
+
+ if (exit != target ? d->replaceElements(target, elements) : d->pushElements(elements)) {
+ d->depthChange(d->elements.count(), oldDepth);
+ if (exit) {
+ exit->removal = true;
+ d->removing.insert(exit);
+ }
+ QQuickStackElement *enter = d->elements.top();
+ d->startTransition(QQuickStackTransition::replaceExit(operation, exit, this),
+ QQuickStackTransition::replaceEnter(operation, enter, this),
+ operation == Immediate);
+ d->setCurrentItem(enter);
+ }
+
+ if (d->currentItem) {
+ QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(v4, d->currentItem));
+ args->setReturnValue(rv->asReturnedValue());
+ } else {
+ args->setReturnValue(QV4::Encode::null());
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::StackView::empty
+ \readonly
+
+ This property holds whether the stack is empty.
+
+ \sa depth
+*/
+bool QQuickStackView::isEmpty() const
+{
+ Q_D(const QQuickStackView);
+ return d->elements.isEmpty();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::StackView::clear(transition)
+
+ Removes all items from the stack.
+
+ \include qquickstackview.qdocinc pop-ownership
+
+ Since QtQuick.Controls 2.3, a \a transition can be optionally specified. Supported transitions:
+
+ \value StackView.Immediate Clear the stack immediately without any transition (default).
+ \value StackView.PushTransition Clear the stack with a push transition.
+ \value StackView.ReplaceTransition Clear the stack with a replace transition.
+ \value StackView.PopTransition Clear the stack with a pop transition.
+*/
+void QQuickStackView::clear(Operation operation)
+{
+ Q_D(QQuickStackView);
+ if (d->elements.isEmpty())
+ return;
+
+ const QString operationName = QStringLiteral("clear");
+ if (d->modifyingElements) {
+ d->warnOfInterruption(operationName);
+ return;
+ }
+
+ QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true);
+ QScopedValueRollback<QString> operationNameRollback(d->operation, operationName);
+ if (operation != Immediate) {
+ QQuickStackElement *exit = d->elements.pop();
+ exit->removal = true;
+ d->removing.insert(exit);
+ d->startTransition(QQuickStackTransition::popExit(operation, exit, this),
+ QQuickStackTransition::popEnter(operation, nullptr, this), false);
+ }
+
+ int oldDepth = d->elements.count();
+ d->setCurrentItem(nullptr);
+ qDeleteAll(d->elements);
+ d->elements.clear();
+ d->depthChange(0, oldDepth);
+}
+
+/*!
+ \qmlproperty var QtQuick.Controls::StackView::initialItem
+
+ This property holds the initial item that should be shown when the StackView
+ is created. The initial item can be an \l Item, \l Component, or a \l [QML] url.
+ Specifying an initial item is equivalent to:
+ \code
+ Component.onCompleted: stackView.push(myInitialItem)
+ \endcode
+
+ \sa push()
+*/
+QJSValue QQuickStackView::initialItem() const
+{
+ Q_D(const QQuickStackView);
+ return d->initialItem;
+}
+
+void QQuickStackView::setInitialItem(const QJSValue &item)
+{
+ Q_D(QQuickStackView);
+ d->initialItem = item;
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::popEnter
+
+ This property holds the transition that is applied to the item that
+ enters the stack when another item is popped off of it.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::popEnter() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->removeDisplacedTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setPopEnter(QQuickTransition *enter)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->removeDisplacedTransition == enter)
+ return;
+
+ d->transitioner->removeDisplacedTransition = enter;
+ emit popEnterChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::popExit
+
+ This property holds the transition that is applied to the item that
+ exits the stack when the item is popped off of it.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::popExit() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->removeTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setPopExit(QQuickTransition *exit)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->removeTransition == exit)
+ return;
+
+ d->transitioner->removeTransition = exit;
+ emit popExitChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::pushEnter
+
+ This property holds the transition that is applied to the item that
+ enters the stack when the item is pushed onto it.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::pushEnter() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->addTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setPushEnter(QQuickTransition *enter)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->addTransition == enter)
+ return;
+
+ d->transitioner->addTransition = enter;
+ emit pushEnterChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::pushExit
+
+ This property holds the transition that is applied to the item that
+ exits the stack when another item is pushed onto it.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::pushExit() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->addDisplacedTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setPushExit(QQuickTransition *exit)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->addDisplacedTransition == exit)
+ return;
+
+ d->transitioner->addDisplacedTransition = exit;
+ emit pushExitChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::replaceEnter
+
+ This property holds the transition that is applied to the item that
+ enters the stack when another item is replaced by it.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::replaceEnter() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->moveTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setReplaceEnter(QQuickTransition *enter)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->moveTransition == enter)
+ return;
+
+ d->transitioner->moveTransition = enter;
+ emit replaceEnterChanged();
+}
+
+/*!
+ \qmlproperty Transition QtQuick.Controls::StackView::replaceExit
+
+ This property holds the transition that is applied to the item that
+ exits the stack when it is replaced by another item.
+
+ \sa {Customizing StackView}
+*/
+QQuickTransition *QQuickStackView::replaceExit() const
+{
+ Q_D(const QQuickStackView);
+ if (d->transitioner)
+ return d->transitioner->moveDisplacedTransition;
+ return nullptr;
+}
+
+void QQuickStackView::setReplaceExit(QQuickTransition *exit)
+{
+ Q_D(QQuickStackView);
+ d->ensureTransitioner();
+ if (d->transitioner->moveDisplacedTransition == exit)
+ return;
+
+ d->transitioner->moveDisplacedTransition = exit;
+ emit replaceExitChanged();
+}
+
+void QQuickStackView::componentComplete()
+{
+ QQuickControl::componentComplete();
+
+ Q_D(QQuickStackView);
+ QScopedValueRollback<QString> operationNameRollback(d->operation, QStringLiteral("initialItem"));
+ QQuickStackElement *element = nullptr;
+ QString error;
+ int oldDepth = d->elements.count();
+ if (QObject *o = d->initialItem.toQObject())
+ element = QQuickStackElement::fromObject(o, this, &error);
+ else if (d->initialItem.isString())
+ element = QQuickStackElement::fromString(d->initialItem.toString(), this, &error);
+ if (!error.isEmpty()) {
+ d->warn(error);
+ delete element;
+ } else if (d->pushElement(element)) {
+ d->depthChange(d->elements.count(), oldDepth);
+ d->setCurrentItem(element);
+ element->setStatus(QQuickStackView::Active);
+ }
+}
+
+void QQuickStackView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ QQuickControl::geometryChange(newGeometry, oldGeometry);
+
+ Q_D(QQuickStackView);
+ for (QQuickStackElement *element : qAsConst(d->elements)) {
+ if (element->item) {
+ if (!element->widthValid)
+ element->item->setWidth(newGeometry.width());
+ if (!element->heightValid)
+ element->item->setHeight(newGeometry.height());
+ }
+ }
+}
+
+bool QQuickStackView::childMouseEventFilter(QQuickItem *item, QEvent *event)
+{
+ // in order to block accidental user interaction while busy/transitioning,
+ // StackView filters out childrens' mouse events. therefore we block all
+ // press events. however, since push() may be called from signal handlers
+ // such as onPressed or onDoubleClicked, we must let the current mouse
+ // grabber item receive the respective mouse release event to avoid
+ // breaking its state (QTBUG-50305).
+ if (event->type() == QEvent::MouseButtonPress)
+ return true;
+ if (event->type() == QEvent::UngrabMouse)
+ return false;
+ QQuickWindow *window = item->window();
+ return window && !window->mouseGrabberItem();
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickStackView::touchEvent(QTouchEvent *event)
+{
+ event->ignore(); // QTBUG-65084
+}
+#endif
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickStackView::accessibleRole() const
+{
+ return QAccessible::LayeredPane;
+}
+#endif
+
+void QQuickStackViewAttachedPrivate::itemParentChanged(QQuickItem *item, QQuickItem *parent)
+{
+ Q_Q(QQuickStackViewAttached);
+ int oldIndex = element ? element->index : -1;
+ QQuickStackView *oldView = element ? element->view : nullptr;
+ QQuickStackView::Status oldStatus = element ? element->status : QQuickStackView::Inactive;
+
+ QQuickStackView *newView = qobject_cast<QQuickStackView *>(parent);
+ element = newView ? QQuickStackViewPrivate::get(newView)->findElement(item) : nullptr;
+
+ int newIndex = element ? element->index : -1;
+ QQuickStackView::Status newStatus = element ? element->status : QQuickStackView::Inactive;
+
+ if (oldIndex != newIndex)
+ emit q->indexChanged();
+ if (oldView != newView)
+ emit q->viewChanged();
+ if (oldStatus != newStatus)
+ emit q->statusChanged();
+}
+
+QQuickStackViewAttached::QQuickStackViewAttached(QObject *parent)
+ : QObject(*(new QQuickStackViewAttachedPrivate), parent)
+{
+ Q_D(QQuickStackViewAttached);
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (item) {
+ connect(item, &QQuickItem::visibleChanged, this, &QQuickStackViewAttached::visibleChanged);
+ QQuickItemPrivate::get(item)->addItemChangeListener(d, QQuickItemPrivate::Parent);
+ d->itemParentChanged(item, item->parentItem());
+ } else if (parent) {
+ qmlWarning(parent) << "StackView must be attached to an Item";
+ }
+}
+
+QQuickStackViewAttached::~QQuickStackViewAttached()
+{
+ Q_D(QQuickStackViewAttached);
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ if (parentItem)
+ QQuickItemPrivate::get(parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Parent);
+}
+
+/*!
+ \qmlattachedproperty int QtQuick.Controls::StackView::index
+ \readonly
+
+ This attached property holds the stack index of the item it's
+ attached to, or \c -1 if the item is not in a stack.
+*/
+int QQuickStackViewAttached::index() const
+{
+ Q_D(const QQuickStackViewAttached);
+ return d->element ? d->element->index : -1;
+}
+
+/*!
+ \qmlattachedproperty StackView QtQuick.Controls::StackView::view
+ \readonly
+
+ This attached property holds the stack view of the item it's
+ attached to, or \c null if the item is not in a stack.
+*/
+QQuickStackView *QQuickStackViewAttached::view() const
+{
+ Q_D(const QQuickStackViewAttached);
+ return d->element ? d->element->view : nullptr;
+}
+
+/*!
+ \qmlattachedproperty enumeration QtQuick.Controls::StackView::status
+ \readonly
+
+ This attached property holds the stack status of the item it's
+ attached to, or \c StackView.Inactive if the item is not in a stack.
+
+ Available values:
+ \value StackView.Inactive The item is inactive (or not in a stack).
+ \value StackView.Deactivating The item is being deactivated (popped off).
+ \value StackView.Activating The item is being activated (becoming the current item).
+ \value StackView.Active The item is active, that is, the current item.
+*/
+QQuickStackView::Status QQuickStackViewAttached::status() const
+{
+ Q_D(const QQuickStackViewAttached);
+ return d->element ? d->element->status : QQuickStackView::Inactive;
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlattachedproperty bool QtQuick.Controls::StackView::visible
+
+ This attached property holds the visibility of the item it's attached to.
+ The value follows the value of \l Item::visible.
+
+ By default, StackView shows incoming items when the enter transition begins,
+ and hides outgoing items when the exit transition ends. Setting this property
+ explicitly allows the default behavior to be overridden, making it possible
+ to keep items that are below the top-most item visible.
+
+ \note The default transitions of most styles slide outgoing items outside the
+ view, and may also animate their opacity. In order to keep a full stack
+ of items visible, consider customizing the \l transitions so that the
+ items underneath can be seen.
+
+ \image qtquickcontrols2-stackview-visible.png
+
+ \snippet qtquickcontrols2-stackview-visible.qml 1
+*/
+bool QQuickStackViewAttached::isVisible() const
+{
+ const QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ return parentItem && parentItem->isVisible();
+}
+
+void QQuickStackViewAttached::setVisible(bool visible)
+{
+ Q_D(QQuickStackViewAttached);
+ d->explicitVisible = true;
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ if (parentItem)
+ parentItem->setVisible(visible);
+}
+
+void QQuickStackViewAttached::resetVisible()
+{
+ Q_D(QQuickStackViewAttached);
+ d->explicitVisible = false;
+ if (!d->element || !d->element->view)
+ return;
+
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ if (parentItem)
+ parentItem->setVisible(parentItem == d->element->view->currentItem());
+}
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::activated()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This attached signal is emitted when the item it's attached to is activated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::deactivated()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This attached signal is emitted when the item it's attached to is deactivated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::activating()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This attached signal is emitted when the item it's attached to is in the process of being
+ activated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::deactivating()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This attached signal is emitted when the item it's attached to is in the process of being
+ dectivated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::removed()
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This attached signal is emitted when the item it's attached to has been
+ removed from the stack. It can be used to safely destroy an Item that was
+ pushed onto the stack, for example:
+
+ \code
+ Item {
+ StackView.onRemoved: destroy() // Will be destroyed sometime after this call.
+ }
+ \endcode
+
+ \sa status
+*/
+
+QT_END_NAMESPACE
+
+#include "moc_qquickstackview_p.cpp"
diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp
new file mode 100644
index 0000000000..402efa75d1
--- /dev/null
+++ b/src/quicktemplates2/qquickstackview_p.cpp
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickstackview_p_p.h"
+#include "qquickstackelement_p_p.h"
+#include "qquickstacktransition_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmllist.h>
+#include <QtQml/private/qv4qmlcontext_p.h>
+#include <QtQml/private/qv4qobjectwrapper_p.h>
+#include <QtQml/private/qv4variantobject_p.h>
+#include <QtQml/private/qv4urlobject_p.h>
+#include <QtQuick/private/qquickanimation_p.h>
+#include <QtQuick/private/qquicktransition_p.h>
+
+QT_BEGIN_NAMESPACE
+
+void QQuickStackViewPrivate::warn(const QString &error)
+{
+ Q_Q(QQuickStackView);
+ if (operation.isEmpty())
+ qmlWarning(q) << error;
+ else
+ qmlWarning(q) << operation << ": " << error;
+}
+
+void QQuickStackViewPrivate::warnOfInterruption(const QString &attemptedOperation)
+{
+ Q_Q(QQuickStackView);
+ qmlWarning(q) << "cannot " << attemptedOperation << " while already in the process of completing a " << operation;
+}
+
+void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element)
+{
+ Q_Q(QQuickStackView);
+ QQuickItem *item = element ? element->item : nullptr;
+ if (currentItem == item)
+ return;
+
+ currentItem = item;
+ if (element)
+ element->setVisible(true);
+ if (item)
+ item->setFocus(true);
+ emit q->currentItemChanged();
+}
+
+static bool initProperties(QQuickStackElement *element, const QV4::Value &props, QQmlV4Function *args)
+{
+ if (props.isObject()) {
+ const QV4::QObjectWrapper *wrapper = props.as<QV4::QObjectWrapper>();
+ if (!wrapper) {
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ element->properties.set(v4, props);
+ element->qmlCallingContext.set(v4, v4->qmlContext());
+ return true;
+ }
+ }
+ return false;
+}
+
+QList<QQuickStackElement *> QQuickStackViewPrivate::parseElements(int from, QQmlV4Function *args, QStringList *errors)
+{
+ QV4::ExecutionEngine *v4 = args->v4engine();
+ auto context = v4->callingQmlContext();
+ QV4::Scope scope(v4);
+
+ QList<QQuickStackElement *> elements;
+
+ int argc = args->length();
+ for (int i = from; i < argc; ++i) {
+ QV4::ScopedValue arg(scope, (*args)[i]);
+ if (QV4::ArrayObject *array = arg->as<QV4::ArrayObject>()) {
+ const uint len = uint(array->getLength());
+ for (uint j = 0; j < len; ++j) {
+ QString error;
+ QV4::ScopedValue value(scope, array->get(j));
+ QQuickStackElement *element = createElement(value, context, &error);
+ if (element) {
+ if (j < len - 1) {
+ QV4::ScopedValue props(scope, array->get(j + 1));
+ if (initProperties(element, props, args))
+ ++j;
+ }
+ elements += element;
+ } else if (!error.isEmpty()) {
+ *errors += error;
+ }
+ }
+ } else {
+ QString error;
+ QQuickStackElement *element = createElement(arg, context, &error);
+ if (element) {
+ if (i < argc - 1) {
+ QV4::ScopedValue props(scope, (*args)[i + 1]);
+ if (initProperties(element, props, args))
+ ++i;
+ }
+ elements += element;
+ } else if (!error.isEmpty()) {
+ *errors += error;
+ }
+ }
+ }
+ return elements;
+}
+
+QQuickStackElement *QQuickStackViewPrivate::findElement(QQuickItem *item) const
+{
+ if (item) {
+ for (QQuickStackElement *e : qAsConst(elements)) {
+ if (e->item == item)
+ return e;
+ }
+ }
+ return nullptr;
+}
+
+QQuickStackElement *QQuickStackViewPrivate::findElement(const QV4::Value &value) const
+{
+ if (const QV4::QObjectWrapper *o = value.as<QV4::QObjectWrapper>())
+ return findElement(qobject_cast<QQuickItem *>(o->object()));
+ return nullptr;
+}
+
+static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer<QQmlContextData> &context)
+{
+ if (url.isRelative())
+ return context->resolvedUrl(url).toString();
+ return url;
+}
+
+static QString resolvedUrl(const QString &str, const QQmlRefPointer<QQmlContextData> &context)
+{
+ QUrl url(str);
+ if (url.isRelative())
+ return context->resolvedUrl(url).toString();
+ return str;
+}
+
+QQuickStackElement *QQuickStackViewPrivate::createElement(const QV4::Value &value, const QQmlRefPointer<QQmlContextData> &context, QString *error)
+{
+ Q_Q(QQuickStackView);
+ if (const QV4::String *s = value.as<QV4::String>())
+ return QQuickStackElement::fromString(resolvedUrl(s->toQString(), context), q, error);
+ if (const QV4::QObjectWrapper *o = value.as<QV4::QObjectWrapper>())
+ return QQuickStackElement::fromObject(o->object(), q, error);
+ if (const QV4::UrlObject *u = value.as<QV4::UrlObject>())
+ return QQuickStackElement::fromString(resolvedUrl(u->href(), context), q, error);
+
+ if (const QV4::Object *v = value.as<QV4::Object>()) {
+ const QVariant data = v->engine()->toVariant(value, QMetaType::fromType<QUrl>());
+ if (data.typeId() == QMetaType::QUrl) {
+ return QQuickStackElement::fromString(resolvedUrl(data.toUrl(), context).toString(), q,
+ error);
+ }
+ }
+
+ return nullptr;
+}
+
+bool QQuickStackViewPrivate::pushElements(const QList<QQuickStackElement *> &elems)
+{
+ Q_Q(QQuickStackView);
+ if (!elems.isEmpty()) {
+ for (QQuickStackElement *e : elems) {
+ e->setIndex(elements.count());
+ elements += e;
+ }
+ return elements.top()->load(q);
+ }
+ return false;
+}
+
+bool QQuickStackViewPrivate::pushElement(QQuickStackElement *element)
+{
+ if (element)
+ return pushElements(QList<QQuickStackElement *>() << element);
+ return false;
+}
+
+bool QQuickStackViewPrivate::popElements(QQuickStackElement *element)
+{
+ Q_Q(QQuickStackView);
+ while (elements.count() > 1 && elements.top() != element) {
+ delete elements.pop();
+ if (!element)
+ break;
+ }
+ return elements.top()->load(q);
+}
+
+bool QQuickStackViewPrivate::replaceElements(QQuickStackElement *target, const QList<QQuickStackElement *> &elems)
+{
+ if (target) {
+ while (!elements.isEmpty()) {
+ QQuickStackElement* top = elements.pop();
+ delete top;
+ if (top == target)
+ break;
+ }
+ }
+ return pushElements(elems);
+}
+
+void QQuickStackViewPrivate::ensureTransitioner()
+{
+ if (!transitioner) {
+ transitioner = new QQuickItemViewTransitioner;
+ transitioner->setChangeListener(this);
+ }
+}
+
+void QQuickStackViewPrivate::startTransition(const QQuickStackTransition &first, const QQuickStackTransition &second, bool immediate)
+{
+ if (first.element)
+ first.element->transitionNextReposition(transitioner, first.type, first.target);
+ if (second.element)
+ second.element->transitionNextReposition(transitioner, second.type, second.target);
+
+ if (first.element) {
+ // Let the check for immediate happen after prepareTransition() is
+ // called, because we need the prepared transition in both branches.
+ // Same for the second element.
+ if (!first.element->item || !first.element->prepareTransition(transitioner, first.viewBounds) || immediate)
+ completeTransition(first.element, first.transition, first.status);
+ else
+ first.element->startTransition(transitioner, first.status);
+ }
+ if (second.element) {
+ if (!second.element->item || !second.element->prepareTransition(transitioner, second.viewBounds) || immediate)
+ completeTransition(second.element, second.transition, second.status);
+ else
+ second.element->startTransition(transitioner, second.status);
+ }
+
+ if (transitioner) {
+ setBusy(!transitioner->runningJobs.isEmpty());
+ transitioner->resetTargetLists();
+ }
+}
+
+void QQuickStackViewPrivate::completeTransition(QQuickStackElement *element, QQuickTransition *transition, QQuickStackView::Status status)
+{
+ element->setStatus(status);
+ if (transition) {
+ if (element->prepared) {
+ // Here we force reading all the animations, even if the desired
+ // transition type is StackView.Immediate. After that we force
+ // all the animations to complete immediately, without waiting for
+ // the animation timer.
+ // This allows us to correctly restore all the properties affected
+ // by the push/pop animations.
+ ACTION_IF_DELETED(element, element->completeTransition(transition), return);
+ } else if (element->item) {
+ // At least try to move the item to its desired place. This,
+ // however, is only a partly correct solution, because a lot more
+ // properties can be affected by the transition
+ element->item->setPosition(element->nextTransitionTo);
+ }
+ }
+ viewItemTransitionFinished(element);
+}
+
+void QQuickStackViewPrivate::viewItemTransitionFinished(QQuickItemViewTransitionableItem *transitionable)
+{
+ QQuickStackElement *element = static_cast<QQuickStackElement *>(transitionable);
+ if (element->status == QQuickStackView::Activating) {
+ element->setStatus(QQuickStackView::Active);
+ } else if (element->status == QQuickStackView::Deactivating) {
+ element->setStatus(QQuickStackView::Inactive);
+ QQuickStackElement *existingElement = element->item ? findElement(element->item) : nullptr;
+ // If a different element with the same item is found,
+ // do not call setVisible(false) since it needs to be visible.
+ if (!existingElement || element == existingElement)
+ element->setVisible(false);
+ if (element->removal || element->isPendingRemoval())
+ removed += element;
+ }
+
+ if (transitioner && transitioner->runningJobs.isEmpty()) {
+ // ~QQuickStackElement() emits QQuickStackViewAttached::removed(), which may be used
+ // to modify the stack. Set the status first and make a copy of the destroyable stack
+ // elements to exclude any modifications that may happen during qDeleteAll(). (QTBUG-62153)
+ setBusy(false);
+ QList<QQuickStackElement*> removedElements = removed;
+ removed.clear();
+
+ for (QQuickStackElement *removedElement : qAsConst(removedElements)) {
+ // If an element with the same item is found in the active stack list,
+ // forget about the item so that we don't hide it.
+ if (removedElement->item && findElement(removedElement->item)) {
+ QQuickItemPrivate::get(removedElement->item)->removeItemChangeListener(removedElement, QQuickItemPrivate::Destroyed);
+ removedElement->item = nullptr;
+ }
+ }
+
+ qDeleteAll(removedElements);
+ }
+
+ removing.remove(element);
+}
+
+void QQuickStackViewPrivate::setBusy(bool b)
+{
+ Q_Q(QQuickStackView);
+ if (busy == b)
+ return;
+
+ busy = b;
+ q->setFiltersChildMouseEvents(busy);
+ emit q->busyChanged();
+}
+
+void QQuickStackViewPrivate::depthChange(int newDepth, int oldDepth)
+{
+ Q_Q(QQuickStackView);
+ if (newDepth == oldDepth)
+ return;
+
+ emit q->depthChanged();
+ if (newDepth == 0 || oldDepth == 0)
+ emit q->emptyChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h
new file mode 100644
index 0000000000..f4cb545833
--- /dev/null
+++ b/src/quicktemplates2/qquickstackview_p.h
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTACKVIEW_P_H
+#define QQUICKSTACKVIEW_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlV4Function;
+class QQuickTransition;
+class QQuickStackElement;
+class QQuickStackViewPrivate;
+class QQuickStackViewAttached;
+class QQuickStackViewAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickStackView : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(bool busy READ isBusy NOTIFY busyChanged FINAL)
+ Q_PROPERTY(int depth READ depth NOTIFY depthChanged FINAL)
+ Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
+ Q_PROPERTY(QJSValue initialItem READ initialItem WRITE setInitialItem FINAL)
+ Q_PROPERTY(QQuickTransition *popEnter READ popEnter WRITE setPopEnter NOTIFY popEnterChanged FINAL)
+ Q_PROPERTY(QQuickTransition *popExit READ popExit WRITE setPopExit NOTIFY popExitChanged FINAL)
+ Q_PROPERTY(QQuickTransition *pushEnter READ pushEnter WRITE setPushEnter NOTIFY pushEnterChanged FINAL)
+ Q_PROPERTY(QQuickTransition *pushExit READ pushExit WRITE setPushExit NOTIFY pushExitChanged FINAL)
+ Q_PROPERTY(QQuickTransition *replaceEnter READ replaceEnter WRITE setReplaceEnter NOTIFY replaceEnterChanged FINAL)
+ Q_PROPERTY(QQuickTransition *replaceExit READ replaceExit WRITE setReplaceExit NOTIFY replaceExitChanged FINAL)
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool empty READ isEmpty NOTIFY emptyChanged FINAL REVISION(2, 3))
+ QML_NAMED_ELEMENT(StackView)
+ QML_ATTACHED(QQuickStackViewAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickStackView(QQuickItem *parent = nullptr);
+ ~QQuickStackView();
+
+ static QQuickStackViewAttached *qmlAttachedProperties(QObject *object);
+
+ bool isBusy() const;
+ int depth() const;
+ QQuickItem *currentItem() const;
+
+ enum Status {
+ Inactive = 0,
+ Deactivating = 1,
+ Activating = 2,
+ Active = 3
+ };
+ Q_ENUM(Status)
+
+ QJSValue initialItem() const;
+ void setInitialItem(const QJSValue &item);
+
+ QQuickTransition *popEnter() const;
+ void setPopEnter(QQuickTransition *enter);
+
+ QQuickTransition *popExit() const;
+ void setPopExit(QQuickTransition *exit);
+
+ QQuickTransition *pushEnter() const;
+ void setPushEnter(QQuickTransition *enter);
+
+ QQuickTransition *pushExit() const;
+ void setPushExit(QQuickTransition *exit);
+
+ QQuickTransition *replaceEnter() const;
+ void setReplaceEnter(QQuickTransition *enter);
+
+ QQuickTransition *replaceExit() const;
+ void setReplaceExit(QQuickTransition *exit);
+
+ enum LoadBehavior {
+ DontLoad,
+ ForceLoad
+ };
+ Q_ENUM(LoadBehavior)
+
+ Q_INVOKABLE QQuickItem *get(int index, LoadBehavior behavior = DontLoad);
+ Q_INVOKABLE QQuickItem *find(const QJSValue &callback, LoadBehavior behavior = DontLoad);
+
+ enum Operation {
+ Transition = -1, // ### Deprecated in Qt 6; remove in Qt 7.
+ Immediate = 0,
+ PushTransition = 1,
+ ReplaceTransition = 2,
+ PopTransition = 3,
+ };
+ Q_ENUM(Operation)
+
+ Q_INVOKABLE void push(QQmlV4Function *args);
+ Q_INVOKABLE void pop(QQmlV4Function *args);
+ Q_INVOKABLE void replace(QQmlV4Function *args);
+
+ // 2.3 (Qt 5.10)
+ bool isEmpty() const;
+
+public Q_SLOTS:
+ void clear(Operation operation = Immediate);
+
+Q_SIGNALS:
+ void busyChanged();
+ void depthChanged();
+ void currentItemChanged();
+ void popEnterChanged();
+ void popExitChanged();
+ void pushEnterChanged();
+ void pushExitChanged();
+ void replaceEnterChanged();
+ void replaceExitChanged();
+ // 2.3 (Qt 5.10)
+ Q_REVISION(2, 3) void emptyChanged();
+
+protected:
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ bool childMouseEventFilter(QQuickItem *, QEvent *) override;
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickStackView)
+ Q_DECLARE_PRIVATE(QQuickStackView)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickStackViewAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
+ Q_PROPERTY(QQuickStackView *view READ view NOTIFY viewChanged FINAL)
+ Q_PROPERTY(QQuickStackView::Status status READ status NOTIFY statusChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible RESET resetVisible NOTIFY visibleChanged FINAL) // REVISION(2, 2)
+
+public:
+ explicit QQuickStackViewAttached(QObject *parent = nullptr);
+ ~QQuickStackViewAttached();
+
+ int index() const;
+ QQuickStackView *view() const;
+ QQuickStackView::Status status() const;
+
+ // 2.2 (Qt 5.9)
+ bool isVisible() const;
+ void setVisible(bool visible);
+ void resetVisible();
+
+Q_SIGNALS:
+ void indexChanged();
+ void viewChanged();
+ void statusChanged();
+ // 2.1 (Qt 5.8)
+ /*Q_REVISION(2, 1)*/ void activated();
+ /*Q_REVISION(2, 1)*/ void activating();
+ /*Q_REVISION(2, 1)*/ void deactivated();
+ /*Q_REVISION(2, 1)*/ void deactivating();
+ /*Q_REVISION(2, 1)*/ void removed();
+ // 2.2 (Qt 5.9)
+ /*Q_REVISION(2, 2)*/ void visibleChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickStackViewAttached)
+ Q_DECLARE_PRIVATE(QQuickStackViewAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickStackView)
+QML_DECLARE_TYPEINFO(QQuickStackView, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKSTACKVIEW_P_H
diff --git a/src/quicktemplates2/qquickstackview_p_p.h b/src/quicktemplates2/qquickstackview_p_p.h
new file mode 100644
index 0000000000..0c64019db8
--- /dev/null
+++ b/src/quicktemplates2/qquickstackview_p_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSTACKVIEW_P_P_H
+#define QQUICKSTACKVIEW_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 <QtQuickTemplates2/private/qquickstackview_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuick/private/qquickitemviewtransition_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQml/private/qv4value_p.h>
+#include <QtQml/private/qqmlcontextdata_p.h>
+#include <QtCore/qset.h>
+#include <QtCore/qstack.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickStackElement;
+struct QQuickStackTransition;
+
+class QQuickStackViewPrivate : public QQuickControlPrivate, public QQuickItemViewTransitionChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickStackView)
+
+public:
+ static QQuickStackViewPrivate *get(QQuickStackView *view)
+ {
+ return view->d_func();
+ }
+
+ void warn(const QString &error);
+ void warnOfInterruption(const QString &attemptedOperation);
+
+ void setCurrentItem(QQuickStackElement *element);
+
+ QList<QQuickStackElement *> parseElements(int from, QQmlV4Function *args, QStringList *errors);
+ QQuickStackElement *findElement(QQuickItem *item) const;
+ QQuickStackElement *findElement(const QV4::Value &value) const;
+ QQuickStackElement *createElement(const QV4::Value &value, const QQmlRefPointer<QQmlContextData> &context, QString *error);
+ bool pushElements(const QList<QQuickStackElement *> &elements);
+ bool pushElement(QQuickStackElement *element);
+ bool popElements(QQuickStackElement *element);
+ bool replaceElements(QQuickStackElement *element, const QList<QQuickStackElement *> &elements);
+
+ void ensureTransitioner();
+ void startTransition(const QQuickStackTransition &first, const QQuickStackTransition &second, bool immediate);
+ void completeTransition(QQuickStackElement *element, QQuickTransition *transition, QQuickStackView::Status status);
+
+ void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override;
+ void setBusy(bool busy);
+ void depthChange(int newDepth, int oldDepth);
+
+ bool busy = false;
+ bool modifyingElements = false;
+ QString operation;
+ QJSValue initialItem;
+ QQuickItem *currentItem = nullptr;
+ QSet<QQuickStackElement*> removing;
+ QList<QQuickStackElement*> removed;
+ QStack<QQuickStackElement *> elements;
+ QQuickItemViewTransitioner *transitioner = nullptr;
+};
+
+class QQuickStackViewAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickStackViewAttached)
+
+public:
+ static QQuickStackViewAttachedPrivate *get(QQuickStackViewAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
+
+ bool explicitVisible = false;
+ QQuickStackElement *element = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSTACKVIEW_P_P_H
diff --git a/src/quicktemplates2/qquickswipe_p.h b/src/quicktemplates2/qquickswipe_p.h
new file mode 100644
index 0000000000..768d5638fd
--- /dev/null
+++ b/src/quicktemplates2/qquickswipe_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWIPE_P_H
+#define QQUICKSWIPE_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/qquickswipedelegate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickItem;
+class QQuickTransition;
+class QQuickSwipePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipe : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(bool complete READ isComplete NOTIFY completeChanged FINAL)
+ Q_PROPERTY(QQmlComponent *left READ left WRITE setLeft NOTIFY leftChanged FINAL)
+ Q_PROPERTY(QQmlComponent *behind READ behind WRITE setBehind NOTIFY behindChanged FINAL)
+ Q_PROPERTY(QQmlComponent *right READ right WRITE setRight NOTIFY rightChanged FINAL)
+ Q_PROPERTY(QQuickItem *leftItem READ leftItem NOTIFY leftItemChanged FINAL)
+ Q_PROPERTY(QQuickItem *behindItem READ behindItem NOTIFY behindItemChanged FINAL)
+ Q_PROPERTY(QQuickItem *rightItem READ rightItem NOTIFY rightItemChanged FINAL)
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) // REVISION(2, 2)
+ Q_PROPERTY(QQuickTransition *transition READ transition WRITE setTransition NOTIFY transitionChanged FINAL) // REVISION(2, 2)
+ QML_ANONYMOUS
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSwipe(QQuickSwipeDelegate *control);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ bool isComplete() const;
+ void setComplete(bool complete);
+
+ QQmlComponent *left() const;
+ void setLeft(QQmlComponent *left);
+
+ QQmlComponent *behind() const;
+ void setBehind(QQmlComponent *behind);
+
+ QQmlComponent *right() const;
+ void setRight(QQmlComponent *right);
+
+ QQuickItem *leftItem() const;
+ void setLeftItem(QQuickItem *item);
+
+ QQuickItem *behindItem() const;
+ void setBehindItem(QQuickItem *item);
+
+ QQuickItem *rightItem() const;
+ void setRightItem(QQuickItem *item);
+
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) Q_INVOKABLE void close();
+
+ // 2.2 (Qt 5.9)
+ bool isEnabled() const;
+ void setEnabled(bool enabled);
+
+ QQuickTransition *transition() const;
+ void setTransition(QQuickTransition *transition);
+
+ Q_REVISION(2, 2) Q_INVOKABLE void open(QQuickSwipeDelegate::Side side);
+
+Q_SIGNALS:
+ void positionChanged();
+ void completeChanged();
+ void leftChanged();
+ void behindChanged();
+ void rightChanged();
+ void leftItemChanged();
+ void behindItemChanged();
+ void rightItemChanged();
+ // 2.1 (Qt 5.8)
+ /*Q_REVISION(2, 1)*/ void completed();
+ // 2.2 (Qt 5.9)
+ /*Q_REVISION(2, 2)*/ void opened();
+ /*Q_REVISION(2, 2)*/ void closed();
+ /*Q_REVISION(2, 2)*/ void enabledChanged();
+ /*Q_REVISION(2, 2)*/ void transitionChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSwipe)
+ Q_DECLARE_PRIVATE(QQuickSwipe)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSWIPE_P_H
diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp
new file mode 100644
index 0000000000..242dbc6654
--- /dev/null
+++ b/src/quicktemplates2/qquickswipedelegate.cpp
@@ -0,0 +1,1527 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickswipedelegate_p.h"
+#include "qquickswipedelegate_p_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickitemdelegate_p_p.h"
+#include "qquickvelocitycalculator_p_p.h"
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/private/qeventpoint_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickanimation_p.h>
+#include <QtQuick/private/qquicktransition_p.h>
+#include <QtQuick/private/qquicktransitionmanager_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SwipeDelegate
+ \inherits ItemDelegate
+//! \instantiates QQuickSwipeDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-delegates
+ \brief Swipable item delegate.
+
+ SwipeDelegate presents a view item that can be swiped left or right to
+ expose more options or information. It is used as a delegate in views such
+ as \l ListView.
+
+ In the following example, SwipeDelegate is used in a \l ListView to allow
+ items to be removed from it by swiping to the left:
+
+ \snippet qtquickcontrols2-swipedelegate.qml 1
+
+ SwipeDelegate inherits its API from \l ItemDelegate, which is inherited
+ from AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton
+ API.
+
+ Information regarding the progress of a swipe, as well as the components
+ that should be shown upon swiping, are both available through the
+ \l {SwipeDelegate::}{swipe} grouped property object. For example,
+ \c swipe.position holds the position of the
+ swipe within the range \c -1.0 to \c 1.0. The \c swipe.left
+ property determines which item will be displayed when the control is swiped
+ to the right, and vice versa for \c swipe.right. The positioning of these
+ components is left to applications to decide. For example, without specifying
+ any position for \c swipe.left or \c swipe.right, the following will
+ occur:
+
+ \image qtquickcontrols2-swipedelegate.gif
+
+ If \c swipe.left and \c swipe.right are anchored to the left and
+ right of the \l {Control::}{background} item (respectively), they'll behave like this:
+
+ \image qtquickcontrols2-swipedelegate-leading-trailing.gif
+
+ When using \c swipe.left and \c swipe.right, the control cannot be
+ swiped past the left and right edges. To achieve this type of "wrapping"
+ behavior, set \c swipe.behind instead. This will result in the same
+ item being shown regardless of which direction the control is swiped. For
+ example, in the image below, we set \c swipe.behind and then swipe the
+ control repeatedly in both directions:
+
+ \image qtquickcontrols2-swipedelegate-behind.gif
+
+ \sa {Customizing SwipeDelegate}, {Delegate Controls}, {Qt Quick Controls 2 - Swipe to Remove}{Swipe to Remove Example}
+*/
+
+namespace {
+ typedef QQuickSwipeDelegateAttached Attached;
+
+ Attached *attachedObject(QQuickItem *item) {
+ return qobject_cast<Attached*>(qmlAttachedPropertiesObject<QQuickSwipeDelegate>(item, false));
+ }
+
+ enum PositionAnimation {
+ DontAnimatePosition,
+ AnimatePosition
+ };
+}
+
+class QQuickSwipeTransitionManager : public QQuickTransitionManager
+{
+public:
+ QQuickSwipeTransitionManager(QQuickSwipe *swipe);
+
+ void transition(QQuickTransition *transition, qreal position);
+
+protected:
+ void finished() override;
+
+private:
+ QQuickSwipe *m_swipe = nullptr;
+};
+
+class QQuickSwipePrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipe)
+
+public:
+ QQuickSwipePrivate(QQuickSwipeDelegate *control) : control(control) { }
+
+ static QQuickSwipePrivate *get(QQuickSwipe *swipe);
+
+ QQuickItem *createDelegateItem(QQmlComponent *component);
+ QQuickItem *showRelevantItemForPosition(qreal position);
+ QQuickItem *createRelevantItemForDistance(qreal distance);
+ void reposition(PositionAnimation animationPolicy);
+ void createLeftItem();
+ void createBehindItem();
+ void createRightItem();
+ void createAndShowLeftItem();
+ void createAndShowBehindItem();
+ void createAndShowRightItem();
+
+ void warnAboutMixingDelegates();
+ void warnAboutSettingDelegatesWhileVisible();
+
+ bool hasDelegates() const;
+
+ bool isTransitioning() const;
+ void beginTransition(qreal position);
+ void finishTransition();
+
+ QQuickSwipeDelegate *control = nullptr;
+ // Same range as position, but is set before press events so that we can
+ // keep track of which direction the user must swipe when using left and right delegates.
+ qreal positionBeforePress = 0;
+ qreal position = 0;
+ // A "less strict" version of complete that is true if complete was true
+ // before the last press event.
+ bool wasComplete = false;
+ bool complete = false;
+ bool enabled = true;
+ bool waitForTransition = false;
+ QQuickVelocityCalculator velocityCalculator;
+ QQmlComponent *left = nullptr;
+ QQmlComponent *behind = nullptr;
+ QQmlComponent *right = nullptr;
+ QQuickItem *leftItem = nullptr;
+ QQuickItem *behindItem = nullptr;
+ QQuickItem *rightItem = nullptr;
+ QQuickTransition *transition = nullptr;
+ QScopedPointer<QQuickSwipeTransitionManager> transitionManager;
+};
+
+QQuickSwipeTransitionManager::QQuickSwipeTransitionManager(QQuickSwipe *swipe)
+ : m_swipe(swipe)
+{
+}
+
+void QQuickSwipeTransitionManager::transition(QQuickTransition *transition, qreal position)
+{
+ qmlExecuteDeferred(transition);
+
+ QQmlProperty defaultTarget(m_swipe, QLatin1String("position"));
+ QQmlListProperty<QQuickAbstractAnimation> animations = transition->animations();
+ const int count = animations.count(&animations);
+ for (int i = 0; i < count; ++i) {
+ QQuickAbstractAnimation *anim = animations.at(&animations, i);
+ anim->setDefaultTarget(defaultTarget);
+ }
+
+ QList<QQuickStateAction> actions;
+ actions << QQuickStateAction(m_swipe, QLatin1String("position"), position);
+ QQuickTransitionManager::transition(actions, transition, m_swipe);
+}
+
+void QQuickSwipeTransitionManager::finished()
+{
+ QQuickSwipePrivate::get(m_swipe)->finishTransition();
+}
+
+QQuickSwipePrivate *QQuickSwipePrivate::get(QQuickSwipe *swipe)
+{
+ return swipe->d_func();
+}
+
+QQuickItem *QQuickSwipePrivate::createDelegateItem(QQmlComponent *component)
+{
+ // If we don't use the correct context, it won't be possible to refer to
+ // the control's id from within the delegates.
+ QQmlContext *creationContext = component->creationContext();
+ // The component might not have been created in QML, in which case
+ // the creation context will be null and we have to create it ourselves.
+ if (!creationContext)
+ creationContext = qmlContext(control);
+ QQmlContext *context = new QQmlContext(creationContext, control);
+ context->setContextObject(control);
+ QQuickItem *item = qobject_cast<QQuickItem*>(component->beginCreate(context));
+ if (item) {
+ item->setParentItem(control);
+ component->completeCreate();
+ }
+ return item;
+}
+
+QQuickItem *QQuickSwipePrivate::showRelevantItemForPosition(qreal position)
+{
+ if (qFuzzyIsNull(position))
+ return nullptr;
+
+ if (behind) {
+ createAndShowBehindItem();
+ return behindItem;
+ }
+
+ if (right && position < 0.0) {
+ createAndShowRightItem();
+ return rightItem;
+ }
+
+ if (left && position > 0.0) {
+ createAndShowLeftItem();
+ return leftItem;
+ }
+
+ return nullptr;
+}
+
+QQuickItem *QQuickSwipePrivate::createRelevantItemForDistance(qreal distance)
+{
+ if (qFuzzyIsNull(distance))
+ return nullptr;
+
+ if (behind) {
+ createBehindItem();
+ return behindItem;
+ }
+
+ // a) If the position before the press was 0.0, we know that *any* movement
+ // whose distance is negative will result in the right item being shown and
+ // vice versa.
+ // b) Once the control has been exposed (that is, swiped to the left or right,
+ // and hence the position is either -1.0 or 1.0), we must use the width of the
+ // relevant item to determine if the distance is larger than that item,
+ // in order to know whether or not to display it.
+ // c) If the control has been exposed, and the swipe is larger than the width
+ // of the relevant item from which the swipe started from, we must show the
+ // item on the other side (if any).
+
+ if (right) {
+ if ((distance < 0.0 && positionBeforePress == 0.0) /* a) */
+ || (rightItem && positionBeforePress == -1.0 && distance < rightItem->width()) /* b) */
+ || (leftItem && positionBeforePress == 1.0 && qAbs(distance) > leftItem->width())) /* c) */ {
+ createRightItem();
+ return rightItem;
+ }
+ }
+
+ if (left) {
+ if ((distance > 0.0 && positionBeforePress == 0.0) /* a) */
+ || (leftItem && positionBeforePress == 1.0 && qAbs(distance) < leftItem->width()) /* b) */
+ || (rightItem && positionBeforePress == -1.0 && qAbs(distance) > rightItem->width())) /* c) */ {
+ createLeftItem();
+ return leftItem;
+ }
+ }
+
+ return nullptr;
+}
+
+void QQuickSwipePrivate::reposition(PositionAnimation animationPolicy)
+{
+ QQuickItem *relevantItem = showRelevantItemForPosition(position);
+ const qreal relevantWidth = relevantItem ? relevantItem->width() : 0.0;
+ const qreal contentItemX = position * relevantWidth + control->leftPadding();
+
+ // "Behavior on x" relies on the property system to know when it should update,
+ // so we can prevent it from animating by setting the x position directly.
+ if (animationPolicy == AnimatePosition) {
+ if (QQuickItem *contentItem = control->contentItem())
+ contentItem->setProperty("x", contentItemX);
+ if (QQuickItem *background = control->background())
+ background->setProperty("x", position * relevantWidth);
+ } else {
+ if (QQuickItem *contentItem = control->contentItem())
+ contentItem->setX(contentItemX);
+ if (QQuickItem *background = control->background())
+ background->setX(position * relevantWidth);
+ }
+}
+
+void QQuickSwipePrivate::createLeftItem()
+{
+ if (!leftItem) {
+ Q_Q(QQuickSwipe);
+ q->setLeftItem(createDelegateItem(left));
+ if (!leftItem)
+ qmlWarning(control) << "Failed to create left item:" << left->errors();
+ }
+}
+
+void QQuickSwipePrivate::createBehindItem()
+{
+ if (!behindItem) {
+ Q_Q(QQuickSwipe);
+ q->setBehindItem(createDelegateItem(behind));
+ if (!behindItem)
+ qmlWarning(control) << "Failed to create behind item:" << behind->errors();
+ }
+}
+
+void QQuickSwipePrivate::createRightItem()
+{
+ if (!rightItem) {
+ Q_Q(QQuickSwipe);
+ q->setRightItem(createDelegateItem(right));
+ if (!rightItem)
+ qmlWarning(control) << "Failed to create right item:" << right->errors();
+ }
+}
+
+void QQuickSwipePrivate::createAndShowLeftItem()
+{
+ createLeftItem();
+
+ if (leftItem)
+ leftItem->setVisible(true);
+
+ if (rightItem)
+ rightItem->setVisible(false);
+}
+
+void QQuickSwipePrivate::createAndShowBehindItem()
+{
+ createBehindItem();
+
+ if (behindItem)
+ behindItem->setVisible(true);
+}
+
+void QQuickSwipePrivate::createAndShowRightItem()
+{
+ createRightItem();
+
+ // This item may have already existed but was hidden.
+ if (rightItem)
+ rightItem->setVisible(true);
+
+ // The left item isn't visible when the right item is visible, so save rendering effort by hiding it.
+ if (leftItem)
+ leftItem->setVisible(false);
+}
+
+void QQuickSwipePrivate::warnAboutMixingDelegates()
+{
+ qmlWarning(control) << "cannot set both behind and left/right properties";
+}
+
+void QQuickSwipePrivate::warnAboutSettingDelegatesWhileVisible()
+{
+ qmlWarning(control) << "left/right/behind properties may only be set when swipe.position is 0";
+}
+
+bool QQuickSwipePrivate::hasDelegates() const
+{
+ return left || right || behind;
+}
+
+bool QQuickSwipePrivate::isTransitioning() const
+{
+ return transitionManager && transitionManager->isRunning();
+}
+
+void QQuickSwipePrivate::beginTransition(qreal newPosition)
+{
+ if (waitForTransition)
+ return;
+ Q_Q(QQuickSwipe);
+ if (!transition) {
+ q->setPosition(newPosition);
+ finishTransition();
+ return;
+ }
+
+ if (!transitionManager)
+ transitionManager.reset(new QQuickSwipeTransitionManager(q));
+
+ transitionManager->transition(transition, newPosition);
+}
+
+void QQuickSwipePrivate::finishTransition()
+{
+ Q_Q(QQuickSwipe);
+ waitForTransition = false;
+ q->setComplete(qFuzzyCompare(qAbs(position), qreal(1.0)));
+ if (complete) {
+ emit q->opened();
+ } else {
+ if (qFuzzyIsNull(position))
+ wasComplete = false;
+ emit q->closed();
+ }
+}
+
+QQuickSwipe::QQuickSwipe(QQuickSwipeDelegate *control)
+ : QObject(*(new QQuickSwipePrivate(control)))
+{
+}
+
+QQmlComponent *QQuickSwipe::left() const
+{
+ Q_D(const QQuickSwipe);
+ return d->left;
+}
+
+void QQuickSwipe::setLeft(QQmlComponent *left)
+{
+ Q_D(QQuickSwipe);
+ if (left == d->left)
+ return;
+
+ if (d->behind) {
+ d->warnAboutMixingDelegates();
+ return;
+ }
+
+ if (!qFuzzyIsNull(d->position)) {
+ d->warnAboutSettingDelegatesWhileVisible();
+ return;
+ }
+
+ d->left = left;
+
+ if (!d->left) {
+ delete d->leftItem;
+ d->leftItem = nullptr;
+ }
+
+ d->control->setFiltersChildMouseEvents(d->hasDelegates());
+
+ emit leftChanged();
+}
+
+QQmlComponent *QQuickSwipe::behind() const
+{
+ Q_D(const QQuickSwipe);
+ return d->behind;
+}
+
+void QQuickSwipe::setBehind(QQmlComponent *behind)
+{
+ Q_D(QQuickSwipe);
+ if (behind == d->behind)
+ return;
+
+ if (d->left || d->right) {
+ d->warnAboutMixingDelegates();
+ return;
+ }
+
+ if (!qFuzzyIsNull(d->position)) {
+ d->warnAboutSettingDelegatesWhileVisible();
+ return;
+ }
+
+ d->behind = behind;
+
+ if (!d->behind) {
+ delete d->behindItem;
+ d->behindItem = nullptr;
+ }
+
+ d->control->setFiltersChildMouseEvents(d->hasDelegates());
+
+ emit behindChanged();
+}
+
+QQmlComponent *QQuickSwipe::right() const
+{
+ Q_D(const QQuickSwipe);
+ return d->right;
+}
+
+void QQuickSwipe::setRight(QQmlComponent *right)
+{
+ Q_D(QQuickSwipe);
+ if (right == d->right)
+ return;
+
+ if (d->behind) {
+ d->warnAboutMixingDelegates();
+ return;
+ }
+
+ if (!qFuzzyIsNull(d->position)) {
+ d->warnAboutSettingDelegatesWhileVisible();
+ return;
+ }
+
+ d->right = right;
+
+ if (!d->right) {
+ delete d->rightItem;
+ d->rightItem = nullptr;
+ }
+
+ d->control->setFiltersChildMouseEvents(d->hasDelegates());
+
+ emit rightChanged();
+}
+
+QQuickItem *QQuickSwipe::leftItem() const
+{
+ Q_D(const QQuickSwipe);
+ return d->leftItem;
+}
+
+void QQuickSwipe::setLeftItem(QQuickItem *item)
+{
+ Q_D(QQuickSwipe);
+ if (item == d->leftItem)
+ return;
+
+ delete d->leftItem;
+ d->leftItem = item;
+
+ if (d->leftItem) {
+ d->leftItem->setParentItem(d->control);
+
+ if (qFuzzyIsNull(d->leftItem->z()))
+ d->leftItem->setZ(-2);
+ }
+
+ emit leftItemChanged();
+}
+
+QQuickItem *QQuickSwipe::behindItem() const
+{
+ Q_D(const QQuickSwipe);
+ return d->behindItem;
+}
+
+void QQuickSwipe::setBehindItem(QQuickItem *item)
+{
+ Q_D(QQuickSwipe);
+ if (item == d->behindItem)
+ return;
+
+ delete d->behindItem;
+ d->behindItem = item;
+
+ if (d->behindItem) {
+ d->behindItem->setParentItem(d->control);
+
+ if (qFuzzyIsNull(d->behindItem->z()))
+ d->behindItem->setZ(-2);
+ }
+
+ emit behindItemChanged();
+}
+
+QQuickItem *QQuickSwipe::rightItem() const
+{
+ Q_D(const QQuickSwipe);
+ return d->rightItem;
+}
+
+void QQuickSwipe::setRightItem(QQuickItem *item)
+{
+ Q_D(QQuickSwipe);
+ if (item == d->rightItem)
+ return;
+
+ delete d->rightItem;
+ d->rightItem = item;
+
+ if (d->rightItem) {
+ d->rightItem->setParentItem(d->control);
+
+ if (qFuzzyIsNull(d->rightItem->z()))
+ d->rightItem->setZ(-2);
+ }
+
+ emit rightItemChanged();
+}
+
+qreal QQuickSwipe::position() const
+{
+ Q_D(const QQuickSwipe);
+ return d->position;
+}
+
+void QQuickSwipe::setPosition(qreal position)
+{
+ Q_D(QQuickSwipe);
+ const qreal adjustedPosition = qBound<qreal>(-1.0, position, 1.0);
+ if (adjustedPosition == d->position)
+ return;
+
+ d->position = adjustedPosition;
+ d->reposition(AnimatePosition);
+ emit positionChanged();
+}
+
+bool QQuickSwipe::isComplete() const
+{
+ Q_D(const QQuickSwipe);
+ return d->complete;
+}
+
+void QQuickSwipe::setComplete(bool complete)
+{
+ Q_D(QQuickSwipe);
+ if (complete == d->complete)
+ return;
+
+ d->complete = complete;
+ emit completeChanged();
+ if (d->complete)
+ emit completed();
+}
+
+bool QQuickSwipe::isEnabled() const
+{
+ Q_D(const QQuickSwipe);
+ return d->enabled;
+}
+
+void QQuickSwipe::setEnabled(bool enabled)
+{
+ Q_D(QQuickSwipe);
+ if (enabled == d->enabled)
+ return;
+
+ d->enabled = enabled;
+ emit enabledChanged();
+}
+
+QQuickTransition *QQuickSwipe::transition() const
+{
+ Q_D(const QQuickSwipe);
+ return d->transition;
+}
+
+void QQuickSwipe::setTransition(QQuickTransition *transition)
+{
+ Q_D(QQuickSwipe);
+ if (transition == d->transition)
+ return;
+
+ d->transition = transition;
+ emit transitionChanged();
+}
+
+void QQuickSwipe::open(QQuickSwipeDelegate::Side side)
+{
+ Q_D(QQuickSwipe);
+ if (qFuzzyCompare(qAbs(d->position), qreal(1.0)))
+ return;
+
+ if ((side != QQuickSwipeDelegate::Left && side != QQuickSwipeDelegate::Right)
+ || (!d->left && !d->behind && side == QQuickSwipeDelegate::Left)
+ || (!d->right && !d->behind && side == QQuickSwipeDelegate::Right))
+ return;
+
+ d->beginTransition(side);
+ d->wasComplete = true;
+ d->velocityCalculator.reset();
+ d->positionBeforePress = d->position;
+}
+
+void QQuickSwipe::close()
+{
+ Q_D(QQuickSwipe);
+ if (qFuzzyIsNull(d->position))
+ return;
+
+ if (d->control->isPressed()) {
+ // We don't support closing when we're pressed; release() or clicked() should be used instead.
+ return;
+ }
+
+ d->beginTransition(0.0);
+ d->waitForTransition = true;
+ d->wasComplete = false;
+ d->positionBeforePress = 0.0;
+ d->velocityCalculator.reset();
+}
+
+QQuickSwipeDelegatePrivate::QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control)
+ : swipe(control)
+{
+}
+
+void QQuickSwipeDelegatePrivate::resizeBackground()
+{
+ if (!background)
+ return;
+
+ resizingBackground = true;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ const bool extraAllocated = extra.isAllocated();
+ // Don't check for or set the x here since it will just be overwritten by reposition().
+ if (((!p->widthValid() || !extraAllocated || !extra->hasBackgroundWidth))
+ || (extraAllocated && (extra->hasLeftInset || extra->hasRightInset))) {
+ background->setWidth(width - getLeftInset() - getRightInset());
+ }
+ if (((!p->heightValid() || !extraAllocated || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
+ || (extraAllocated && (extra->hasTopInset || extra->hasBottomInset))) {
+ background->setY(getTopInset());
+ background->setHeight(height - getTopInset() - getBottomInset());
+ }
+
+ resizingBackground = false;
+}
+
+bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event)
+{
+ Q_Q(QQuickSwipeDelegate);
+ const auto posInItem = item->mapToItem(q, event->position().toPoint());
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
+ // If the position is 0, we want to handle events ourselves - we don't want child items to steal them.
+ // This code will only get called when a child item has been created;
+ // events will go through the regular channels (mousePressEvent()) until then.
+ if (qFuzzyIsNull(swipePrivate->position)) {
+ q->mousePressEvent(event);
+ // The press point could be incorrect if the press happened over a child item,
+ // so we correct it after calling the base class' mousePressEvent(), rather
+ // than having to duplicate its code just so we can set the pressPoint.
+ setPressPoint(posInItem);
+ return true;
+ }
+
+ // If the delegate is swiped open, send the event to the exposed item,
+ // in case it's an interactive child (like a Button).
+ if (swipePrivate->complete)
+ forwardMouseEvent(event, item, posInItem);
+
+ // The position is non-zero, this press could be either for a delegate or the control itself
+ // (the control can be clicked to e.g. close the swipe). Either way, we must begin measuring
+ // mouse movement in case it turns into a swipe, in which case we grab the mouse.
+ swipePrivate->positionBeforePress = swipePrivate->position;
+ swipePrivate->velocityCalculator.startMeasuring(event->position().toPoint(), event->timestamp());
+ setPressPoint(item->mapToItem(q, event->position().toPoint()));
+
+ // When a delegate or any of its children uses the attached properties and signals,
+ // it declares that it wants mouse events.
+ const bool delivered = attachedObjectsSetPressed(item, event->scenePosition(), true);
+ if (delivered)
+ event->accept();
+ return delivered;
+}
+
+bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event)
+{
+ Q_Q(QQuickSwipeDelegate);
+
+ if (holdTimer > 0) {
+ if (QLineF(pressPoint, event->position()).length() > QGuiApplication::styleHints()->startDragDistance())
+ stopPressAndHold();
+ }
+
+ // The delegate can still be pressed when swipe.enabled is false,
+ // but the mouse moving shouldn't have any effect on swipe.position.
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
+ if (!swipePrivate->enabled)
+ return false;
+
+ // Protect against division by zero.
+ if (width == 0)
+ return false;
+
+ // Don't bother reacting to events if we don't have any delegates.
+ if (!swipePrivate->left && !swipePrivate->right && !swipePrivate->behind)
+ return false;
+
+ // Don't handle move events for the control if it wasn't pressed.
+ if (item == q && !pressed)
+ return false;
+
+ const QPointF mappedEventPos = item->mapToItem(q, event->position().toPoint());
+ const qreal distance = (mappedEventPos - pressPoint).x();
+ if (!q->keepMouseGrab()) {
+ // Taken from QQuickDrawerPrivate::grabMouse; see comments there.
+ int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
+ const bool overThreshold = QQuickWindowPrivate::dragOverThreshold(distance, Qt::XAxis, event, threshold);
+ if (window && overThreshold) {
+ QQuickItem *grabber = q->window()->mouseGrabberItem();
+ if (!grabber || !grabber->keepMouseGrab()) {
+ q->grabMouse();
+ q->setKeepMouseGrab(true);
+ q->setPressed(true);
+ swipe.setComplete(false);
+
+ attachedObjectsSetPressed(item, event->scenePosition(), false, true);
+ }
+ }
+ }
+
+ if (q->keepMouseGrab()) {
+ // Ensure we don't try to calculate a position when the user tried to drag
+ // to the left when the left item is already exposed, and vice versa.
+ // The code below assumes that the drag is valid, so if we don't have this check,
+ // the wrong items are visible and the swiping wraps.
+ if (swipePrivate->behind
+ || ((swipePrivate->left || swipePrivate->right)
+ && (qFuzzyIsNull(swipePrivate->positionBeforePress)
+ || (swipePrivate->positionBeforePress == -1.0 && distance >= 0.0)
+ || (swipePrivate->positionBeforePress == 1.0 && distance <= 0.0)))) {
+
+ // We must instantiate the items here so that we can calculate the
+ // position against the width of the relevant item.
+ QQuickItem *relevantItem = swipePrivate->createRelevantItemForDistance(distance);
+ // If there isn't any relevant item, the user may have swiped back to the 0 position,
+ // or they swiped back to a position that is equal to positionBeforePress.
+ const qreal normalizedDistance = relevantItem ? distance / relevantItem->width() : 0.0;
+ qreal position = 0;
+
+ // If the control was exposed before the drag begun, the distance should be inverted.
+ // For example, if the control had been swiped to the right, the position would be 1.0.
+ // If the control was then swiped to the left by a distance of -20 pixels, the normalized
+ // distance might be -0.2, for example, which cannot be used as the position; the swipe
+ // started from the right, so we account for that by adding the position.
+ if (qFuzzyIsNull(normalizedDistance)) {
+ // There are two cases when the normalizedDistance can be 0,
+ // and we must distinguish between them:
+ //
+ // a) The swipe returns to the position that it was at before the press event.
+ // In this case, the distance will be 0.
+ // There would have been many position changes in the meantime, so we can't just
+ // ignore the move event; we have to set position to what it was before the press.
+ //
+ // b) If the position was at, 1.0, for example, and the control was then swiped
+ // to the left by the exact width of the left item, there won't be any relevant item
+ // (because the swipe's position would be at 0.0). In turn, the normalizedDistance
+ // would be 0 (because of the lack of a relevant item), but the distance will be non-zero.
+ position = qFuzzyIsNull(distance) ? swipePrivate->positionBeforePress : 0;
+ } else if (!swipePrivate->wasComplete) {
+ position = normalizedDistance;
+ } else {
+ position = distance > 0 ? normalizedDistance - 1.0 : normalizedDistance + 1.0;
+ }
+
+ if (swipePrivate->isTransitioning())
+ swipePrivate->transitionManager->cancel();
+ swipe.setPosition(position);
+ }
+ } else {
+ // The swipe wasn't initiated.
+ if (event->position().toPoint().y() < 0 || event->position().toPoint().y() > height) {
+ // The mouse went outside the vertical bounds of the control, so
+ // we should no longer consider it pressed.
+ q->setPressed(false);
+ }
+ }
+
+ event->accept();
+
+ return q->keepMouseGrab();
+}
+
+static const qreal exposeVelocityThreshold = 300.0;
+
+bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event)
+{
+ Q_Q(QQuickSwipeDelegate);
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
+ swipePrivate->velocityCalculator.stopMeasuring(event->position().toPoint(), event->timestamp());
+
+ const bool hadGrabbedMouse = q->keepMouseGrab();
+ q->setKeepMouseGrab(false);
+
+ // QQuickSwipe::close() doesn't allow closing while pressed, but now we're releasing.
+ // So set the pressed state false if this release _could_ result in closing, so that check can be bypassed.
+ if (!qIsNull(swipePrivate->position))
+ q->setPressed(false);
+
+ // Animations for the background and contentItem delegates are typically
+ // only enabled when !control.down, so that the animations aren't running
+ // when the user is swiping. To ensure that the animations are enabled
+ // *before* the positions of these delegates change (via the swipe.setPosition() calls below),
+ // we must cancel the press. QQuickAbstractButton::mouseUngrabEvent() does this
+ // for us, but by then it's too late.
+ if (hadGrabbedMouse) {
+ // TODO: this is copied from QQuickAbstractButton::mouseUngrabEvent().
+ // Eventually it should be moved into a private helper so that we don't have to duplicate it.
+ q->setPressed(false);
+ stopPressRepeat();
+ stopPressAndHold();
+ emit q->canceled();
+ }
+
+ // Inform the given item that the mouse is released, in case it's an interactive child.
+ if (item != q && (swipePrivate->complete || swipePrivate->wasComplete))
+ forwardMouseEvent(event, item, item->mapFromScene(event->scenePosition()));
+
+ // The control can be exposed by either swiping past the halfway mark, or swiping fast enough.
+ const qreal swipeVelocity = swipePrivate->velocityCalculator.velocity().x();
+ if (swipePrivate->position > 0.5 ||
+ (swipePrivate->position > 0.0 && swipeVelocity > exposeVelocityThreshold)) {
+ swipePrivate->beginTransition(1.0);
+ swipePrivate->wasComplete = true;
+ } else if (swipePrivate->position < -0.5 ||
+ (swipePrivate->position < 0.0 && swipeVelocity < -exposeVelocityThreshold)) {
+ swipePrivate->beginTransition(-1.0);
+ swipePrivate->wasComplete = true;
+ } else if (!swipePrivate->isTransitioning()) {
+ // The position is either <= 0.5 or >= -0.5, so the position should go to 0.
+ // However, if the position was already 0 or close to it, we were just clicked,
+ // and we don't need to start a transition.
+ if (!qFuzzyIsNull(swipePrivate->position))
+ swipePrivate->beginTransition(0.0);
+ swipePrivate->wasComplete = false;
+ }
+
+ // Inform any QQuickSwipeDelegateAttached objects that the mouse is released.
+ attachedObjectsSetPressed(item, event->scenePosition(), false);
+
+ // Only consume child events if we had grabbed the mouse.
+ return hadGrabbedMouse;
+}
+
+/*! \internal
+ Send a localized copy of \a event with \a localPos to the \a destination item.
+*/
+void QQuickSwipeDelegatePrivate::forwardMouseEvent(QMouseEvent *event, QQuickItem *destination, QPointF localPos)
+{
+ Q_Q(QQuickSwipeDelegate);
+ QMutableSinglePointEvent localizedEvent(*event);
+ localizedEvent.mutablePoint().setPosition(localPos);
+ QGuiApplication::sendEvent(destination, &localizedEvent);
+ q->setPressed(!localizedEvent.isAccepted());
+}
+
+/*! \internal
+ For each QQuickSwipeDelegateAttached object on children of \a item:
+ if \a scenePos is in the attachee (the item to which it's attached), then
+ set its \a pressed state. Unless \a cancel is \c true, when the state
+ transitions from pressed to released, also emit \l QQuickSwipeDelegateAttached::clicked().
+ Returns \c true if at least one relevant attached object was found.
+*/
+bool QQuickSwipeDelegatePrivate::attachedObjectsSetPressed(QQuickItem *item, QPointF scenePos, bool pressed, bool cancel)
+{
+ bool found = false;
+ QVarLengthArray<QQuickItem *, 16> itemAndChildren;
+ itemAndChildren.append(item);
+ for (int i = 0; i < itemAndChildren.count(); ++i) {
+ auto item = itemAndChildren.at(i);
+ auto posInItem = item->mapFromScene(scenePos);
+ if (item->contains(posInItem)) {
+ if (Attached *attached = attachedObject(item)) {
+ const bool wasPressed = attached->isPressed();
+ attached->setPressed(pressed);
+ if (wasPressed && !pressed && !cancel)
+ emit attached->clicked();
+ found = true;
+ }
+ }
+ for (auto child : item->childItems())
+ itemAndChildren.append(child);
+ }
+ return found;
+}
+
+static void warnIfHorizontallyAnchored(QQuickItem *item, const QString &itemName)
+{
+ if (!item)
+ return;
+
+ QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
+ if (anchors && (anchors->fill() || anchors->centerIn() || anchors->left().item || anchors->right().item)
+ && !item->property("_q_QQuickSwipeDelegate_warned").toBool()) {
+ qmlWarning(item) << QString::fromLatin1("SwipeDelegate: cannot use horizontal anchors with %1; unable to layout the item.").arg(itemName);
+ item->setProperty("_q_QQuickSwipeDelegate_warned", true);
+ }
+}
+
+void QQuickSwipeDelegatePrivate::resizeContent()
+{
+ warnIfHorizontallyAnchored(background, QStringLiteral("background"));
+ warnIfHorizontallyAnchored(contentItem, QStringLiteral("contentItem"));
+
+ // If the background and contentItem are repositioned due to a swipe,
+ // we don't want to call QQuickControlPrivate's implementation of this function,
+ // as it repositions the contentItem to be visible.
+ // However, we still want to position the contentItem vertically
+ // and resize it (in case the control was resized while open).
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
+ if (!swipePrivate->complete) {
+ QQuickItemDelegatePrivate::resizeContent();
+ } else if (contentItem) {
+ Q_Q(QQuickSwipeDelegate);
+ contentItem->setY(q->topPadding());
+ contentItem->setWidth(q->availableWidth());
+ contentItem->setHeight(q->availableHeight());
+ }
+}
+
+QPalette QQuickSwipeDelegatePrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::ListView);
+}
+
+QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickSwipeDelegatePrivate(this)), parent)
+{
+ // QQuickSwipeDelegate still depends on synthesized mouse events
+ setAcceptTouchEvents(false);
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlmethod void QtQuick.Controls::SwipeDelegate::swipe.open(enumeration side)
+
+ This method sets the \c position of the swipe so that it opens
+ from the specified \a side.
+
+ Available values:
+ \value SwipeDelegate.Left The \c position is set to \c 1, which makes the swipe open
+ from the left. Either \c swipe.left or \c swipe.behind must
+ have been specified; otherwise the call is ignored.
+ \value SwipeDelegate.Right The \c position is set to \c -1, which makes the swipe open
+ from the right. Either \c swipe.right or \c swipe.behind must
+ have been specified; otherwise the call is ignored.
+
+ Any animations defined for the \l {Item::}{x} position of \l {Control::}{contentItem}
+ and \l {Control::}{background} will be triggered.
+
+ \sa swipe, swipe.close()
+*/
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlmethod void QtQuick.Controls::SwipeDelegate::swipe.close()
+
+ This method sets the \c position of the swipe to \c 0. Any animations
+ defined for the \l {Item::}{x} position of \l {Control::}{contentItem}
+ and \l {Control::}{background} will be triggered.
+
+ \sa swipe, swipe.open()
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal void QtQuick.Controls::SwipeDelegate::swipe.opened()
+
+ This signal is emitted when the delegate has been swiped open
+ and the transition has finished.
+
+ It is useful for performing some action upon completion of a swipe.
+ For example, it can be used to remove the delegate from the list
+ that it is in.
+
+ \sa swipe, swipe.closed()
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlsignal void QtQuick.Controls::SwipeDelegate::swipe.closed()
+
+ This signal is emitted when the delegate has been swiped to closed
+ and the transition has finished.
+
+ It is useful for performing some action upon cancellation of a swipe.
+ For example, it can be used to cancel the removal of the delegate from
+ the list that it is in.
+
+ \sa swipe, swipe.opened()
+*/
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlsignal void QtQuick.Controls::SwipeDelegate::swipe.completed()
+
+ This signal is emitted when \c swipe.complete becomes \c true.
+
+ It is useful for performing some action upon completion of a swipe.
+ For example, it can be used to remove the delegate from the list
+ that it is in.
+
+ \sa swipe
+*/
+
+/*!
+ \qmlproperty real QtQuick.Controls::SwipeDelegate::swipe.position
+ \qmlproperty bool QtQuick.Controls::SwipeDelegate::swipe.complete
+ \qmlproperty bool QtQuick.Controls::SwipeDelegate::swipe.enabled
+ \qmlproperty Component QtQuick.Controls::SwipeDelegate::swipe.left
+ \qmlproperty Component QtQuick.Controls::SwipeDelegate::swipe.behind
+ \qmlproperty Component QtQuick.Controls::SwipeDelegate::swipe.right
+ \qmlproperty Item QtQuick.Controls::SwipeDelegate::swipe.leftItem
+ \qmlproperty Item QtQuick.Controls::SwipeDelegate::swipe.behindItem
+ \qmlproperty Item QtQuick.Controls::SwipeDelegate::swipe.rightItem
+ \qmlproperty Transition QtQuick.Controls::SwipeDelegate::swipe.transition
+
+ \table
+ \header
+ \li Name
+ \li Description
+ \row
+ \li position
+ \li This read-only property holds the position of the swipe relative to either
+ side of the control. When this value reaches either
+ \c -1.0 (left side) or \c 1.0 (right side) and the mouse button is
+ released, \c complete will be \c true.
+ \row
+ \li complete
+ \li This read-only property holds whether the control is fully exposed after
+ having been swiped to the left or right.
+
+ When complete is \c true, any interactive items declared in \c left,
+ \c right, or \c behind will receive mouse events.
+ \row
+ \li enabled
+ \li This property determines whether or not the control can be swiped.
+
+ This property was added in QtQuick.Controls 2.2.
+ \row
+ \li left
+ \li This property holds the left delegate.
+
+ The left delegate sits behind both \l {Control::}{contentItem} and
+ \l {Control::}{background}. When the SwipeDelegate is swiped to the right,
+ this item will be gradually revealed.
+
+ \include qquickswipedelegate-interaction.qdocinc
+ \row
+ \li behind
+ \li This property holds the delegate that is shown when the
+ SwipeDelegate is swiped to both the left and right.
+
+ As with the \c left and \c right delegates, it sits behind both
+ \l {Control::}{contentItem} and \l {Control::}{background}. However, a
+ SwipeDelegate whose \c behind has been set can be continuously swiped
+ from either side, and will always show the same item.
+
+ \include qquickswipedelegate-interaction.qdocinc
+ \row
+ \li right
+ \li This property holds the right delegate.
+
+ The right delegate sits behind both \l {Control::}{contentItem} and
+ \l {Control::}{background}. When the SwipeDelegate is swiped to the left,
+ this item will be gradually revealed.
+
+ \include qquickswipedelegate-interaction.qdocinc
+ \row
+ \li leftItem
+ \li This read-only property holds the item instantiated from the \c left component.
+
+ If \c left has not been set, or the position hasn't changed since
+ creation of the SwipeDelegate, this property will be \c null.
+ \row
+ \li behindItem
+ \li This read-only property holds the item instantiated from the \c behind component.
+
+ If \c behind has not been set, or the position hasn't changed since
+ creation of the SwipeDelegate, this property will be \c null.
+ \row
+ \li rightItem
+ \li This read-only property holds the item instantiated from the \c right component.
+
+ If \c right has not been set, or the position hasn't changed since
+ creation of the SwipeDelegate, this property will be \c null.
+ \row
+ \li transition
+ \li This property holds the transition that is applied when a swipe is released,
+ or \l swipe.open() or \l swipe.close() is called.
+
+ \snippet qtquickcontrols2-swipedelegate-transition.qml 1
+
+ This property was added in Qt Quick Controls 2.2.
+ \endtable
+
+ \sa {Control::}{contentItem}, {Control::}{background}, swipe.open(), swipe.close()
+*/
+QQuickSwipe *QQuickSwipeDelegate::swipe() const
+{
+ Q_D(const QQuickSwipeDelegate);
+ return const_cast<QQuickSwipe*>(&d->swipe);
+}
+
+QQuickSwipeDelegateAttached *QQuickSwipeDelegate::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSwipeDelegateAttached(object);
+}
+
+static bool isChildOrGrandchildOf(QQuickItem *child, QQuickItem *item)
+{
+ return item && (child == item || item->isAncestorOf(child));
+}
+
+bool QQuickSwipeDelegate::childMouseEventFilter(QQuickItem *child, QEvent *event)
+{
+ Q_D(QQuickSwipeDelegate);
+ // The contentItem is, by default, usually a non-interactive item like Text, and
+ // the same applies to the background. This means that simply stacking the left/right/behind
+ // items before these items won't allow us to get mouse events when the control is not currently exposed
+ // but has been previously. Therefore, we instead call setFiltersChildMouseEvents(true) in the constructor
+ // and filter out child events only when the child is the left/right/behind item.
+ const QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
+ if (!isChildOrGrandchildOf(child, swipePrivate->leftItem) && !isChildOrGrandchildOf(child, swipePrivate->behindItem)
+ && !isChildOrGrandchildOf(child, swipePrivate->rightItem)) {
+ return false;
+ }
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress: {
+ return d->handleMousePressEvent(child, static_cast<QMouseEvent *>(event));
+ } case QEvent::MouseMove: {
+ return d->handleMouseMoveEvent(child, static_cast<QMouseEvent *>(event));
+ } case QEvent::MouseButtonRelease: {
+ // Make sure that the control gets release events if it has created child
+ // items that are stealing events from it.
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ QQuickItemDelegate::mouseReleaseEvent(mouseEvent);
+ return d->handleMouseReleaseEvent(child, mouseEvent);
+ } case QEvent::UngrabMouse: {
+ // If the mouse was pressed over e.g. rightItem and then dragged down,
+ // the ListView would eventually grab the mouse, at which point we must
+ // clear the pressed flag so that it doesn't stay pressed after the release.
+ Attached *attached = attachedObject(child);
+ if (attached)
+ attached->setPressed(false);
+ return false;
+ } default:
+ return false;
+ }
+}
+
+// We only override this to set positionBeforePress;
+// otherwise, it's the same as the base class implementation.
+void QQuickSwipeDelegate::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwipeDelegate);
+ QQuickItemDelegate::mousePressEvent(event);
+
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
+ if (!swipePrivate->enabled)
+ return;
+
+ swipePrivate->positionBeforePress = swipePrivate->position;
+ swipePrivate->velocityCalculator.startMeasuring(event->position().toPoint(), event->timestamp());
+
+ if (swipePrivate->complete) {
+ auto item = d->swipe.rightItem();
+ if (item && item->contains(item->mapFromScene(event->scenePosition()))) {
+ d->pressedItem = item;
+ d->handleMousePressEvent(item, event);
+ } else {
+ item = d->swipe.leftItem();
+ if (item && item->contains(item->mapFromScene(event->scenePosition()))) {
+ d->pressedItem = item;
+ d->handleMousePressEvent(item, event);
+ }
+ }
+ }
+}
+
+void QQuickSwipeDelegate::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwipeDelegate);
+ if (filtersChildMouseEvents())
+ d->handleMouseMoveEvent(this, event);
+ else
+ QQuickItemDelegate::mouseMoveEvent(event);
+ if (d->pressedItem)
+ d->handleMouseMoveEvent(d->pressedItem, event);
+}
+
+void QQuickSwipeDelegate::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwipeDelegate);
+ if (!filtersChildMouseEvents() || !d->handleMouseReleaseEvent(this, event))
+ QQuickItemDelegate::mouseReleaseEvent(event);
+
+ if (d->pressedItem) {
+ if (d->pressedItem->acceptedMouseButtons())
+ d->handleMouseReleaseEvent(d->pressedItem, event);
+ d->pressedItem = nullptr;
+ }
+}
+
+void QQuickSwipeDelegate::mouseUngrabEvent()
+{
+ Q_D(QQuickSwipeDelegate);
+ setPressed(false);
+
+ auto item = d->swipe.rightItem();
+ if (item) {
+ if (auto control = qmlobject_cast<QQuickControl *>(item))
+ QQuickControlPrivate::get(control)->handleUngrab();
+ Attached *attached = attachedObject(item);
+ if (attached)
+ attached->setPressed(false);
+ } else {
+ item = d->swipe.leftItem();
+ if (item) {
+ if (auto control = qmlobject_cast<QQuickControl *>(item))
+ QQuickControlPrivate::get(control)->handleUngrab();
+ Attached *attached = attachedObject(item);
+ if (attached)
+ attached->setPressed(false);
+ }
+ }
+
+ d->pressedItem = nullptr;
+}
+
+void QQuickSwipeDelegate::touchEvent(QTouchEvent *event)
+{
+ // Don't allow QQuickControl accept the touch event, because QQuickSwipeDelegate
+ // is still based on synthesized mouse events
+ event->ignore();
+}
+
+void QQuickSwipeDelegate::componentComplete()
+{
+ Q_D(QQuickSwipeDelegate);
+ QQuickItemDelegate::componentComplete();
+ QQuickSwipePrivate::get(&d->swipe)->reposition(DontAnimatePosition);
+}
+
+void QQuickSwipeDelegate::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickSwipeDelegate);
+ QQuickControl::geometryChange(newGeometry, oldGeometry);
+
+ if (isComponentComplete() && !qFuzzyCompare(newGeometry.width(), oldGeometry.width())) {
+ QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&d->swipe);
+ swipePrivate->reposition(DontAnimatePosition);
+ }
+}
+
+QFont QQuickSwipeDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ListView);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickSwipeDelegate::accessibleRole() const
+{
+ return QAccessible::ListItem;
+}
+#endif
+
+class QQuickSwipeDelegateAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeDelegateAttached)
+
+public:
+ // True when left/right/behind is non-interactive and is pressed.
+ bool pressed = false;
+};
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlattachedsignal QtQuick.Controls::SwipeDelegate::clicked()
+
+ This signal can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to react to
+ clicks. Items can only be clicked when \c swipe.complete is \c true.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c clicked() signal instead.
+
+ To respond to clicks on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{clicked()} signal.
+
+ \note See the documentation for \l pressed for information on
+ how to use the event-related properties correctly.
+
+ \sa pressed
+*/
+
+QQuickSwipeDelegateAttached::QQuickSwipeDelegateAttached(QObject *object)
+ : QObject(*(new QQuickSwipeDelegateAttachedPrivate), object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (item) {
+ // This allows us to be notified when an otherwise non-interactive item
+ // is pressed and clicked. The alternative is much more more complex:
+ // iterating through children that contain the event pos and finding
+ // the first one with an attached object.
+ item->setAcceptedMouseButtons(Qt::AllButtons);
+ } else {
+ qWarning() << "Attached properties of SwipeDelegate must be accessed through an Item";
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlattachedproperty bool QtQuick.Controls::SwipeDelegate::pressed
+ \readonly
+
+ This property can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to detect if it
+ is pressed. Items can only be pressed when \c swipe.complete is \c true.
+
+ For example:
+
+ \code
+ swipe.right: Label {
+ anchors.right: parent.right
+ height: parent.height
+ text: "Action"
+ color: "white"
+ padding: 12
+ background: Rectangle {
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ \endcode
+
+ It is possible to have multiple items which individually receive mouse and
+ touch events. For example, to have two actions in the \c swipe.right item,
+ use the following code:
+
+ \code
+ swipe.right: Row {
+ anchors.right: parent.right
+ height: parent.height
+
+ Label {
+ id: moveLabel
+ text: qsTr("Move")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Moving...")
+
+ background: Rectangle {
+ color: moveLabel.SwipeDelegate.pressed ? Qt.darker("#ffbf47", 1.1) : "#ffbf47"
+ }
+ }
+ Label {
+ id: deleteLabel
+ text: qsTr("Delete")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Deleting...")
+
+ background: Rectangle {
+ color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ }
+ \endcode
+
+ Note how the \c color assignment in each \l {Control::}{background} item
+ qualifies the attached property with the \c id of the label. This
+ is important; using the attached properties on an item causes that item
+ to accept events. Suppose we had left out the \c id in the previous example:
+
+ \code
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ \endcode
+
+ The \l Rectangle background item is a child of the label, so it naturally
+ receives events before it. In practice, this means that the background
+ color will change, but the \c onClicked handler in the label will never
+ get called.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c pressed property instead.
+
+ For presses on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{pressed} property.
+
+ \sa clicked()
+*/
+bool QQuickSwipeDelegateAttached::isPressed() const
+{
+ Q_D(const QQuickSwipeDelegateAttached);
+ return d->pressed;
+}
+
+void QQuickSwipeDelegateAttached::setPressed(bool pressed)
+{
+ Q_D(QQuickSwipeDelegateAttached);
+ if (pressed == d->pressed)
+ return;
+
+ d->pressed = pressed;
+ emit pressedChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickswipe_p.cpp"
+#include "moc_qquickswipedelegate_p.cpp"
diff --git a/src/quicktemplates2/qquickswipedelegate_p.h b/src/quicktemplates2/qquickswipedelegate_p.h
new file mode 100644
index 0000000000..cbf5f4b483
--- /dev/null
+++ b/src/quicktemplates2/qquickswipedelegate_p.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWIPEDELEGATE_P_H
+#define QQUICKSWIPEDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSwipe;
+class QQuickSwipeDelegatePrivate;
+class QQuickSwipeDelegateAttached;
+class QQuickSwipeDelegateAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegate : public QQuickItemDelegate
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickSwipe *swipe READ swipe CONSTANT FINAL)
+ QML_NAMED_ELEMENT(SwipeDelegate)
+ QML_ATTACHED(QQuickSwipeDelegateAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSwipeDelegate(QQuickItem *parent = nullptr);
+
+ QQuickSwipe *swipe() const;
+
+ enum Side { Left = 1, Right = -1 };
+ Q_ENUM(Side)
+
+ static QQuickSwipeDelegateAttached *qmlAttachedProperties(QObject *object);
+
+protected:
+ bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseUngrabEvent() override;
+ void touchEvent(QTouchEvent *event) override;
+
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeDelegate)
+ Q_DECLARE_PRIVATE(QQuickSwipeDelegate)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegateAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+
+public:
+ explicit QQuickSwipeDelegateAttached(QObject *object = nullptr);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+Q_SIGNALS:
+ void pressedChanged();
+ void clicked();
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeDelegateAttached)
+ Q_DECLARE_PRIVATE(QQuickSwipeDelegateAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSwipeDelegate)
+QML_DECLARE_TYPEINFO(QQuickSwipeDelegate, QML_HAS_ATTACHED_PROPERTIES)
+Q_DECLARE_METATYPE(QQuickSwipeDelegate::Side)
+
+#endif // QQUICKSWIPEDELEGATE_P_H
diff --git a/src/quicktemplates2/qquickswipedelegate_p_p.h b/src/quicktemplates2/qquickswipedelegate_p_p.h
new file mode 100644
index 0000000000..46e47eb677
--- /dev/null
+++ b/src/quicktemplates2/qquickswipedelegate_p_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWIPEDELEGATE_P_P_H
+#define QQUICKSWIPEDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p_p.h>
+#include <QtQuickTemplates2/private/qquickswipe_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSwipeDelegate;
+
+class QQuickSwipeDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeDelegate)
+
+public:
+ QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *control);
+
+ bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event);
+ bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event);
+ bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event);
+ void forwardMouseEvent(QMouseEvent *event, QQuickItem *destination, QPointF localPos);
+ bool attachedObjectsSetPressed(QQuickItem *item, QPointF scenePos, bool pressed, bool cancel = false);
+
+ void resizeContent() override;
+ void resizeBackground() override;
+
+ QPalette defaultPalette() const override;
+
+ QQuickSwipe swipe;
+ QQuickItem *pressedItem = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKSWIPEDELEGATE_P_P_H
diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp
new file mode 100644
index 0000000000..3277ba524f
--- /dev/null
+++ b/src/quicktemplates2/qquickswipeview.cpp
@@ -0,0 +1,478 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickswipeview_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SwipeView
+ \inherits Container
+//! \instantiates QQuickSwipeView
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-navigation
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Enables the user to navigate pages by swiping sideways.
+
+ SwipeView provides a swipe-based navigation model.
+
+ \image qtquickcontrols2-swipeview.gif
+
+ SwipeView is populated with a set of pages. One page is visible at a time.
+ The user can navigate between the pages by swiping sideways. Notice that
+ SwipeView itself is entirely non-visual. It is recommended to combine it
+ with PageIndicator, to give the user a visual clue that there are multiple
+ pages.
+
+ \snippet qtquickcontrols2-swipeview-indicator.qml 1
+
+ As shown above, SwipeView is typically populated with a static set of
+ pages that are defined inline as children of the view. It is also possible
+ to \l {Container::addItem()}{add}, \l {Container::insertItem()}{insert},
+ \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
+ pages dynamically at run time.
+
+ \include container-currentindex.qdocinc {file} {SwipeView} {TabBar}
+
+ It is generally not advisable to add excessive amounts of pages to a
+ SwipeView. However, when the amount of pages grows larger, or individual
+ pages are relatively complex, it may be desirable to free up resources by
+ unloading pages that are outside the immediate reach of the user.
+ The following example presents how to use \l Loader to keep a maximum of
+ three pages simultaneously instantiated.
+
+ \code
+ SwipeView {
+ Repeater {
+ model: 6
+ Loader {
+ active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem
+ sourceComponent: Text {
+ text: index
+ Component.onCompleted: console.log("created:", index)
+ Component.onDestruction: console.log("destroyed:", index)
+ }
+ }
+ }
+ }
+ \endcode
+
+ \note SwipeView takes over the geometry management of items added to the
+ view. Using anchors on the items is not supported, and any \c width
+ or \c height assignment will be overridden by the view. Notice that
+ this only applies to the root of the item. Specifying width and height,
+ or using anchors for its children works as expected.
+
+ \sa TabBar, PageIndicator, {Customizing SwipeView}, {Navigation Controls}, {Container Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+class QQuickSwipeViewPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeView)
+
+public:
+ void resizeItem(QQuickItem *item);
+ void resizeItems();
+
+ static QQuickSwipeViewPrivate *get(QQuickSwipeView *view);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ bool interactive = true;
+ Qt::Orientation orientation = Qt::Horizontal;
+};
+
+class QQuickSwipeViewAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeViewAttached)
+
+public:
+ static QQuickSwipeViewAttachedPrivate *get(QQuickSwipeViewAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void update(QQuickSwipeView *newView, int newIndex);
+ void updateCurrentIndex();
+ void setCurrentIndex(int i);
+
+ QQuickSwipeView *swipeView = nullptr;
+ int index = -1;
+ int currentIndex = -1;
+};
+
+void QQuickSwipeViewPrivate::resizeItems()
+{
+ Q_Q(QQuickSwipeView);
+ const int count = q->count();
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = itemAt(i);
+ if (item) {
+ QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors;
+ // TODO: expose QQuickAnchorLine so we can test for other conflicting anchors
+ if (anchors && (anchors->fill() || anchors->centerIn()) && !item->property("_q_QQuickSwipeView_warned").toBool()) {
+ qmlWarning(item) << "SwipeView has detected conflicting anchors. Unable to layout the item.";
+ item->setProperty("_q_QQuickSwipeView_warned", true);
+ }
+ if (orientation == Qt::Horizontal)
+ item->setPosition({i * (contentItem->width() + spacing), 0});
+ else
+ item->setPosition({0, i * (contentItem->height() + spacing)});
+ item->setSize(QSizeF(contentItem->width(), contentItem->height()));
+ }
+ }
+}
+
+QQuickSwipeViewPrivate *QQuickSwipeViewPrivate::get(QQuickSwipeView *view)
+{
+ return view->d_func();
+}
+
+void QQuickSwipeViewPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickSwipeView);
+ QQuickContainerPrivate::itemImplicitWidthChanged(item);
+ if (item == q->currentItem())
+ updateImplicitContentWidth();
+}
+
+void QQuickSwipeViewPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickSwipeView);
+ QQuickContainerPrivate::itemImplicitHeightChanged(item);
+ if (item == q->currentItem())
+ updateImplicitContentHeight();
+}
+
+qreal QQuickSwipeViewPrivate::getContentWidth() const
+{
+ Q_Q(const QQuickSwipeView);
+ QQuickItem *currentItem = q->currentItem();
+ return currentItem ? currentItem->implicitWidth() : 0;
+}
+
+qreal QQuickSwipeViewPrivate::getContentHeight() const
+{
+ Q_Q(const QQuickSwipeView);
+ QQuickItem *currentItem = q->currentItem();
+ return currentItem ? currentItem->implicitHeight() : 0;
+}
+
+QQuickSwipeView::QQuickSwipeView(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickSwipeViewPrivate), parent)
+{
+ Q_D(QQuickSwipeView);
+ d->changeTypes |= QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+ setFlag(ItemIsFocusScope);
+ setActiveFocusOnTab(true);
+ QObjectPrivate::connect(this, &QQuickContainer::currentItemChanged, d, &QQuickControlPrivate::updateImplicitContentSize);
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::SwipeView::interactive
+
+ This property describes whether the user can interact with the SwipeView.
+ The user cannot swipe a view that is not interactive.
+
+ The default value is \c true.
+*/
+bool QQuickSwipeView::isInteractive() const
+{
+ Q_D(const QQuickSwipeView);
+ return d->interactive;
+}
+
+void QQuickSwipeView::setInteractive(bool interactive)
+{
+ Q_D(QQuickSwipeView);
+ if (d->interactive == interactive)
+ return;
+
+ d->interactive = interactive;
+ emit interactiveChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty enumeration QtQuick.Controls::SwipeView::orientation
+
+ This property holds the orientation.
+
+ Possible values:
+ \value Qt.Horizontal Horizontal (default)
+ \value Qt.Vertical Vertical
+
+ \sa horizontal, vertical
+*/
+Qt::Orientation QQuickSwipeView::orientation() const
+{
+ Q_D(const QQuickSwipeView);
+ return d->orientation;
+}
+
+void QQuickSwipeView::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickSwipeView);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ if (isComponentComplete())
+ d->resizeItems();
+ emit orientationChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::SwipeView::horizontal
+ \readonly
+
+ This property holds whether the swipe view is horizontal.
+
+ \sa orientation
+*/
+bool QQuickSwipeView::isHorizontal() const
+{
+ Q_D(const QQuickSwipeView);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \qmlproperty bool QtQuick.Controls::SwipeView::vertical
+ \readonly
+
+ This property holds whether the swipe view is vertical.
+
+ \sa orientation
+*/
+bool QQuickSwipeView::isVertical() const
+{
+ Q_D(const QQuickSwipeView);
+ return d->orientation == Qt::Vertical;
+}
+
+QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSwipeViewAttached(object);
+}
+
+void QQuickSwipeView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickSwipeView);
+ QQuickContainer::geometryChange(newGeometry, oldGeometry);
+ d->resizeItems();
+}
+
+void QQuickSwipeView::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickSwipeView);
+ if (isComponentComplete())
+ item->setSize(QSizeF(d->contentItem->width(), d->contentItem->height()));
+ QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
+ if (attached)
+ QQuickSwipeViewAttachedPrivate::get(attached)->update(this, index);
+}
+
+void QQuickSwipeView::itemMoved(int index, QQuickItem *item)
+{
+ QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
+ if (attached)
+ QQuickSwipeViewAttachedPrivate::get(attached)->update(this, index);
+}
+
+void QQuickSwipeView::itemRemoved(int, QQuickItem *item)
+{
+ QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item));
+ if (attached)
+ QQuickSwipeViewAttachedPrivate::get(attached)->update(nullptr, -1);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickSwipeView::accessibleRole() const
+{
+ return QAccessible::PageTabList;
+}
+#endif
+
+/*!
+ \qmlattachedproperty int QtQuick.Controls::SwipeView::index
+ \readonly
+
+ This attached property holds the index of each child item in the SwipeView.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SwipeView::isCurrentItem
+ \readonly
+
+ This attached property is \c true if this child is the current item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SwipeView::isNextItem
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \readonly
+
+ This attached property is \c true if this child is the next item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SwipeView::isPreviousItem
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \readonly
+
+ This attached property is \c true if this child is the previous item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
+ \qmlattachedproperty SwipeView QtQuick.Controls::SwipeView::view
+ \readonly
+
+ This attached property holds the view that manages this child item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+void QQuickSwipeViewAttachedPrivate::updateCurrentIndex()
+{
+ setCurrentIndex(swipeView ? swipeView->currentIndex() : -1);
+}
+
+void QQuickSwipeViewAttachedPrivate::setCurrentIndex(int i)
+{
+ if (i == currentIndex)
+ return;
+
+ Q_Q(QQuickSwipeViewAttached);
+ const bool wasCurrent = q->isCurrentItem();
+ const bool wasNext = q->isNextItem();
+ const bool wasPrevious = q->isPreviousItem();
+
+ currentIndex = i;
+ if (wasCurrent != q->isCurrentItem())
+ emit q->isCurrentItemChanged();
+ if (wasNext != q->isNextItem())
+ emit q->isNextItemChanged();
+ if (wasPrevious != q->isPreviousItem())
+ emit q->isPreviousItemChanged();
+}
+
+void QQuickSwipeViewAttachedPrivate::update(QQuickSwipeView *newView, int newIndex)
+{
+ Q_Q(QQuickSwipeViewAttached);
+ int oldIndex = index;
+ QQuickSwipeView *oldView = swipeView;
+
+ index = newIndex;
+ swipeView = newView;
+
+ if (oldView != newView) {
+ if (oldView) {
+ disconnect(oldView, &QQuickSwipeView::currentIndexChanged,
+ this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
+ }
+ if (newView) {
+ connect(newView, &QQuickSwipeView::currentIndexChanged,
+ this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
+ }
+ emit q->viewChanged();
+ }
+ if (oldIndex != newIndex)
+ emit q->indexChanged();
+
+ updateCurrentIndex();
+}
+
+QQuickSwipeViewAttached::QQuickSwipeViewAttached(QObject *parent)
+ : QObject(*(new QQuickSwipeViewAttachedPrivate), parent)
+{
+ if (!qobject_cast<QQuickItem *>(parent))
+ qmlWarning(parent) << "SwipeView: attached properties must be accessed from within a child item";
+}
+
+int QQuickSwipeViewAttached::index() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index;
+}
+
+bool QQuickSwipeViewAttached::isCurrentItem() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex;
+}
+
+QQuickSwipeView *QQuickSwipeViewAttached::view() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->swipeView;
+}
+
+bool QQuickSwipeViewAttached::isNextItem() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex + 1;
+}
+
+bool QQuickSwipeViewAttached::isPreviousItem() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex - 1;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickswipeview_p.cpp"
diff --git a/src/quicktemplates2/qquickswipeview_p.h b/src/quicktemplates2/qquickswipeview_p.h
new file mode 100644
index 0000000000..8a09a37e22
--- /dev/null
+++ b/src/quicktemplates2/qquickswipeview_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWIPEVIEW_P_H
+#define QQUICKSWIPEVIEW_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSwipeViewAttached;
+class QQuickSwipeViewPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeView : public QQuickContainer
+{
+ Q_OBJECT
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged FINAL REVISION(2, 1))
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL REVISION(2, 2))
+ // 2.3 (Qt 5.10)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION(2, 3))
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION(2, 3))
+ QML_NAMED_ELEMENT(SwipeView)
+ QML_ATTACHED(QQuickSwipeViewAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSwipeView(QQuickItem *parent = nullptr);
+
+ static QQuickSwipeViewAttached *qmlAttachedProperties(QObject *object);
+
+ // 2.1 (Qt 5.8)
+ bool isInteractive() const;
+ void setInteractive(bool interactive);
+
+ // 2.2 (Qt 5.9)
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ // 2.3 (Qt 5.10)
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+Q_SIGNALS:
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void interactiveChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void orientationChanged();
+
+protected:
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemMoved(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeView)
+ Q_DECLARE_PRIVATE(QQuickSwipeView)
+};
+
+class QQuickSwipeViewAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeViewAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged FINAL)
+ Q_PROPERTY(QQuickSwipeView *view READ view NOTIFY viewChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool isNextItem READ isNextItem NOTIFY isNextItemChanged FINAL REVISION(2, 1))
+ Q_PROPERTY(bool isPreviousItem READ isPreviousItem NOTIFY isPreviousItemChanged FINAL REVISION(2, 1))
+
+public:
+ explicit QQuickSwipeViewAttached(QObject *parent = nullptr);
+
+ int index() const;
+ bool isCurrentItem() const;
+ QQuickSwipeView *view() const;
+
+ // 2.1 (Qt 5.8)
+ bool isNextItem() const;
+ bool isPreviousItem() const;
+
+Q_SIGNALS:
+ void indexChanged();
+ void isCurrentItemChanged();
+ void viewChanged();
+ // 2.1 (Qt 5.8)
+ /*Q_REVISION(2, 1)*/ void isNextItemChanged();
+ /*Q_REVISION(2, 1)*/ void isPreviousItemChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeViewAttached)
+ Q_DECLARE_PRIVATE(QQuickSwipeViewAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSwipeView)
+QML_DECLARE_TYPEINFO(QQuickSwipeView, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKSWIPEVIEW_P_H
diff --git a/src/quicktemplates2/qquickswitch.cpp b/src/quicktemplates2/qquickswitch.cpp
new file mode 100644
index 0000000000..9d4ac4530b
--- /dev/null
+++ b/src/quicktemplates2/qquickswitch.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickswitch_p.h"
+#include "qquickabstractbutton_p_p.h"
+
+#include <QtGui/qstylehints.h>
+#include <QtGui/qguiapplication.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Switch
+ \inherits AbstractButton
+//! \instantiates QQuickSwitch
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Switch button that can be toggled on or off.
+
+ \image qtquickcontrols2-switch.gif
+
+ Switch is an option button that can be dragged or toggled on (checked) or
+ off (unchecked). Switches are typically used to select between two states.
+ For larger sets of options, such as those in a list, consider using
+ \l SwitchDelegate instead.
+
+ Switch inherits its API from \l AbstractButton. For instance, the state
+ of the switch can be set with the \l {AbstractButton::}{checked} property.
+
+ \code
+ ColumnLayout {
+ Switch {
+ text: qsTr("Wi-Fi")
+ }
+ Switch {
+ text: qsTr("Bluetooth")
+ }
+ }
+ \endcode
+
+ \sa {Customizing Switch}, {Button Controls}
+*/
+
+class QQuickSwitchPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwitch)
+
+public:
+ qreal positionAt(const QPointF &point) const;
+
+ bool canDrag(const QPointF &movePoint) const;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::Switch); }
+
+ qreal position = 0;
+};
+
+qreal QQuickSwitchPrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickSwitch);
+ qreal pos = 0.0;
+ if (indicator)
+ pos = indicator->mapFromItem(q, point).x() / indicator->width();
+ if (q->isMirrored())
+ return 1.0 - pos;
+ return pos;
+}
+
+bool QQuickSwitchPrivate::canDrag(const QPointF &movePoint) const
+{
+ // don't start dragging the handle unless the initial press was at the indicator,
+ // or the drag has reached the indicator area. this prevents unnatural jumps when
+ // dragging far outside the indicator.
+ const qreal pressPos = positionAt(pressPoint);
+ const qreal movePos = positionAt(movePoint);
+ return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0);
+}
+
+void QQuickSwitchPrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickSwitch);
+ QQuickAbstractButtonPrivate::handleMove(point);
+ if (q->keepMouseGrab() || q->keepTouchGrab())
+ q->setPosition(positionAt(point));
+}
+
+void QQuickSwitchPrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickSwitch);
+ QQuickAbstractButtonPrivate::handleRelease(point);
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+}
+
+QQuickSwitch::QQuickSwitch(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickSwitchPrivate), parent)
+{
+ Q_D(QQuickSwitch);
+ d->keepPressed = true;
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Switch::position
+ \readonly
+
+ \input includes/qquickswitch.qdocinc position
+*/
+qreal QQuickSwitch::position() const
+{
+ Q_D(const QQuickSwitch);
+ return d->position;
+}
+
+void QQuickSwitch::setPosition(qreal position)
+{
+ Q_D(QQuickSwitch);
+ position = qBound<qreal>(0.0, position, 1.0);
+ if (qFuzzyCompare(d->position, position))
+ return;
+
+ d->position = position;
+ emit positionChanged();
+ emit visualPositionChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::Switch::visualPosition
+ \readonly
+
+ \input includes/qquickswitch.qdocinc visualPosition
+*/
+qreal QQuickSwitch::visualPosition() const
+{
+ Q_D(const QQuickSwitch);
+ if (isMirrored())
+ return 1.0 - d->position;
+ return d->position;
+}
+
+void QQuickSwitch::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwitch);
+ if (!keepMouseGrab()) {
+ const QPointF movePoint = event->position();
+ if (d->canDrag(movePoint))
+ setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event));
+ }
+ QQuickAbstractButton::mouseMoveEvent(event);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickSwitch::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickSwitch);
+ if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) {
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (point.id() != d->touchId || point.state() != QEventPoint::Updated)
+ continue;
+ if (d->canDrag(point.position()))
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(), Qt::XAxis, &point));
+ }
+ }
+ QQuickAbstractButton::touchEvent(event);
+}
+#endif
+
+void QQuickSwitch::mirrorChange()
+{
+ QQuickAbstractButton::mirrorChange();
+ emit visualPositionChanged();
+}
+
+void QQuickSwitch::nextCheckState()
+{
+ Q_D(QQuickSwitch);
+ if (keepMouseGrab() || keepTouchGrab()) {
+ d->toggle(d->position > 0.5);
+ // the checked state might not change => force a position update to
+ // avoid that the handle is left somewhere in the middle (QTBUG-57944)
+ setPosition(d->checked ? 1.0 : 0.0);
+ } else {
+ QQuickAbstractButton::nextCheckState();
+ }
+}
+
+void QQuickSwitch::buttonChange(ButtonChange change)
+{
+ Q_D(QQuickSwitch);
+ if (change == ButtonCheckedChange)
+ setPosition(d->checked ? 1.0 : 0.0);
+ else
+ QQuickAbstractButton::buttonChange(change);
+}
+
+QFont QQuickSwitch::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Switch);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickswitch_p.cpp"
diff --git a/src/quicktemplates2/qquickswitch_p.h b/src/quicktemplates2/qquickswitch_p.h
new file mode 100644
index 0000000000..b3df029923
--- /dev/null
+++ b/src/quicktemplates2/qquickswitch_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWITCH_P_H
+#define QQUICKSWITCH_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSwitchPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwitch : public QQuickAbstractButton
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
+ QML_NAMED_ELEMENT(Switch)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSwitch(QQuickItem *parent = nullptr);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ qreal visualPosition() const;
+
+Q_SIGNALS:
+ void positionChanged();
+ void visualPositionChanged();
+
+protected:
+ void mouseMoveEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+ void mirrorChange() override;
+
+ void nextCheckState() override;
+ void buttonChange(ButtonChange change) override;
+
+ QFont defaultFont() const override;
+
+private:
+ Q_DISABLE_COPY(QQuickSwitch)
+ Q_DECLARE_PRIVATE(QQuickSwitch)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSwitch)
+
+#endif // QQUICKSWITCH_P_H
diff --git a/src/quicktemplates2/qquickswitchdelegate.cpp b/src/quicktemplates2/qquickswitchdelegate.cpp
new file mode 100644
index 0000000000..4b9e3e79f4
--- /dev/null
+++ b/src/quicktemplates2/qquickswitchdelegate.cpp
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickswitchdelegate_p.h"
+
+#include "qquickitemdelegate_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype SwitchDelegate
+ \inherits ItemDelegate
+//! \instantiates QQuickSwitchDelegate
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-delegates
+ \brief Item delegate with a switch indicator that can be toggled on or off.
+
+ \image qtquickcontrols2-switchdelegate.gif
+
+ SwitchDelegate presents an item delegate that can be toggled on (checked) or
+ off (unchecked). Switch delegates are typically used to select one or more
+ options from a set of options. For smaller sets of options, or for options
+ that need to be uniquely identifiable, consider using \l Switch instead.
+
+ SwitchDelegate inherits its API from \l ItemDelegate, which is inherited
+ from \l AbstractButton. For instance, you can set \l {AbstractButton::text}{text},
+ and react to \l {AbstractButton::clicked}{clicks} using the \l AbstractButton
+ API. The state of the switch delegate can be set with the
+ \l {AbstractButton::}{checked} property.
+
+ \code
+ ListView {
+ model: ["Option 1", "Option 2", "Option 3"]
+ delegate: SwitchDelegate {
+ text: modelData
+ }
+ }
+ \endcode
+
+ \sa {Customizing SwitchDelegate}, {Delegate Controls}
+*/
+
+class QQuickSwitchDelegatePrivate : public QQuickItemDelegatePrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwitchDelegate)
+
+public:
+ qreal positionAt(const QPointF &point) const;
+
+ bool canDrag(const QPointF &movePoint) const;
+ void handleMove(const QPointF &point) override;
+ void handleRelease(const QPointF &point) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ListView); }
+
+ qreal position = 0;
+};
+
+qreal QQuickSwitchDelegatePrivate::positionAt(const QPointF &point) const
+{
+ Q_Q(const QQuickSwitchDelegate);
+ qreal pos = 0.0;
+ if (indicator)
+ pos = indicator->mapFromItem(q, point).x() / indicator->width();
+ if (q->isMirrored())
+ return 1.0 - pos;
+ return pos;
+}
+
+bool QQuickSwitchDelegatePrivate::canDrag(const QPointF &movePoint) const
+{
+ // don't start dragging the handle unless the initial press was at the indicator,
+ // or the drag has reached the indicator area. this prevents unnatural jumps when
+ // dragging far outside the indicator.
+ const qreal pressPos = positionAt(pressPoint);
+ const qreal movePos = positionAt(movePoint);
+ return (pressPos >= 0.0 && pressPos <= 1.0) || (movePos >= 0.0 && movePos <= 1.0);
+}
+
+void QQuickSwitchDelegatePrivate::handleMove(const QPointF &point)
+{
+ Q_Q(QQuickSwitchDelegate);
+ QQuickItemDelegatePrivate::handleMove(point);
+ if (q->keepMouseGrab() || q->keepTouchGrab())
+ q->setPosition(positionAt(point));
+}
+
+void QQuickSwitchDelegatePrivate::handleRelease(const QPointF &point)
+{
+ Q_Q(QQuickSwitchDelegate);
+ QQuickItemDelegatePrivate::handleRelease(point);
+ q->setKeepMouseGrab(false);
+ q->setKeepTouchGrab(false);
+}
+
+QQuickSwitchDelegate::QQuickSwitchDelegate(QQuickItem *parent)
+ : QQuickItemDelegate(*(new QQuickSwitchDelegatePrivate), parent)
+{
+ Q_D(QQuickSwitchDelegate);
+ d->keepPressed = true;
+ setCheckable(true);
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::SwitchDelegate::position
+ \readonly
+
+ \input includes/qquickswitch.qdocinc position
+*/
+qreal QQuickSwitchDelegate::position() const
+{
+ Q_D(const QQuickSwitchDelegate);
+ return d->position;
+}
+
+void QQuickSwitchDelegate::setPosition(qreal position)
+{
+ Q_D(QQuickSwitchDelegate);
+ position = qBound<qreal>(0.0, position, 1.0);
+ if (qFuzzyCompare(d->position, position))
+ return;
+
+ d->position = position;
+ emit positionChanged();
+ emit visualPositionChanged();
+}
+
+/*!
+ \qmlproperty real QtQuick.Controls::SwitchDelegate::visualPosition
+ \readonly
+
+ \input includes/qquickswitch.qdocinc visualPosition
+*/
+qreal QQuickSwitchDelegate::visualPosition() const
+{
+ Q_D(const QQuickSwitchDelegate);
+ if (isMirrored())
+ return 1.0 - d->position;
+ return d->position;
+}
+
+void QQuickSwitchDelegate::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (!keepMouseGrab()) {
+ const QPointF movePoint = event->position();
+ if (d->canDrag(movePoint))
+ setKeepMouseGrab(QQuickWindowPrivate::dragOverThreshold(movePoint.x() - d->pressPoint.x(), Qt::XAxis, event));
+ }
+ QQuickItemDelegate::mouseMoveEvent(event);
+}
+
+#if QT_CONFIG(quicktemplates2_multitouch)
+void QQuickSwitchDelegate::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (!keepTouchGrab() && event->type() == QEvent::TouchUpdate) {
+ for (const QTouchEvent::TouchPoint &point : event->points()) {
+ if (point.id() != d->touchId || point.state() != QEventPoint::Updated)
+ continue;
+ if (d->canDrag(point.position()))
+ setKeepTouchGrab(QQuickWindowPrivate::dragOverThreshold(point.position().x() - d->pressPoint.x(), Qt::XAxis, &point));
+ }
+ }
+ QQuickItemDelegate::touchEvent(event);
+}
+#endif
+
+QFont QQuickSwitchDelegate::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ListView);
+}
+
+void QQuickSwitchDelegate::mirrorChange()
+{
+ QQuickItemDelegate::mirrorChange();
+ emit visualPositionChanged();
+}
+
+void QQuickSwitchDelegate::nextCheckState()
+{
+ Q_D(QQuickSwitchDelegate);
+ if (keepMouseGrab() || keepTouchGrab()) {
+ d->toggle(d->position > 0.5);
+ // the checked state might not change => force a position update to
+ // avoid that the handle is left somewhere in the middle (QTBUG-57944)
+ setPosition(d->checked ? 1.0 : 0.0);
+ } else {
+ QQuickItemDelegate::nextCheckState();
+ }
+}
+
+void QQuickSwitchDelegate::buttonChange(ButtonChange change)
+{
+ Q_D(QQuickSwitchDelegate);
+ if (change == ButtonCheckedChange)
+ setPosition(d->checked ? 1.0 : 0.0);
+ else
+ QQuickAbstractButton::buttonChange(change);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquickswitchdelegate_p.cpp"
diff --git a/src/quicktemplates2/qquickswitchdelegate_p.h b/src/quicktemplates2/qquickswitchdelegate_p.h
new file mode 100644
index 0000000000..a2eb6f62ae
--- /dev/null
+++ b/src/quicktemplates2/qquickswitchdelegate_p.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKSWITCHDELEGATE_P_H
+#define QQUICKSWITCHDELEGATE_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 <QtQuickTemplates2/private/qquickitemdelegate_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickSwitchDelegatePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwitchDelegate : public QQuickItemDelegate
+{
+ Q_OBJECT
+ Q_PROPERTY(qreal position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
+ QML_NAMED_ELEMENT(SwitchDelegate)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickSwitchDelegate(QQuickItem *parent = nullptr);
+
+ qreal position() const;
+ void setPosition(qreal position);
+
+ qreal visualPosition() const;
+
+Q_SIGNALS:
+ void positionChanged();
+ void visualPositionChanged();
+
+protected:
+ void mouseMoveEvent(QMouseEvent *event) override;
+#if QT_CONFIG(quicktemplates2_multitouch)
+ void touchEvent(QTouchEvent *event) override;
+#endif
+
+ QFont defaultFont() const override;
+
+ void mirrorChange() override;
+
+ void nextCheckState() override;
+ void buttonChange(ButtonChange change) override;
+
+private:
+ Q_DISABLE_COPY(QQuickSwitchDelegate)
+ Q_DECLARE_PRIVATE(QQuickSwitchDelegate)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickSwitchDelegate)
+
+#endif // QQUICKSWITCHDELEGATE_P_H
diff --git a/src/quicktemplates2/qquicktabbar.cpp b/src/quicktemplates2/qquicktabbar.cpp
new file mode 100644
index 0000000000..0297324e01
--- /dev/null
+++ b/src/quicktemplates2/qquicktabbar.cpp
@@ -0,0 +1,508 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktabbar_p.h"
+#include "qquicktabbutton_p.h"
+#include "qquickcontainer_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype TabBar
+ \inherits Container
+//! \instantiates QQuickTabBar
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-navigation
+ \ingroup qtquickcontrols2-containers
+ \ingroup qtquickcontrols2-focusscopes
+ \brief Allows the user to switch between different views or subtasks.
+
+ TabBar provides a tab-based navigation model.
+
+ \image qtquickcontrols2-tabbar-wireframe.png
+
+ TabBar is populated with TabButton controls, and can be used together with
+ any layout or container control that provides \c currentIndex -property,
+ such as \l StackLayout or \l SwipeView
+
+ \snippet qtquickcontrols2-tabbar.qml 1
+
+ As shown above, TabBar is typically populated with a static set of tab buttons
+ that are defined inline as children of the tab bar. It is also possible to
+ \l {Container::addItem()}{add}, \l {Container::insertItem()}{insert},
+ \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
+ items dynamically at run time. The items can be accessed using
+ \l {Container::}{itemAt()} or \l {Container::}{contentChildren}.
+
+ \include container-currentindex.qdocinc {file} {TabBar} {SwipeView}
+
+ \section2 Resizing Tabs
+
+ By default, TabBar resizes its buttons to fit the width of the control.
+ The available space is distributed equally to each button. The default
+ resizing behavior can be overridden by setting an explicit width for the
+ buttons.
+
+ The following example illustrates how to keep each tab button at their
+ implicit size instead of being resized to fit the tabbar:
+
+ \borderedimage qtquickcontrols2-tabbar-explicit.png
+
+ \snippet qtquickcontrols2-tabbar-explicit.qml 1
+
+ \section2 Flickable Tabs
+
+ If the total width of the buttons exceeds the available width of the tab bar,
+ it automatically becomes flickable.
+
+ \image qtquickcontrols2-tabbar-flickable.png
+
+ \snippet qtquickcontrols2-tabbar-flickable.qml 1
+
+ \sa TabButton, {Customizing TabBar}, {Navigation Controls}, {Container Controls},
+ {Focus Management in Qt Quick Controls}
+*/
+
+class QQuickTabBarPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTabBar)
+
+public:
+ void updateCurrentItem();
+ void updateCurrentIndex();
+ void updateLayout();
+
+ qreal getContentWidth() const override;
+ qreal getContentHeight() const override;
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::TabBar); }
+
+ bool updatingLayout = false;
+ QQuickTabBar::Position position = QQuickTabBar::Header;
+#if QT_CONFIG(wheelevent)
+ QPoint accumulatedAngleDelta;
+#endif
+};
+
+class QQuickTabBarAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTabBarAttached)
+
+public:
+ static QQuickTabBarAttachedPrivate *get(QQuickTabBarAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void update(QQuickTabBar *tabBar, int index);
+
+ int index = -1;
+ QQuickTabBar *tabBar = nullptr;
+};
+
+void QQuickTabBarPrivate::updateCurrentItem()
+{
+ QQuickTabButton *button = qobject_cast<QQuickTabButton *>(contentModel->get(currentIndex));
+ if (button)
+ button->setChecked(true);
+}
+
+void QQuickTabBarPrivate::updateCurrentIndex()
+{
+ Q_Q(QQuickTabBar);
+ QQuickTabButton *button = qobject_cast<QQuickTabButton *>(q->sender());
+ if (button && button->isChecked())
+ q->setCurrentIndex(contentModel->indexOf(button, nullptr));
+}
+
+void QQuickTabBarPrivate::updateLayout()
+{
+ Q_Q(QQuickTabBar);
+ const int count = contentModel->count();
+ if (count <= 0 || !contentItem)
+ return;
+
+ qreal reservedWidth = 0;
+ int resizableCount = 0;
+
+ QList<QQuickItem *> allItems;
+ allItems.reserve(count);
+
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid())
+ ++resizableCount;
+ else
+ reservedWidth += item->width();
+ allItems += item;
+ }
+ }
+
+ const qreal totalSpacing = qMax(0, count - 1) * spacing;
+ const qreal itemWidth = (contentItem->width() - reservedWidth - totalSpacing) / qMax(1, resizableCount);
+
+ updatingLayout = true;
+ for (QQuickItem *item : qAsConst(allItems)) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid()) {
+ item->setWidth(itemWidth);
+ p->widthValidFlag = false;
+ }
+ if (!p->heightValid()) {
+ item->setHeight(contentHeight);
+ p->heightValidFlag = false;
+ } else {
+ item->setY((contentHeight - item->height()) / 2);
+ }
+ }
+ updatingLayout = false;
+}
+
+qreal QQuickTabBarPrivate::getContentWidth() const
+{
+ Q_Q(const QQuickTabBar);
+ const int count = contentModel->count();
+ qreal totalWidth = qMax(0, count - 1) * spacing;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid())
+ totalWidth += item->implicitWidth();
+ else
+ totalWidth += item->width();
+ }
+ }
+ return totalWidth;
+}
+
+qreal QQuickTabBarPrivate::getContentHeight() const
+{
+ Q_Q(const QQuickTabBar);
+ const int count = contentModel->count();
+ qreal maxHeight = 0;
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item)
+ maxHeight = qMax(maxHeight, item->implicitHeight());
+ }
+ return maxHeight;
+}
+
+void QQuickTabBarPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ QQuickContainerPrivate::itemGeometryChanged(item, change, diff);
+ if (!updatingLayout) {
+ if (change.sizeChange())
+ updateImplicitContentSize();
+ updateLayout();
+ }
+}
+
+void QQuickTabBarPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitWidthChanged(item);
+ if (item != contentItem)
+ updateImplicitContentWidth();
+}
+
+void QQuickTabBarPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ QQuickContainerPrivate::itemImplicitHeightChanged(item);
+ if (item != contentItem)
+ updateImplicitContentHeight();
+}
+
+QQuickTabBar::QQuickTabBar(QQuickItem *parent)
+ : QQuickContainer(*(new QQuickTabBarPrivate), parent)
+{
+ Q_D(QQuickTabBar);
+ d->changeTypes |= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+ setFlag(ItemIsFocusScope);
+ QObjectPrivate::connect(this, &QQuickTabBar::currentIndexChanged, d, &QQuickTabBarPrivate::updateCurrentItem);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::TabBar::position
+
+ This property holds the position of the tab bar.
+
+ \note If the tab bar is assigned as a header or footer of \l ApplicationWindow
+ or \l Page, the appropriate position is set automatically.
+
+ Possible values:
+ \value TabBar.Header The tab bar is at the top, as a window or page header.
+ \value TabBar.Footer The tab bar is at the bottom, as a window or page footer.
+
+ The default value is style-specific.
+
+ \sa ApplicationWindow::header, ApplicationWindow::footer, Page::header, Page::footer
+*/
+QQuickTabBar::Position QQuickTabBar::position() const
+{
+ Q_D(const QQuickTabBar);
+ return d->position;
+}
+
+void QQuickTabBar::setPosition(Position position)
+{
+ Q_D(QQuickTabBar);
+ if (d->position == position)
+ return;
+
+ d->position = position;
+ emit positionChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty real QtQuick.Controls::TabBar::contentWidth
+
+ This property holds the content width. It is used for calculating the total
+ implicit width of the tab bar.
+
+ \note This property is available in TabBar since QtQuick.Controls 2.2 (Qt 5.9),
+ but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
+
+ \sa Container::contentWidth
+*/
+
+/*!
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+ \qmlproperty real QtQuick.Controls::TabBar::contentHeight
+
+ This property holds the content height. It is used for calculating the total
+ implicit height of the tab bar.
+
+ \note This property is available in TabBar since QtQuick.Controls 2.2 (Qt 5.9),
+ but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
+
+ \sa Container::contentHeight
+*/
+
+QQuickTabBarAttached *QQuickTabBar::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickTabBarAttached(object);
+}
+
+void QQuickTabBar::updatePolish()
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::updatePolish();
+ d->updateLayout();
+}
+
+void QQuickTabBar::componentComplete()
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::componentComplete();
+ d->updateCurrentItem();
+ d->updateLayout();
+}
+
+void QQuickTabBar::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::geometryChange(newGeometry, oldGeometry);
+ d->updateLayout();
+}
+
+bool QQuickTabBar::isContent(QQuickItem *item) const
+{
+ return qobject_cast<QQuickTabButton *>(item);
+}
+
+void QQuickTabBar::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickTabBar);
+ Q_UNUSED(index);
+ QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-55129
+ if (QQuickTabButton *button = qobject_cast<QQuickTabButton *>(item))
+ QObjectPrivate::connect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex);
+ QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
+ if (attached)
+ QQuickTabBarAttachedPrivate::get(attached)->update(this, index);
+ d->updateImplicitContentSize();
+ if (isComponentComplete())
+ polish();
+}
+
+void QQuickTabBar::itemMoved(int index, QQuickItem *item)
+{
+ QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
+ if (attached)
+ QQuickTabBarAttachedPrivate::get(attached)->update(this, index);
+}
+
+void QQuickTabBar::itemRemoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickTabBar);
+ Q_UNUSED(index);
+ if (QQuickTabButton *button = qobject_cast<QQuickTabButton *>(item))
+ QObjectPrivate::disconnect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex);
+ QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
+ if (attached)
+ QQuickTabBarAttachedPrivate::get(attached)->update(nullptr, -1);
+ d->updateImplicitContentSize();
+ if (isComponentComplete())
+ polish();
+}
+
+#if QT_CONFIG(wheelevent)
+void QQuickTabBar::wheelEvent(QWheelEvent *event)
+{
+ Q_D(QQuickTabBar);
+ QQuickContainer::wheelEvent(event);
+ if (d->wheelEnabled) {
+ d->accumulatedAngleDelta += event->angleDelta();
+ int xSteps = d->accumulatedAngleDelta.x() / QWheelEvent::DefaultDeltasPerStep;
+ int ySteps = d->accumulatedAngleDelta.y() / QWheelEvent::DefaultDeltasPerStep;
+ if (xSteps > 0 || ySteps > 0) {
+ decrementCurrentIndex();
+ d->accumulatedAngleDelta = QPoint();
+ } else if (xSteps < 0 || ySteps < 0) {
+ incrementCurrentIndex();
+ d->accumulatedAngleDelta = QPoint();
+ }
+ }
+}
+#endif
+
+QFont QQuickTabBar::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::TabBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickTabBar::accessibleRole() const
+{
+ return QAccessible::PageTabList;
+}
+#endif
+
+/*!
+ \qmlattachedproperty int QtQuick.Controls::TabBar::index
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \readonly
+
+ This attached property holds the index of each tab button in the TabBar.
+
+ It is attached to each tab button of the TabBar.
+*/
+
+/*!
+ \qmlattachedproperty TabBar QtQuick.Controls::TabBar::tabBar
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \readonly
+
+ This attached property holds the tab bar that manages this tab button.
+
+ It is attached to each tab button of the TabBar.
+*/
+
+/*!
+ \qmlattachedproperty enumeration QtQuick.Controls::TabBar::position
+ \since QtQuick.Controls 2.3 (Qt 5.10)
+ \readonly
+
+ This attached property holds the position of the tab bar.
+
+ It is attached to each tab button of the TabBar.
+
+ Possible values:
+ \value TabBar.Header The tab bar is at the top, as a window or page header.
+ \value TabBar.Footer The tab bar is at the bottom, as a window or page footer.
+*/
+
+void QQuickTabBarAttachedPrivate::update(QQuickTabBar *newTabBar, int newIndex)
+{
+ Q_Q(QQuickTabBarAttached);
+ const int oldIndex = index;
+ const QQuickTabBar *oldTabBar = tabBar;
+ const QQuickTabBar::Position oldPos = q->position();
+
+ index = newIndex;
+ tabBar = newTabBar;
+
+ if (oldTabBar != newTabBar) {
+ if (oldTabBar)
+ QObject::disconnect(oldTabBar, &QQuickTabBar::positionChanged, q, &QQuickTabBarAttached::positionChanged);
+ if (newTabBar)
+ QObject::connect(newTabBar, &QQuickTabBar::positionChanged, q, &QQuickTabBarAttached::positionChanged);
+ emit q->tabBarChanged();
+ }
+
+ if (oldIndex != newIndex)
+ emit q->indexChanged();
+ if (oldPos != q->position())
+ emit q->positionChanged();
+}
+
+QQuickTabBarAttached::QQuickTabBarAttached(QObject *parent)
+ : QObject(*(new QQuickTabBarAttachedPrivate), parent)
+{
+}
+
+int QQuickTabBarAttached::index() const
+{
+ Q_D(const QQuickTabBarAttached);
+ return d->index;
+}
+
+QQuickTabBar *QQuickTabBarAttached::tabBar() const
+{
+ Q_D(const QQuickTabBarAttached);
+ return d->tabBar;
+}
+
+QQuickTabBar::Position QQuickTabBarAttached::position() const
+{
+ Q_D(const QQuickTabBarAttached);
+ if (!d->tabBar)
+ return QQuickTabBar::Header;
+ return d->tabBar->position();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktabbar_p.cpp"
diff --git a/src/quicktemplates2/qquicktabbar_p.h b/src/quicktemplates2/qquicktabbar_p.h
new file mode 100644
index 0000000000..2da6d4a77b
--- /dev/null
+++ b/src/quicktemplates2/qquicktabbar_p.h
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABBAR_P_H
+#define QQUICKTABBAR_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 <QtQuickTemplates2/private/qquickcontainer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTabBarPrivate;
+class QQuickTabBarAttached;
+class QQuickTabBarAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTabBar : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ QML_NAMED_ELEMENT(TabBar)
+ QML_ATTACHED(QQuickTabBarAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickTabBar(QQuickItem *parent = nullptr);
+
+ enum Position {
+ Header,
+ Footer
+ };
+ Q_ENUM(Position)
+
+ Position position() const;
+ void setPosition(Position position);
+
+ static QQuickTabBarAttached *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void positionChanged();
+
+protected:
+ void updatePolish() override;
+ void componentComplete() override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ bool isContent(QQuickItem *item) const override;
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemMoved(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+#if QT_CONFIG(wheelevent)
+ void wheelEvent(QWheelEvent *event) override;
+#endif
+
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickTabBar)
+ Q_DECLARE_PRIVATE(QQuickTabBar)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTabBarAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
+ Q_PROPERTY(QQuickTabBar *tabBar READ tabBar NOTIFY tabBarChanged FINAL)
+ Q_PROPERTY(QQuickTabBar::Position position READ position NOTIFY positionChanged FINAL)
+
+public:
+ explicit QQuickTabBarAttached(QObject *parent = nullptr);
+
+ int index() const;
+ QQuickTabBar *tabBar() const;
+ QQuickTabBar::Position position() const;
+
+Q_SIGNALS:
+ void indexChanged();
+ void tabBarChanged();
+ void positionChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickTabBarAttached)
+ Q_DECLARE_PRIVATE(QQuickTabBarAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTabBar)
+QML_DECLARE_TYPEINFO(QQuickTabBar, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTABBAR_P_H
diff --git a/src/quicktemplates2/qquicktabbutton.cpp b/src/quicktemplates2/qquicktabbutton.cpp
new file mode 100644
index 0000000000..0faa2150ea
--- /dev/null
+++ b/src/quicktemplates2/qquicktabbutton.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktabbutton_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickabstractbutton_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype TabButton
+ \inherits AbstractButton
+//! \instantiates QQuickTabButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-navigation
+ \brief Button with a look suitable for a TabBar.
+
+ \image qtquickcontrols2-tabbutton.png
+
+ TabButton is used in conjunction with a \l TabBar.
+
+ \snippet qtquickcontrols2-tabbutton.qml 1
+
+ TabButton inherits its API from AbstractButton. For instance, you can set
+ \l {AbstractButton::text}{text}, and react to \l {AbstractButton::clicked}{clicks}
+ using the AbstractButton API.
+
+ \sa TabBar, {Customizing TabButton}, {Button Controls}, {Navigation Controls}
+*/
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTabButtonPrivate : public QQuickAbstractButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTabButton)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::TabBar); }
+};
+
+QQuickTabButton::QQuickTabButton(QQuickItem *parent)
+ : QQuickAbstractButton(*(new QQuickTabButtonPrivate), parent)
+{
+ setCheckable(true);
+ setAutoExclusive(true);
+}
+
+QFont QQuickTabButton::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::TabBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickTabButton::accessibleRole() const
+{
+ return QAccessible::PageTab;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktabbutton_p.cpp"
diff --git a/src/quicktemplates2/qquicktabbutton_p.h b/src/quicktemplates2/qquicktabbutton_p.h
new file mode 100644
index 0000000000..302180c47d
--- /dev/null
+++ b/src/quicktemplates2/qquicktabbutton_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTABBUTTON_P_H
+#define QQUICKTABBUTTON_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 <QtQuickTemplates2/private/qquickabstractbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTabButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTabButton : public QQuickAbstractButton
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(TabButton)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickTabButton(QQuickItem *parent = nullptr);
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DECLARE_PRIVATE(QQuickTabButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTabButton)
+
+#endif // QQUICKTABBUTTON_P_H
diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp
new file mode 100644
index 0000000000..d28718f2fb
--- /dev/null
+++ b/src/quicktemplates2/qquicktextarea.cpp
@@ -0,0 +1,1181 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktextarea_p.h"
+#include "qquicktextarea_p_p.h"
+#include "qquickcontrol_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickscrollview_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickclipnode_p.h>
+#include <QtQuick/private/qquickflickable_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype TextArea
+ \inherits TextEdit
+//! \instantiates QQuickTextArea
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \brief Multi-line text input area.
+
+ TextArea is a multi-line text editor. TextArea extends TextEdit with
+ a \l {placeholderText}{placeholder text} functionality, and adds decoration.
+
+ \image qtquickcontrols2-textarea.png
+
+ \code
+ TextArea {
+ placeholderText: qsTr("Enter description")
+ }
+ \endcode
+
+ TextArea is not scrollable by itself. Especially on screen-size constrained
+ platforms, it is often preferable to make entire application pages scrollable.
+ On such a scrollable page, a non-scrollable TextArea might behave better than
+ nested scrollable controls. Notice, however, that in such a scenario, the background
+ decoration of the TextArea scrolls together with the rest of the scrollable
+ content.
+
+ \section2 Scrollable TextArea
+
+ If you want to make a TextArea scrollable, for example, when it covers
+ an entire application page, it can be placed inside a \l ScrollView.
+
+ \image qtquickcontrols2-textarea-scrollable.png
+
+ \snippet qtquickcontrols2-textarea-scrollable.qml 1
+
+ A TextArea that is placed inside a \l ScrollView does the following:
+
+ \list
+ \li Sets the content size automatically
+ \li Ensures that the background decoration stays in place
+ \li Clips the content
+ \endlist
+
+ \section2 Tab Focus
+
+ By default, pressing the tab key while TextArea has
+ \l {Item::activeFocus}{active focus} results in a tab character being input
+ into the control itself. To make tab pass active focus onto another item,
+ use the attached \l KeyNavigation properties:
+
+ \code
+ TextField {
+ id: textField
+ }
+
+ TextArea {
+ KeyNavigation.priority: KeyNavigation.BeforeItem
+ KeyNavigation.tab: textField
+ }
+ \endcode
+
+ \sa TextField, {Customizing TextArea}, {Input Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextArea::pressAndHold(MouseEvent event)
+
+ This signal is emitted when there is a long press (the delay depends on the platform plugin).
+ The \a event parameter provides information about the press, including the x and y
+ coordinates of the press, and which button is pressed.
+
+ \sa pressed, released
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextArea::pressed(MouseEvent event)
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This signal is emitted when the text area is pressed by the user.
+ The \a event parameter provides information about the press,
+ including the x and y coordinates of the press, and which button is pressed.
+
+ \sa released, pressAndHold
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextArea::released(MouseEvent event)
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This signal is emitted when the text area is released by the user.
+ The \a event parameter provides information about the release,
+ including the x and y coordinates of the press, and which button
+ is pressed.
+
+ \sa pressed, pressAndHold
+*/
+
+QQuickTextAreaPrivate::QQuickTextAreaPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installActivationObserver(this);
+#endif
+}
+
+QQuickTextAreaPrivate::~QQuickTextAreaPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void QQuickTextAreaPrivate::setTopInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextArea);
+ const QMarginsF oldInset = getInset();
+ extra.value().topInset = value;
+ extra.value().hasTopInset = !reset;
+ if (!qFuzzyCompare(oldInset.top(), value)) {
+ emit q->topInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextAreaPrivate::setLeftInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextArea);
+ const QMarginsF oldInset = getInset();
+ extra.value().leftInset = value;
+ extra.value().hasLeftInset = !reset;
+ if (!qFuzzyCompare(oldInset.left(), value)) {
+ emit q->leftInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextAreaPrivate::setRightInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextArea);
+ const QMarginsF oldInset = getInset();
+ extra.value().rightInset = value;
+ extra.value().hasRightInset = !reset;
+ if (!qFuzzyCompare(oldInset.right(), value)) {
+ emit q->rightInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextAreaPrivate::setBottomInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextArea);
+ const QMarginsF oldInset = getInset();
+ extra.value().bottomInset = value;
+ extra.value().hasBottomInset = !reset;
+ if (!qFuzzyCompare(oldInset.bottom(), value)) {
+ emit q->bottomInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextAreaPrivate::resizeBackground()
+{
+ if (!background)
+ return;
+
+ resizingBackground = true;
+
+ // When using the attached property TextArea.flickable, we reparent the background out
+ // of TextArea and into the Flickable since we don't want the background to move while
+ // flicking. This means that the size of the background should also follow the size of
+ // the Flickable rather than the size of the TextArea.
+ const auto flickable = qobject_cast<QQuickFlickable *>(background->parentItem());
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
+ || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
+ const qreal bgWidth = flickable ? flickable->width() : width;
+ background->setX(getLeftInset());
+ background->setWidth(bgWidth - getLeftInset() - getRightInset());
+ }
+
+ if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
+ || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
+ const qreal bgHeight = flickable ? flickable->height() : height;
+ background->setY(getTopInset());
+ background->setHeight(bgHeight - getTopInset() - getBottomInset());
+ }
+
+ resizingBackground = false;
+}
+
+/*!
+ \internal
+
+ Determine which font is implicitly imposed on this control by its ancestors
+ and QGuiApplication::font, resolve this against its own font (attributes from
+ the implicit font are copied over). Then propagate this font to this
+ control's children.
+*/
+void QQuickTextAreaPrivate::resolveFont()
+{
+ Q_Q(QQuickTextArea);
+ inheritFont(QQuickControlPrivate::parentFont(q));
+}
+
+void QQuickTextAreaPrivate::inheritFont(const QFont &font)
+{
+ QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
+ parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
+
+ const QFont defaultFont = QQuickTheme::font(QQuickTheme::TextArea);
+ QFont resolvedFont = parentFont.resolve(defaultFont);
+
+ setFont_helper(resolvedFont);
+}
+
+/*!
+ \internal
+
+ Assign \a font to this control, and propagate it to all children.
+*/
+void QQuickTextAreaPrivate::updateFont(const QFont &font)
+{
+ Q_Q(QQuickTextArea);
+ QFont oldFont = sourceFont;
+ q->QQuickTextEdit::setFont(font);
+
+ QQuickControlPrivate::updateFontRecur(q, font);
+
+ if (oldFont != font)
+ emit q->fontChanged();
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickTextAreaPrivate::updateHoverEnabled(bool enabled, bool xplicit)
+{
+ Q_Q(QQuickTextArea);
+ if (!xplicit && explicitHoverEnabled)
+ return;
+
+ bool wasEnabled = q->isHoverEnabled();
+ explicitHoverEnabled = xplicit;
+ if (wasEnabled != enabled) {
+ q->setAcceptHoverEvents(enabled);
+ QQuickControlPrivate::updateHoverEnabledRecur(q, enabled);
+ emit q->hoverEnabledChanged();
+ }
+}
+#endif
+
+void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item)
+{
+ Q_Q(QQuickTextArea);
+ flickable = item;
+ q->setParentItem(flickable->contentItem());
+
+ if (background)
+ background->setParentItem(flickable);
+
+ QObjectPrivate::connect(q, &QQuickTextArea::contentSizeChanged, this, &QQuickTextAreaPrivate::resizeFlickableContent);
+ QObjectPrivate::connect(q, &QQuickTextEdit::cursorRectangleChanged, this, &QQuickTextAreaPrivate::ensureCursorVisible);
+
+ QObject::connect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
+ QObject::connect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
+
+ QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size);
+ QQuickItemPrivate::get(flickable)->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
+ QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
+
+ resizeFlickableControl();
+}
+
+void QQuickTextAreaPrivate::detachFlickable()
+{
+ Q_Q(QQuickTextArea);
+ q->setParentItem(nullptr);
+ if (background && background->parentItem() == flickable)
+ background->setParentItem(q);
+
+ QObjectPrivate::disconnect(q, &QQuickTextArea::contentSizeChanged, this, &QQuickTextAreaPrivate::resizeFlickableContent);
+ QObjectPrivate::disconnect(q, &QQuickTextEdit::cursorRectangleChanged, this, &QQuickTextAreaPrivate::ensureCursorVisible);
+
+ QObject::disconnect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
+ QObject::disconnect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
+
+ QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickGeometryChange::Nothing);
+ QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed);
+ QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
+ QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
+
+ flickable = nullptr;
+
+ resizeBackground();
+}
+
+void QQuickTextAreaPrivate::ensureCursorVisible()
+{
+ Q_Q(QQuickTextArea);
+ if (!flickable)
+ return;
+
+ const qreal cx = flickable->contentX();
+ const qreal cy = flickable->contentY();
+ const qreal w = flickable->width();
+ const qreal h = flickable->height();
+
+ const qreal tp = q->topPadding();
+ const qreal lp = q->leftPadding();
+ const QRectF cr = q->cursorRectangle();
+
+ if (cr.left() <= cx + lp) {
+ flickable->setContentX(cr.left() - lp);
+ } else {
+ // calculate the rectangle of the next character and ensure that
+ // it's visible if it's on the same line with the cursor
+ const qreal rp = q->rightPadding();
+ const QRectF nr = q->cursorPosition() < q->length() ? q->positionToRectangle(q->cursorPosition() + 1) : QRectF();
+ if (qFuzzyCompare(nr.y(), cr.y()) && nr.right() >= cx + lp + w - rp)
+ flickable->setContentX(nr.right() - w + rp);
+ else if (cr.right() >= cx + lp + w - rp)
+ flickable->setContentX(cr.right() - w + rp);
+ }
+
+ if (cr.top() <= cy + tp) {
+ flickable->setContentY(cr.top() - tp);
+ } else {
+ const qreal bp = q->bottomPadding();
+ if (cr.bottom() >= cy + tp + h - bp)
+ flickable->setContentY(cr.bottom() - h + bp);
+ }
+}
+
+void QQuickTextAreaPrivate::resizeFlickableControl()
+{
+ Q_Q(QQuickTextArea);
+ if (!flickable)
+ return;
+
+ const qreal w = wrapMode == QQuickTextArea::NoWrap ? qMax(flickable->width(), flickable->contentWidth()) : flickable->width();
+ const qreal h = qMax(flickable->height(), flickable->contentHeight());
+ q->setSize(QSizeF(w, h));
+
+ resizeBackground();
+}
+
+void QQuickTextAreaPrivate::resizeFlickableContent()
+{
+ Q_Q(QQuickTextArea);
+ if (!flickable)
+ return;
+
+ flickable->setContentWidth(q->contentWidth() + q->leftPadding() + q->rightPadding());
+ flickable->setContentHeight(q->contentHeight() + q->topPadding() + q->bottomPadding());
+}
+
+void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(diff);
+ if (!resizingBackground && item == background) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ // Only set hasBackgroundWidth/Height if it was a width/height change,
+ // otherwise we're prevented from setting a width/height in the future.
+ if (change.widthChange())
+ extra.value().hasBackgroundWidth = p->widthValid();
+ if (change.heightChange())
+ extra.value().hasBackgroundHeight = p->heightValid();
+ }
+
+ if (flickable)
+ resizeFlickableControl();
+ else
+ resizeBackground();
+}
+
+qreal QQuickTextAreaPrivate::getImplicitWidth() const
+{
+ return QQuickItemPrivate::getImplicitWidth();
+}
+
+qreal QQuickTextAreaPrivate::getImplicitHeight() const
+{
+ return QQuickItemPrivate::getImplicitHeight();
+}
+
+void QQuickTextAreaPrivate::implicitWidthChanged()
+{
+ Q_Q(QQuickTextArea);
+ QQuickItemPrivate::implicitWidthChanged();
+ emit q->implicitWidthChanged3();
+}
+
+void QQuickTextAreaPrivate::implicitHeightChanged()
+{
+ Q_Q(QQuickTextArea);
+ QQuickItemPrivate::implicitHeightChanged();
+ emit q->implicitHeightChanged3();
+}
+
+void QQuickTextAreaPrivate::readOnlyChanged(bool isReadOnly)
+{
+ Q_UNUSED(isReadOnly);
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(q_func()))
+ accessibleAttached->set_readOnly(isReadOnly);
+#endif
+#if QT_CONFIG(cursor)
+ q_func()->setCursor(isReadOnly && !selectByMouse ? Qt::ArrowCursor : Qt::IBeamCursor);
+#endif
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickTextAreaPrivate::accessibilityActiveChanged(bool active)
+{
+ if (!active)
+ return;
+
+ Q_Q(QQuickTextArea);
+ QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
+ Q_ASSERT(accessibleAttached);
+ accessibleAttached->setRole(accessibleRole());
+ accessibleAttached->set_readOnly(q->isReadOnly());
+ accessibleAttached->setDescription(placeholder);
+}
+
+QAccessible::Role QQuickTextAreaPrivate::accessibleRole() const
+{
+ return QAccessible::EditableText;
+}
+#endif
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickTextAreaPrivate::cancelBackground()
+{
+ Q_Q(QQuickTextArea);
+ quickCancelDeferred(q, backgroundName());
+}
+
+void QQuickTextAreaPrivate::executeBackground(bool complete)
+{
+ Q_Q(QQuickTextArea);
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
+}
+
+void QQuickTextAreaPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickTextArea);
+ if (item == background)
+ emit q->implicitBackgroundWidthChanged();
+}
+
+void QQuickTextAreaPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickTextArea);
+ if (item == background)
+ emit q->implicitBackgroundHeightChanged();
+}
+
+void QQuickTextAreaPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickTextArea);
+ if (item == background) {
+ background = nullptr;
+ emit q->implicitBackgroundWidthChanged();
+ emit q->implicitBackgroundHeightChanged();
+ } else if (item == flickable) {
+ detachFlickable();
+ }
+}
+
+QPalette QQuickTextAreaPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::TextArea);
+}
+
+QQuickTextArea::QQuickTextArea(QQuickItem *parent)
+ : QQuickTextEdit(*(new QQuickTextAreaPrivate), parent)
+{
+ Q_D(QQuickTextArea);
+ setActiveFocusOnTab(true);
+ setAcceptedMouseButtons(Qt::AllButtons);
+ d->setImplicitResizeEnabled(false);
+ d->pressHandler.control = this;
+#if QT_CONFIG(cursor)
+ setCursor(Qt::IBeamCursor);
+#endif
+ QObjectPrivate::connect(this, &QQuickTextEdit::readOnlyChanged,
+ d, &QQuickTextAreaPrivate::readOnlyChanged);
+}
+
+QQuickTextArea::~QQuickTextArea()
+{
+ Q_D(QQuickTextArea);
+ if (d->flickable)
+ d->detachFlickable();
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+}
+
+QQuickTextAreaAttached *QQuickTextArea::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickTextAreaAttached(object);
+}
+
+QFont QQuickTextArea::font() const
+{
+ return QQuickTextEdit::font();
+}
+
+void QQuickTextArea::setFont(const QFont &font)
+{
+ Q_D(QQuickTextArea);
+ if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
+ return;
+
+ d->extra.value().requestedFont = font;
+ d->resolveFont();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::TextArea::background
+
+ This property holds the background item.
+
+ \input qquickcontrol-background.qdocinc notes
+
+ \sa {Customizing TextArea}
+*/
+QQuickItem *QQuickTextArea::background() const
+{
+ QQuickTextAreaPrivate *d = const_cast<QQuickTextAreaPrivate *>(d_func());
+ if (!d->background)
+ d->executeBackground();
+ return d->background;
+}
+
+void QQuickTextArea::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickTextArea);
+ if (d->background == background)
+ return;
+
+ if (!d->background.isExecuting())
+ d->cancelBackground();
+
+ const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
+ const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
+
+ if (d->extra.isAllocated()) {
+ d->extra.value().hasBackgroundWidth = false;
+ d->extra.value().hasBackgroundHeight = false;
+ }
+
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ QQuickControlPrivate::hideOldItem(d->background);
+ d->background = background;
+
+ if (background) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (p->widthValid() || p->heightValid()) {
+ d->extra.value().hasBackgroundWidth = p->widthValid();
+ d->extra.value().hasBackgroundHeight = p->heightValid();
+ }
+ if (d->flickable)
+ background->setParentItem(d->flickable);
+ else
+ background->setParentItem(this);
+ if (qFuzzyIsNull(background->z()))
+ background->setZ(-1);
+ if (isComponentComplete())
+ d->resizeBackground();
+ QQuickControlPrivate::addImplicitSizeListener(background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ }
+
+ if (!qFuzzyCompare(oldImplicitBackgroundWidth, implicitBackgroundWidth()))
+ emit implicitBackgroundWidthChanged();
+ if (!qFuzzyCompare(oldImplicitBackgroundHeight, implicitBackgroundHeight()))
+ emit implicitBackgroundHeightChanged();
+ if (!d->background.isExecuting())
+ emit backgroundChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::TextArea::placeholderText
+
+ This property holds the short hint that is displayed in the text area before
+ the user enters a value.
+*/
+QString QQuickTextArea::placeholderText() const
+{
+ Q_D(const QQuickTextArea);
+ return d->placeholder;
+}
+
+void QQuickTextArea::setPlaceholderText(const QString &text)
+{
+ Q_D(QQuickTextArea);
+ if (d->placeholder == text)
+ return;
+
+ d->placeholder = text;
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this))
+ accessibleAttached->setDescription(text);
+#endif
+ emit placeholderTextChanged();
+}
+
+/*!
+ \qmlproperty color QtQuick.Controls::TextArea::placeholderTextColor
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+
+ This property holds the color of placeholderText.
+
+ \sa placeholderText
+*/
+QColor QQuickTextArea::placeholderTextColor() const
+{
+ Q_D(const QQuickTextArea);
+ return d->placeholderColor;
+}
+
+void QQuickTextArea::setPlaceholderTextColor(const QColor &color)
+{
+ Q_D(QQuickTextArea);
+ if (d->placeholderColor == color)
+ return;
+
+ d->placeholderColor = color;
+ emit placeholderTextColorChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::TextArea::focusReason
+
+ \include qquickcontrol-focusreason.qdocinc
+*/
+Qt::FocusReason QQuickTextArea::focusReason() const
+{
+ Q_D(const QQuickTextArea);
+ return d->focusReason;
+}
+
+void QQuickTextArea::setFocusReason(Qt::FocusReason reason)
+{
+ Q_D(QQuickTextArea);
+ if (d->focusReason == reason)
+ return;
+
+ d->focusReason = reason;
+ emit focusReasonChanged();
+}
+
+bool QQuickTextArea::contains(const QPointF &point) const
+{
+ Q_D(const QQuickTextArea);
+ if (d->flickable && !d->flickable->contains(d->flickable->mapFromItem(this, point)))
+ return false;
+ return QQuickTextEdit::contains(point);
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::TextArea::hovered
+ \readonly
+
+ This property holds whether the text area is hovered.
+
+ \sa hoverEnabled
+*/
+bool QQuickTextArea::isHovered() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickTextArea);
+ return d->hovered;
+#else
+ return false;
+#endif
+}
+
+void QQuickTextArea::setHovered(bool hovered)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextArea);
+ if (hovered == d->hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+#else
+ Q_UNUSED(hovered);
+#endif
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::TextArea::hoverEnabled
+
+ This property determines whether the text area accepts hover events. The default value is \c true.
+
+ \sa hovered
+*/
+bool QQuickTextArea::isHoverEnabled() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickTextArea);
+ return d->hoverEnabled;
+#else
+ return false;
+#endif
+}
+
+void QQuickTextArea::setHoverEnabled(bool enabled)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextArea);
+ if (d->explicitHoverEnabled && enabled == d->hoverEnabled)
+ return;
+
+ d->updateHoverEnabled(enabled, true); // explicit=true
+#else
+ Q_UNUSED(enabled);
+#endif
+}
+
+void QQuickTextArea::resetHoverEnabled()
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextArea);
+ if (!d->explicitHoverEnabled)
+ return;
+
+ d->explicitHoverEnabled = false;
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundWidth
+ \readonly
+
+ This property holds the implicit background width.
+
+ The value is equal to \c {background ? background.implicitWidth : 0}.
+
+ \sa implicitBackgroundHeight
+*/
+qreal QQuickTextArea::implicitBackgroundWidth() const
+{
+ Q_D(const QQuickTextArea);
+ if (!d->background)
+ return 0;
+ return d->background->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::implicitBackgroundHeight
+ \readonly
+
+ This property holds the implicit background height.
+
+ The value is equal to \c {background ? background.implicitHeight : 0}.
+
+ \sa implicitBackgroundWidth
+*/
+qreal QQuickTextArea::implicitBackgroundHeight() const
+{
+ Q_D(const QQuickTextArea);
+ if (!d->background)
+ return 0;
+ return d->background->implicitHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::topInset
+
+ This property holds the top inset for the background.
+
+ \sa {Control Layout}, bottomInset
+*/
+qreal QQuickTextArea::topInset() const
+{
+ Q_D(const QQuickTextArea);
+ return d->getTopInset();
+}
+
+void QQuickTextArea::setTopInset(qreal inset)
+{
+ Q_D(QQuickTextArea);
+ d->setTopInset(inset);
+}
+
+void QQuickTextArea::resetTopInset()
+{
+ Q_D(QQuickTextArea);
+ d->setTopInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::leftInset
+
+ This property holds the left inset for the background.
+
+ \sa {Control Layout}, rightInset
+*/
+qreal QQuickTextArea::leftInset() const
+{
+ Q_D(const QQuickTextArea);
+ return d->getLeftInset();
+}
+
+void QQuickTextArea::setLeftInset(qreal inset)
+{
+ Q_D(QQuickTextArea);
+ d->setLeftInset(inset);
+}
+
+void QQuickTextArea::resetLeftInset()
+{
+ Q_D(QQuickTextArea);
+ d->setLeftInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::rightInset
+
+ This property holds the right inset for the background.
+
+ \sa {Control Layout}, leftInset
+*/
+qreal QQuickTextArea::rightInset() const
+{
+ Q_D(const QQuickTextArea);
+ return d->getRightInset();
+}
+
+void QQuickTextArea::setRightInset(qreal inset)
+{
+ Q_D(QQuickTextArea);
+ d->setRightInset(inset);
+}
+
+void QQuickTextArea::resetRightInset()
+{
+ Q_D(QQuickTextArea);
+ d->setRightInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextArea::bottomInset
+
+ This property holds the bottom inset for the background.
+
+ \sa {Control Layout}, topInset
+*/
+qreal QQuickTextArea::bottomInset() const
+{
+ Q_D(const QQuickTextArea);
+ return d->getBottomInset();
+}
+
+void QQuickTextArea::setBottomInset(qreal inset)
+{
+ Q_D(QQuickTextArea);
+ d->setBottomInset(inset);
+}
+
+void QQuickTextArea::resetBottomInset()
+{
+ Q_D(QQuickTextArea);
+ d->setBottomInset(0, true);
+}
+
+void QQuickTextArea::classBegin()
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::classBegin();
+ d->resolveFont();
+}
+
+void QQuickTextArea::componentComplete()
+{
+ Q_D(QQuickTextArea);
+ d->executeBackground(true);
+ QQuickTextEdit::componentComplete();
+ d->resizeBackground();
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ setAcceptHoverEvents(QQuickControlPrivate::calcHoverEnabled(d->parentItem));
+#endif
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ d->accessibilityActiveChanged(true);
+#endif
+}
+
+void QQuickTextArea::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::itemChange(change, value);
+ switch (change) {
+ case ItemEnabledHasChanged:
+ break;
+ case ItemSceneChange:
+ case ItemParentHasChanged:
+ if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
+ d->resolveFont();
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+ if (change == ItemParentHasChanged) {
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(value.item->parentItem());
+ if (flickable) {
+ QQuickScrollView *scrollView = qobject_cast<QQuickScrollView *>(flickable->parentItem());
+ if (scrollView)
+ d->attachFlickable(flickable);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickTextArea::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::geometryChange(newGeometry, oldGeometry);
+ d->resizeBackground();
+}
+
+void QQuickTextArea::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
+{
+ Q_D(QQuickTextArea);
+ Q_UNUSED(newInset);
+ Q_UNUSED(oldInset);
+ d->resizeBackground();
+}
+
+QSGNode *QQuickTextArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ Q_D(QQuickTextArea);
+ QQuickDefaultClipNode *clipNode = static_cast<QQuickDefaultClipNode *>(oldNode);
+ if (!clipNode)
+ clipNode = new QQuickDefaultClipNode(QRectF());
+
+ QQuickItem *clipper = this;
+ if (d->flickable)
+ clipper = d->flickable;
+
+ const QRectF cr = clipper->clipRect().adjusted(
+ leftPadding(), topPadding(),
+ (!d->cursorItem && effectiveHAlign() == HAlignment::AlignRight ? 1 : 0) - rightPadding(),
+ -bottomPadding());
+
+ clipNode->setRect(!d->flickable ? cr : cr.translated(d->flickable->contentX(), d->flickable->contentY()));
+ clipNode->update();
+
+ QSGNode *textNode = QQuickTextEdit::updatePaintNode(clipNode->firstChild(), data);
+ if (!textNode->parent())
+ clipNode->appendChildNode(textNode);
+
+ if (d->cursorItem) {
+ QQuickDefaultClipNode *cursorNode = QQuickItemPrivate::get(d->cursorItem)->clipNode();
+ if (cursorNode)
+ cursorNode->setClipRect(d->cursorItem->mapRectFromItem(clipper, cr));
+ }
+
+ return clipNode;
+}
+
+void QQuickTextArea::focusInEvent(QFocusEvent *event)
+{
+ QQuickTextEdit::focusInEvent(event);
+ setFocusReason(event->reason());
+}
+
+void QQuickTextArea::focusOutEvent(QFocusEvent *event)
+{
+ QQuickTextEdit::focusOutEvent(event);
+ setFocusReason(event->reason());
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickTextArea::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::hoverEnterEvent(event);
+ setHovered(d->hoverEnabled);
+ event->ignore();
+}
+
+void QQuickTextArea::hoverLeaveEvent(QHoverEvent *event)
+{
+ QQuickTextEdit::hoverLeaveEvent(event);
+ setHovered(false);
+ event->ignore();
+}
+#endif
+
+void QQuickTextArea::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextArea);
+ d->pressHandler.mousePressEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ // Calling the base class implementation will result in QQuickTextControl's
+ // press handler being called, which ignores events that aren't Qt::LeftButton.
+ const bool wasAccepted = event->isAccepted();
+ QQuickTextEdit::mousePressEvent(event);
+ if (wasAccepted)
+ event->accept();
+ }
+}
+
+void QQuickTextArea::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextArea);
+ d->pressHandler.mouseMoveEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ QQuickTextEdit::mouseMoveEvent(event);
+ }
+}
+
+void QQuickTextArea::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextArea);
+ d->pressHandler.mouseReleaseEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ QQuickTextEdit::mouseReleaseEvent(event);
+ }
+}
+
+void QQuickTextArea::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextArea);
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ QQuickTextEdit::mouseDoubleClickEvent(event);
+}
+
+void QQuickTextArea::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickTextArea);
+ if (event->timerId() == d->pressHandler.timer.timerId())
+ d->pressHandler.timerEvent(event);
+ else
+ QQuickTextEdit::timerEvent(event);
+}
+
+class QQuickTextAreaAttachedPrivate : public QObjectPrivate
+{
+public:
+ QQuickTextArea *control = nullptr;
+};
+
+QQuickTextAreaAttached::QQuickTextAreaAttached(QObject *parent)
+ : QObject(*(new QQuickTextAreaAttachedPrivate), parent)
+{
+}
+
+/*!
+ \qmlattachedproperty TextArea QtQuick.Controls::TextArea::flickable
+
+ This property attaches a text area to a \l Flickable.
+
+ \sa ScrollBar, ScrollIndicator, {Scrollable TextArea}
+*/
+QQuickTextArea *QQuickTextAreaAttached::flickable() const
+{
+ Q_D(const QQuickTextAreaAttached);
+ return d->control;
+}
+
+void QQuickTextAreaAttached::setFlickable(QQuickTextArea *control)
+{
+ Q_D(QQuickTextAreaAttached);
+ QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(parent());
+ if (!flickable) {
+ qmlWarning(parent()) << "TextArea must be attached to a Flickable";
+ return;
+ }
+
+ if (d->control == control)
+ return;
+
+ if (d->control)
+ QQuickTextAreaPrivate::get(d->control)->detachFlickable();
+
+ d->control = control;
+
+ if (control)
+ QQuickTextAreaPrivate::get(control)->attachFlickable(flickable);
+
+ emit flickableChanged();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktextarea_p.cpp"
diff --git a/src/quicktemplates2/qquicktextarea_p.h b/src/quicktemplates2/qquicktextarea_p.h
new file mode 100644
index 0000000000..8ab62d4d78
--- /dev/null
+++ b/src/quicktemplates2/qquicktextarea_p.h
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTAREA_P_H
+#define QQUICKTEXTAREA_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/qpalette.h>
+#include <QtQuick/private/qquicktextedit_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickText;
+class QQuickTextAreaPrivate;
+class QQuickTextAreaAttached;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTextArea : public QQuickTextEdit
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged3 FINAL)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged3 FINAL)
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL)
+ Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL REVISION(2, 1))
+ Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled RESET resetHoverEnabled NOTIFY hoverEnabledChanged FINAL REVISION(2, 1))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(QColor placeholderTextColor READ placeholderTextColor WRITE setPlaceholderTextColor NOTIFY placeholderTextColorChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundWidth READ implicitBackgroundWidth NOTIFY implicitBackgroundWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundHeight READ implicitBackgroundHeight NOTIFY implicitBackgroundHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal topInset READ topInset WRITE setTopInset RESET resetTopInset NOTIFY topInsetChanged FINAL REVISION(2, 5))
+ 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_CLASSINFO("DeferredPropertyNames", "background")
+ QML_NAMED_ELEMENT(TextArea)
+ QML_ATTACHED(QQuickTextAreaAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickTextArea(QQuickItem *parent = nullptr);
+ ~QQuickTextArea();
+
+ static QQuickTextAreaAttached *qmlAttachedProperties(QObject *object);
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ QString placeholderText() const;
+ void setPlaceholderText(const QString &text);
+
+ Qt::FocusReason focusReason() const;
+ void setFocusReason(Qt::FocusReason reason);
+
+ bool contains(const QPointF &point) const override;
+
+ // 2.1 (Qt 5.8)
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ bool isHoverEnabled() const;
+ void setHoverEnabled(bool enabled);
+ void resetHoverEnabled();
+
+ // 2.5 (Qt 5.12)
+ QColor placeholderTextColor() const;
+ void setPlaceholderTextColor(const QColor &color);
+
+ qreal implicitBackgroundWidth() const;
+ qreal implicitBackgroundHeight() const;
+
+ qreal topInset() const;
+ void setTopInset(qreal inset);
+ void resetTopInset();
+
+ qreal leftInset() const;
+ void setLeftInset(qreal inset);
+ void resetLeftInset();
+
+ qreal rightInset() const;
+ void setRightInset(qreal inset);
+ void resetRightInset();
+
+ qreal bottomInset() const;
+ void setBottomInset(qreal inset);
+ void resetBottomInset();
+
+Q_SIGNALS:
+ void fontChanged();
+ void implicitWidthChanged3();
+ void implicitHeightChanged3();
+ void backgroundChanged();
+ void placeholderTextChanged();
+ void focusReasonChanged();
+ void pressAndHold(QQuickMouseEvent *event);
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void pressed(QQuickMouseEvent *event);
+ Q_REVISION(2, 1) void released(QQuickMouseEvent *event);
+ Q_REVISION(2, 1) void hoveredChanged();
+ Q_REVISION(2, 1) void hoverEnabledChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void placeholderTextColorChanged();
+ Q_REVISION(2, 5) void implicitBackgroundWidthChanged();
+ Q_REVISION(2, 5) void implicitBackgroundHeightChanged();
+ Q_REVISION(2, 5) void topInsetChanged();
+ Q_REVISION(2, 5) void leftInsetChanged();
+ Q_REVISION(2, 5) void rightInsetChanged();
+ Q_REVISION(2, 5) void bottomInsetChanged();
+
+protected:
+ friend struct QQuickPressHandler;
+
+ void classBegin() override;
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ virtual void insetChange(const QMarginsF &newInset, const QMarginsF &oldInset);
+
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;
+
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+#if QT_CONFIG(quicktemplates2_hover)
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+#endif
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickTextArea)
+ Q_DECLARE_PRIVATE(QQuickTextArea)
+};
+
+class QQuickTextAreaAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTextAreaAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickTextArea *flickable READ flickable WRITE setFlickable NOTIFY flickableChanged FINAL)
+
+public:
+ explicit QQuickTextAreaAttached(QObject *parent);
+
+ QQuickTextArea *flickable() const;
+ void setFlickable(QQuickTextArea *control);
+
+Q_SIGNALS:
+ void flickableChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickTextAreaAttached)
+ Q_DECLARE_PRIVATE(QQuickTextAreaAttached)
+};
+
+struct QQuickTextEditForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickTextEdit)
+ QML_ADDED_IN_VERSION(2, 3)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTextArea)
+QML_DECLARE_TYPEINFO(QQuickTextArea, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTEXTAREA_P_H
diff --git a/src/quicktemplates2/qquicktextarea_p_p.h b/src/quicktemplates2/qquicktextarea_p_p.h
new file mode 100644
index 0000000000..2ed2b44f31
--- /dev/null
+++ b/src/quicktemplates2/qquicktextarea_p_p.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTAREA_P_P_H
+#define QQUICKTEXTAREA_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 <QtQml/private/qlazilyallocated_p.h>
+#include <QtQuick/private/qquicktextedit_p_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickpresshandler_p_p.h>
+#include <QtQuickTemplates2/private/qquickdeferredpointer_p_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#include <QtQuickTemplates2/private/qquicktextarea_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQuickFlickable;
+
+class QQuickTextAreaPrivate : public QQuickTextEditPrivate, public QQuickItemChangeListener
+#if QT_CONFIG(accessibility)
+ , public QAccessible::ActivationObserver
+#endif
+{
+ Q_DECLARE_PUBLIC(QQuickTextArea)
+
+public:
+ QQuickTextAreaPrivate();
+ ~QQuickTextAreaPrivate();
+
+ static QQuickTextAreaPrivate *get(QQuickTextArea *item)
+ {
+ return static_cast<QQuickTextAreaPrivate *>(QObjectPrivate::get(item));
+ }
+
+ inline QMarginsF getInset() const { return QMarginsF(getLeftInset(), getTopInset(), getRightInset(), getBottomInset()); }
+ inline qreal getTopInset() const { return extra.isAllocated() ? extra->topInset : 0; }
+ inline qreal getLeftInset() const { return extra.isAllocated() ? extra->leftInset : 0; }
+ inline qreal getRightInset() const { return extra.isAllocated() ? extra->rightInset : 0; }
+ inline qreal getBottomInset() const { return extra.isAllocated() ? extra->bottomInset : 0; }
+
+ void setTopInset(qreal value, bool reset = false);
+ void setLeftInset(qreal value, bool reset = false);
+ void setRightInset(qreal value, bool reset = false);
+ void setBottomInset(qreal value, bool reset = false);
+
+ void resizeBackground();
+
+ void resolveFont();
+ void inheritFont(const QFont &font);
+ void updateFont(const QFont &font);
+ inline void setFont_helper(const QFont &font) {
+ if (sourceFont.resolveMask() == font.resolveMask() && sourceFont == font)
+ return;
+ updateFont(font);
+ }
+
+#if QT_CONFIG(quicktemplates2_hover)
+ void updateHoverEnabled(bool h, bool e);
+#endif
+
+ void attachFlickable(QQuickFlickable *flickable);
+ void detachFlickable();
+ void ensureCursorVisible();
+ void resizeFlickableControl();
+ void resizeFlickableContent();
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+
+ qreal getImplicitWidth() const override;
+ qreal getImplicitHeight() const override;
+
+ void implicitWidthChanged() override;
+ void implicitHeightChanged() override;
+
+ void readOnlyChanged(bool isReadOnly);
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+ void cancelBackground();
+ void executeBackground(bool complete = false);
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override;
+
+#if QT_CONFIG(quicktemplates2_hover)
+ bool hovered = false;
+ bool explicitHoverEnabled = false;
+#endif
+
+ struct ExtraData {
+ bool hasTopInset = false;
+ bool hasLeftInset = false;
+ bool hasRightInset = false;
+ bool hasBottomInset = false;
+ bool hasBackgroundWidth = false;
+ bool hasBackgroundHeight = false;
+ qreal topInset = 0;
+ qreal leftInset = 0;
+ qreal rightInset = 0;
+ qreal bottomInset = 0;
+ QFont requestedFont;
+ QPalette requestedPalette;
+ };
+ QLazilyAllocated<ExtraData> extra;
+
+ bool resizingBackground = false;
+ QPalette resolvedPalette;
+ QQuickDeferredPointer<QQuickItem> background;
+ QString placeholder;
+ QColor placeholderColor;
+ Qt::FocusReason focusReason = Qt::OtherFocusReason;
+ QQuickPressHandler pressHandler;
+ QQuickFlickable *flickable = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTEXTAREA_P_P_H
diff --git a/src/quicktemplates2/qquicktextfield.cpp b/src/quicktemplates2/qquicktextfield.cpp
new file mode 100644
index 0000000000..7cac120805
--- /dev/null
+++ b/src/quicktemplates2/qquicktextfield.cpp
@@ -0,0 +1,953 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktextfield_p.h"
+#include "qquicktextfield_p_p.h"
+#include "qquickcontrol_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickdeferredexecute_p_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquickclipnode_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtQuick/private/qquickaccessibleattached_p.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype TextField
+ \inherits TextInput
+//! \instantiates QQuickTextField
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \brief Single-line text input field.
+
+ TextField is a single line text editor. TextField extends TextInput with
+ a \l {placeholderText}{placeholder text} functionality, and adds decoration.
+
+ \table
+ \row \li \image qtquickcontrols2-textfield-normal.png
+ \li A text field in its normal state.
+ \row \li \image qtquickcontrols2-textfield-focused.png
+ \li A text field that has active focus.
+ \row \li \image qtquickcontrols2-textfield-disabled.png
+ \li A text field that is disabled.
+ \endtable
+
+ \code
+ TextField {
+ placeholderText: qsTr("Enter name")
+ }
+ \endcode
+
+ \sa TextArea, {Customizing TextField}, {Input Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextField::pressAndHold(MouseEvent event)
+
+ This signal is emitted when there is a long press (the delay depends on the platform plugin).
+ The \a event parameter provides information about the press, including the x and y
+ coordinates of the press, and which button is pressed.
+
+ \sa pressed, released
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextField::pressed(MouseEvent event)
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This signal is emitted when the text field is pressed by the user.
+ The \a event parameter provides information about the press,
+ including the x and y coordinates of the press, and which button
+ is pressed.
+
+ \sa released, pressAndHold
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextField::released(MouseEvent event)
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This signal is emitted when the text field is released by the user.
+ The \a event parameter provides information about the release,
+ including the x and y coordinates of the press, and which button
+ is pressed.
+
+ \sa pressed, pressAndHold
+*/
+
+QQuickTextFieldPrivate::QQuickTextFieldPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installActivationObserver(this);
+#endif
+}
+
+QQuickTextFieldPrivate::~QQuickTextFieldPrivate()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::removeActivationObserver(this);
+#endif
+}
+
+void QQuickTextFieldPrivate::setTopInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextField);
+ const QMarginsF oldInset = getInset();
+ extra.value().topInset = value;
+ extra.value().hasTopInset = !reset;
+ if (!qFuzzyCompare(oldInset.top(), value)) {
+ emit q->topInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextFieldPrivate::setLeftInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextField);
+ const QMarginsF oldInset = getInset();
+ extra.value().leftInset = value;
+ extra.value().hasLeftInset = !reset;
+ if (!qFuzzyCompare(oldInset.left(), value)) {
+ emit q->leftInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextFieldPrivate::setRightInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextField);
+ const QMarginsF oldInset = getInset();
+ extra.value().rightInset = value;
+ extra.value().hasRightInset = !reset;
+ if (!qFuzzyCompare(oldInset.right(), value)) {
+ emit q->rightInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextFieldPrivate::setBottomInset(qreal value, bool reset)
+{
+ Q_Q(QQuickTextField);
+ const QMarginsF oldInset = getInset();
+ extra.value().bottomInset = value;
+ extra.value().hasBottomInset = !reset;
+ if (!qFuzzyCompare(oldInset.bottom(), value)) {
+ emit q->bottomInsetChanged();
+ q->insetChange(getInset(), oldInset);
+ }
+}
+
+void QQuickTextFieldPrivate::resizeBackground()
+{
+ if (!background)
+ return;
+
+ resizingBackground = true;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (((!p->widthValid() || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x()))
+ || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) {
+ const bool wasWidthValid = p->widthValid();
+ background->setX(getLeftInset());
+ background->setWidth(width - getLeftInset() - getRightInset());
+ // If the user hadn't previously set the width, that shouldn't change when we set it for them.
+ if (!wasWidthValid)
+ p->widthValidFlag = false;
+ }
+ if (((!p->heightValid() || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y()))
+ || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) {
+ const bool wasHeightValid = p->heightValid();
+ background->setY(getTopInset());
+ background->setHeight(height - getTopInset() - getBottomInset());
+ if (!wasHeightValid)
+ p->heightValidFlag = false;
+ }
+
+ resizingBackground = false;
+}
+
+/*!
+ \internal
+
+ Determine which font is implicitly imposed on this control by its ancestors
+ and QGuiApplication::font, resolve this against its own font (attributes from
+ the implicit font are copied over). Then propagate this font to this
+ control's children.
+*/
+void QQuickTextFieldPrivate::resolveFont()
+{
+ Q_Q(QQuickTextField);
+ inheritFont(QQuickControlPrivate::parentFont(q));
+}
+
+void QQuickTextFieldPrivate::inheritFont(const QFont &font)
+{
+ QFont parentFont = extra.isAllocated() ? extra->requestedFont.resolve(font) : font;
+ parentFont.setResolveMask(extra.isAllocated() ? extra->requestedFont.resolveMask() | font.resolveMask() : font.resolveMask());
+
+ const QFont defaultFont = QQuickTheme::font(QQuickTheme::TextField);
+ QFont resolvedFont = parentFont.resolve(defaultFont);
+
+ setFont_helper(resolvedFont);
+}
+
+/*!
+ \internal
+
+ Assign \a font to this control, and propagate it to all children.
+*/
+void QQuickTextFieldPrivate::updateFont(const QFont &font)
+{
+ Q_Q(QQuickTextField);
+ QFont oldFont = sourceFont;
+ q->QQuickTextInput::setFont(font);
+
+ QQuickControlPrivate::updateFontRecur(q, font);
+
+ if (oldFont != font)
+ emit q->fontChanged();
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickTextFieldPrivate::updateHoverEnabled(bool enabled, bool xplicit)
+{
+ Q_Q(QQuickTextField);
+ if (!xplicit && explicitHoverEnabled)
+ return;
+
+ bool wasEnabled = q->isHoverEnabled();
+ explicitHoverEnabled = xplicit;
+ if (wasEnabled != enabled) {
+ q->setAcceptHoverEvents(enabled);
+ QQuickControlPrivate::updateHoverEnabledRecur(q, enabled);
+ emit q->hoverEnabledChanged();
+ }
+}
+#endif
+
+qreal QQuickTextFieldPrivate::getImplicitWidth() const
+{
+ return QQuickItemPrivate::getImplicitWidth();
+}
+
+qreal QQuickTextFieldPrivate::getImplicitHeight() const
+{
+ return QQuickItemPrivate::getImplicitHeight();
+}
+
+void QQuickTextFieldPrivate::implicitWidthChanged()
+{
+ Q_Q(QQuickTextField);
+ QQuickItemPrivate::implicitWidthChanged();
+ emit q->implicitWidthChanged3();
+}
+
+void QQuickTextFieldPrivate::implicitHeightChanged()
+{
+ Q_Q(QQuickTextField);
+ QQuickItemPrivate::implicitHeightChanged();
+ emit q->implicitHeightChanged3();
+}
+
+void QQuickTextFieldPrivate::readOnlyChanged(bool isReadOnly)
+{
+ Q_UNUSED(isReadOnly);
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(q_func()))
+ accessibleAttached->set_readOnly(isReadOnly);
+#endif
+#if QT_CONFIG(cursor)
+ q_func()->setCursor(isReadOnly && !selectByMouse ? Qt::ArrowCursor : Qt::IBeamCursor);
+#endif
+}
+
+void QQuickTextFieldPrivate::echoModeChanged(QQuickTextField::EchoMode echoMode)
+{
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(q_func()))
+ accessibleAttached->set_passwordEdit((echoMode == QQuickTextField::Password || echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false);
+#else
+ Q_UNUSED(echoMode);
+#endif
+}
+
+#if QT_CONFIG(accessibility)
+void QQuickTextFieldPrivate::accessibilityActiveChanged(bool active)
+{
+ if (!active)
+ return;
+
+ Q_Q(QQuickTextField);
+ QQuickAccessibleAttached *accessibleAttached = qobject_cast<QQuickAccessibleAttached *>(qmlAttachedPropertiesObject<QQuickAccessibleAttached>(q, true));
+ Q_ASSERT(accessibleAttached);
+ accessibleAttached->setRole(accessibleRole());
+ accessibleAttached->set_readOnly(m_readOnly);
+ accessibleAttached->set_passwordEdit((m_echoMode == QQuickTextField::Password || m_echoMode == QQuickTextField::PasswordEchoOnEdit) ? true : false);
+ accessibleAttached->setDescription(placeholder);
+}
+
+QAccessible::Role QQuickTextFieldPrivate::accessibleRole() const
+{
+ return QAccessible::EditableText;
+}
+#endif
+
+static inline QString backgroundName() { return QStringLiteral("background"); }
+
+void QQuickTextFieldPrivate::cancelBackground()
+{
+ Q_Q(QQuickTextField);
+ quickCancelDeferred(q, backgroundName());
+}
+
+void QQuickTextFieldPrivate::executeBackground(bool complete)
+{
+ Q_Q(QQuickTextField);
+ if (background.wasExecuted())
+ return;
+
+ if (!background || complete)
+ quickBeginDeferred(q, backgroundName(), background);
+ if (complete)
+ quickCompleteDeferred(q, backgroundName(), background);
+}
+
+void QQuickTextFieldPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ Q_UNUSED(diff);
+ if (resizingBackground || item != background || !change.sizeChange())
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ // QTBUG-71875: only allocate the extra data if we have to.
+ // resizeBackground() relies on the value of extra.isAllocated()
+ // as part of its checks to see whether it should resize the background or not.
+ if (p->widthValid() || extra.isAllocated())
+ extra.value().hasBackgroundWidth = p->widthValid();
+ if (p->heightValid() || extra.isAllocated())
+ extra.value().hasBackgroundHeight = p->heightValid();
+ resizeBackground();
+}
+
+void QQuickTextFieldPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_Q(QQuickTextField);
+ if (item == background)
+ emit q->implicitBackgroundWidthChanged();
+}
+
+void QQuickTextFieldPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_Q(QQuickTextField);
+ if (item == background)
+ emit q->implicitBackgroundHeightChanged();
+}
+
+void QQuickTextFieldPrivate::itemDestroyed(QQuickItem *item)
+{
+ Q_Q(QQuickTextField);
+ if (item == background) {
+ background = nullptr;
+ emit q->implicitBackgroundWidthChanged();
+ emit q->implicitBackgroundHeightChanged();
+ }
+}
+
+QPalette QQuickTextFieldPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::TextField);
+}
+
+QQuickTextField::QQuickTextField(QQuickItem *parent)
+ : QQuickTextInput(*(new QQuickTextFieldPrivate), parent)
+{
+ Q_D(QQuickTextField);
+ d->pressHandler.control = this;
+ d->setImplicitResizeEnabled(false);
+ setAcceptedMouseButtons(Qt::AllButtons);
+ setActiveFocusOnTab(true);
+#if QT_CONFIG(cursor)
+ setCursor(Qt::IBeamCursor);
+#endif
+ QObjectPrivate::connect(this, &QQuickTextInput::readOnlyChanged, d, &QQuickTextFieldPrivate::readOnlyChanged);
+ QObjectPrivate::connect(this, &QQuickTextInput::echoModeChanged, d, &QQuickTextFieldPrivate::echoModeChanged);
+}
+
+QQuickTextField::~QQuickTextField()
+{
+ Q_D(QQuickTextField);
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+}
+
+QFont QQuickTextField::font() const
+{
+ return QQuickTextInput::font();
+}
+
+void QQuickTextField::setFont(const QFont &font)
+{
+ Q_D(QQuickTextField);
+ if (d->extra.value().requestedFont.resolveMask() == font.resolveMask() && d->extra.value().requestedFont == font)
+ return;
+
+ d->extra.value().requestedFont = font;
+ d->resolveFont();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::TextField::background
+
+ This property holds the background item.
+
+ \input qquickcontrol-background.qdocinc notes
+
+ \sa {Customizing TextField}
+*/
+QQuickItem *QQuickTextField::background() const
+{
+ QQuickTextFieldPrivate *d = const_cast<QQuickTextFieldPrivate *>(d_func());
+ if (!d->background)
+ d->executeBackground();
+ return d->background;
+}
+
+void QQuickTextField::setBackground(QQuickItem *background)
+{
+ Q_D(QQuickTextField);
+ if (d->background == background)
+ return;
+
+ if (!d->background.isExecuting())
+ d->cancelBackground();
+
+ const qreal oldImplicitBackgroundWidth = implicitBackgroundWidth();
+ const qreal oldImplicitBackgroundHeight = implicitBackgroundHeight();
+
+ if (d->extra.isAllocated()) {
+ d->extra.value().hasBackgroundWidth = false;
+ d->extra.value().hasBackgroundHeight = false;
+ }
+
+ QQuickControlPrivate::removeImplicitSizeListener(d->background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ QQuickControlPrivate::hideOldItem(d->background);
+ d->background = background;
+
+ if (background) {
+ background->setParentItem(this);
+ if (qFuzzyIsNull(background->z()))
+ background->setZ(-1);
+ QQuickItemPrivate *p = QQuickItemPrivate::get(background);
+ if (p->widthValid() || p->heightValid()) {
+ d->extra.value().hasBackgroundWidth = p->widthValid();
+ d->extra.value().hasBackgroundHeight = p->heightValid();
+ }
+ if (isComponentComplete())
+ d->resizeBackground();
+ QQuickControlPrivate::addImplicitSizeListener(background, d, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry);
+ }
+
+ if (!qFuzzyCompare(oldImplicitBackgroundWidth, implicitBackgroundWidth()))
+ emit implicitBackgroundWidthChanged();
+ if (!qFuzzyCompare(oldImplicitBackgroundHeight, implicitBackgroundHeight()))
+ emit implicitBackgroundHeightChanged();
+ if (!d->background.isExecuting())
+ emit backgroundChanged();
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::TextField::placeholderText
+
+ This property holds the hint that is displayed in the TextField before the user
+ enters text.
+*/
+QString QQuickTextField::placeholderText() const
+{
+ Q_D(const QQuickTextField);
+ return d->placeholder;
+}
+
+void QQuickTextField::setPlaceholderText(const QString &text)
+{
+ Q_D(QQuickTextField);
+ if (d->placeholder == text)
+ return;
+
+ d->placeholder = text;
+#if QT_CONFIG(accessibility)
+ if (QQuickAccessibleAttached *accessibleAttached = QQuickControlPrivate::accessibleAttached(this))
+ accessibleAttached->setDescription(text);
+#endif
+ emit placeholderTextChanged();
+}
+
+/*!
+ \qmlproperty color QtQuick.Controls::TextField::placeholderTextColor
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+
+ This property holds the color of placeholderText.
+
+ \sa placeholderText
+*/
+QColor QQuickTextField::placeholderTextColor() const
+{
+ Q_D(const QQuickTextField);
+ return d->placeholderColor;
+}
+
+void QQuickTextField::setPlaceholderTextColor(const QColor &color)
+{
+ Q_D(QQuickTextField);
+ if (d->placeholderColor == color)
+ return;
+
+ d->placeholderColor = color;
+ emit placeholderTextColorChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::TextField::focusReason
+
+ \include qquickcontrol-focusreason.qdocinc
+*/
+Qt::FocusReason QQuickTextField::focusReason() const
+{
+ Q_D(const QQuickTextField);
+ return d->focusReason;
+}
+
+void QQuickTextField::setFocusReason(Qt::FocusReason reason)
+{
+ Q_D(QQuickTextField);
+ if (d->focusReason == reason)
+ return;
+
+ d->focusReason = reason;
+ emit focusReasonChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::TextField::hovered
+ \readonly
+
+ This property holds whether the text field is hovered.
+
+ \sa hoverEnabled
+*/
+bool QQuickTextField::isHovered() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickTextField);
+ return d->hovered;
+#else
+ return false;
+#endif
+}
+
+void QQuickTextField::setHovered(bool hovered)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextField);
+ if (hovered == d->hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+#else
+ Q_UNUSED(hovered);
+#endif
+}
+
+/*!
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+ \qmlproperty bool QtQuick.Controls::TextField::hoverEnabled
+
+ This property determines whether the text field accepts hover events. The default value is \c false.
+
+ \sa hovered
+*/
+bool QQuickTextField::isHoverEnabled() const
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(const QQuickTextField);
+ return d->hoverEnabled;
+#else
+ return false;
+#endif
+}
+
+void QQuickTextField::setHoverEnabled(bool enabled)
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextField);
+ if (d->explicitHoverEnabled && enabled == d->hoverEnabled)
+ return;
+
+ d->updateHoverEnabled(enabled, true); // explicit=true
+#else
+ Q_UNUSED(enabled);
+#endif
+}
+
+void QQuickTextField::resetHoverEnabled()
+{
+#if QT_CONFIG(quicktemplates2_hover)
+ Q_D(QQuickTextField);
+ if (!d->explicitHoverEnabled)
+ return;
+
+ d->explicitHoverEnabled = false;
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+}
+
+void QQuickTextField::classBegin()
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::classBegin();
+ d->resolveFont();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::implicitBackgroundWidth
+ \readonly
+
+ This property holds the implicit background width.
+
+ The value is equal to \c {background ? background.implicitWidth : 0}.
+
+ \sa implicitBackgroundHeight
+*/
+qreal QQuickTextField::implicitBackgroundWidth() const
+{
+ Q_D(const QQuickTextField);
+ if (!d->background)
+ return 0;
+ return d->background->implicitWidth();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::implicitBackgroundHeight
+ \readonly
+
+ This property holds the implicit background height.
+
+ The value is equal to \c {background ? background.implicitHeight : 0}.
+
+ \sa implicitBackgroundWidth
+*/
+qreal QQuickTextField::implicitBackgroundHeight() const
+{
+ Q_D(const QQuickTextField);
+ if (!d->background)
+ return 0;
+ return d->background->implicitHeight();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::topInset
+
+ This property holds the top inset for the background.
+
+ \sa {Control Layout}, bottomInset
+*/
+qreal QQuickTextField::topInset() const
+{
+ Q_D(const QQuickTextField);
+ return d->getTopInset();
+}
+
+void QQuickTextField::setTopInset(qreal inset)
+{
+ Q_D(QQuickTextField);
+ d->setTopInset(inset);
+}
+
+void QQuickTextField::resetTopInset()
+{
+ Q_D(QQuickTextField);
+ d->setTopInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::leftInset
+
+ This property holds the left inset for the background.
+
+ \sa {Control Layout}, rightInset
+*/
+qreal QQuickTextField::leftInset() const
+{
+ Q_D(const QQuickTextField);
+ return d->getLeftInset();
+}
+
+void QQuickTextField::setLeftInset(qreal inset)
+{
+ Q_D(QQuickTextField);
+ d->setLeftInset(inset);
+}
+
+void QQuickTextField::resetLeftInset()
+{
+ Q_D(QQuickTextField);
+ d->setLeftInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::rightInset
+
+ This property holds the right inset for the background.
+
+ \sa {Control Layout}, leftInset
+*/
+qreal QQuickTextField::rightInset() const
+{
+ Q_D(const QQuickTextField);
+ return d->getRightInset();
+}
+
+void QQuickTextField::setRightInset(qreal inset)
+{
+ Q_D(QQuickTextField);
+ d->setRightInset(inset);
+}
+
+void QQuickTextField::resetRightInset()
+{
+ Q_D(QQuickTextField);
+ d->setRightInset(0, true);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlproperty real QtQuick.Controls::TextField::bottomInset
+
+ This property holds the bottom inset for the background.
+
+ \sa {Control Layout}, topInset
+*/
+qreal QQuickTextField::bottomInset() const
+{
+ Q_D(const QQuickTextField);
+ return d->getBottomInset();
+}
+
+void QQuickTextField::setBottomInset(qreal inset)
+{
+ Q_D(QQuickTextField);
+ d->setBottomInset(inset);
+}
+
+void QQuickTextField::resetBottomInset()
+{
+ Q_D(QQuickTextField);
+ d->setBottomInset(0, true);
+}
+
+void QQuickTextField::componentComplete()
+{
+ Q_D(QQuickTextField);
+ d->executeBackground(true);
+ QQuickTextInput::componentComplete();
+ d->resizeBackground();
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ setAcceptHoverEvents(QQuickControlPrivate::calcHoverEnabled(d->parentItem));
+#endif
+#if QT_CONFIG(accessibility)
+ if (QAccessible::isActive())
+ d->accessibilityActiveChanged(true);
+#endif
+}
+
+void QQuickTextField::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::itemChange(change, value);
+ switch (change) {
+ case ItemEnabledHasChanged:
+ break;
+ case ItemSceneChange:
+ case ItemParentHasChanged:
+ if ((change == ItemParentHasChanged && value.item) || (change == ItemSceneChange && value.window)) {
+ d->resolveFont();
+#if QT_CONFIG(quicktemplates2_hover)
+ if (!d->explicitHoverEnabled)
+ d->updateHoverEnabled(QQuickControlPrivate::calcHoverEnabled(d->parentItem), false); // explicit=false
+#endif
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void QQuickTextField::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::geometryChange(newGeometry, oldGeometry);
+ d->resizeBackground();
+}
+
+void QQuickTextField::insetChange(const QMarginsF &newInset, const QMarginsF &oldInset)
+{
+ Q_D(QQuickTextField);
+ Q_UNUSED(newInset);
+ Q_UNUSED(oldInset);
+ d->resizeBackground();
+}
+QSGNode *QQuickTextField::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ QQuickDefaultClipNode *clipNode = static_cast<QQuickDefaultClipNode *>(oldNode);
+ if (!clipNode)
+ clipNode = new QQuickDefaultClipNode(QRectF());
+
+ clipNode->setRect(clipRect().adjusted(leftPadding(), topPadding(), -rightPadding(), -bottomPadding()));
+ clipNode->update();
+
+ QSGNode *textNode = QQuickTextInput::updatePaintNode(clipNode->firstChild(), data);
+ if (!textNode->parent())
+ clipNode->appendChildNode(textNode);
+
+ return clipNode;
+}
+
+void QQuickTextField::focusInEvent(QFocusEvent *event)
+{
+ QQuickTextInput::focusInEvent(event);
+ setFocusReason(event->reason());
+}
+
+void QQuickTextField::focusOutEvent(QFocusEvent *event)
+{
+ QQuickTextInput::focusOutEvent(event);
+ setFocusReason(event->reason());
+}
+
+#if QT_CONFIG(quicktemplates2_hover)
+void QQuickTextField::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::hoverEnterEvent(event);
+ setHovered(d->hoverEnabled);
+ event->ignore();
+}
+
+void QQuickTextField::hoverLeaveEvent(QHoverEvent *event)
+{
+ QQuickTextInput::hoverLeaveEvent(event);
+ setHovered(false);
+ event->ignore();
+}
+#endif
+
+void QQuickTextField::mousePressEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextField);
+ d->pressHandler.mousePressEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ if (event->buttons() != Qt::RightButton)
+ QQuickTextInput::mousePressEvent(event);
+ }
+}
+
+void QQuickTextField::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextField);
+ d->pressHandler.mouseMoveEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ if (event->buttons() != Qt::RightButton)
+ QQuickTextInput::mouseMoveEvent(event);
+ }
+}
+
+void QQuickTextField::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextField);
+ d->pressHandler.mouseReleaseEvent(event);
+ if (d->pressHandler.isActive()) {
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ if (event->buttons() != Qt::RightButton)
+ QQuickTextInput::mouseReleaseEvent(event);
+ }
+}
+
+void QQuickTextField::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ Q_D(QQuickTextField);
+ if (d->pressHandler.delayedMousePressEvent) {
+ QQuickTextInput::mousePressEvent(d->pressHandler.delayedMousePressEvent);
+ d->pressHandler.clearDelayedMouseEvent();
+ }
+ if (event->buttons() != Qt::RightButton)
+ QQuickTextInput::mouseDoubleClickEvent(event);
+}
+
+void QQuickTextField::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickTextField);
+ if (event->timerId() == d->pressHandler.timer.timerId())
+ d->pressHandler.timerEvent(event);
+ else
+ QQuickTextInput::timerEvent(event);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktextfield_p.cpp"
diff --git a/src/quicktemplates2/qquicktextfield_p.h b/src/quicktemplates2/qquicktextfield_p.h
new file mode 100644
index 0000000000..a1d433c0b2
--- /dev/null
+++ b/src/quicktemplates2/qquicktextfield_p.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTFIELD_P_H
+#define QQUICKTEXTFIELD_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/qpalette.h>
+#include <QtQuick/private/qquicktextinput_p.h>
+#include <QtQuick/private/qquickevents_p_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTextFieldPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTextField : public QQuickTextInput
+{
+ Q_OBJECT
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) // override
+ Q_PROPERTY(qreal implicitWidth READ implicitWidth WRITE setImplicitWidth NOTIFY implicitWidthChanged3 FINAL)
+ Q_PROPERTY(qreal implicitHeight READ implicitHeight WRITE setImplicitHeight NOTIFY implicitHeightChanged3 FINAL)
+ Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
+ Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL)
+ Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL REVISION(2, 1))
+ Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled RESET resetHoverEnabled NOTIFY hoverEnabledChanged FINAL REVISION(2, 1))
+ // 2.5 (Qt 5.12)
+ Q_PROPERTY(QColor placeholderTextColor READ placeholderTextColor WRITE setPlaceholderTextColor NOTIFY placeholderTextColorChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundWidth READ implicitBackgroundWidth NOTIFY implicitBackgroundWidthChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal implicitBackgroundHeight READ implicitBackgroundHeight NOTIFY implicitBackgroundHeightChanged FINAL REVISION(2, 5))
+ Q_PROPERTY(qreal topInset READ topInset WRITE setTopInset RESET resetTopInset NOTIFY topInsetChanged FINAL REVISION(2, 5))
+ 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_CLASSINFO("DeferredPropertyNames", "background")
+ QML_NAMED_ELEMENT(TextField)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickTextField(QQuickItem *parent = nullptr);
+ ~QQuickTextField();
+
+ QFont font() const;
+ void setFont(const QFont &font);
+
+ QQuickItem *background() const;
+ void setBackground(QQuickItem *background);
+
+ QString placeholderText() const;
+ void setPlaceholderText(const QString &text);
+
+ Qt::FocusReason focusReason() const;
+ void setFocusReason(Qt::FocusReason reason);
+
+ // 2.1 (Qt 5.8)
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ bool isHoverEnabled() const;
+ void setHoverEnabled(bool enabled);
+ void resetHoverEnabled();
+
+ // 2.5 (Qt 5.12)
+ QColor placeholderTextColor() const;
+ void setPlaceholderTextColor(const QColor &color);
+
+ qreal implicitBackgroundWidth() const;
+ qreal implicitBackgroundHeight() const;
+
+ qreal topInset() const;
+ void setTopInset(qreal inset);
+ void resetTopInset();
+
+ qreal leftInset() const;
+ void setLeftInset(qreal inset);
+ void resetLeftInset();
+
+ qreal rightInset() const;
+ void setRightInset(qreal inset);
+ void resetRightInset();
+
+ qreal bottomInset() const;
+ void setBottomInset(qreal inset);
+ void resetBottomInset();
+
+Q_SIGNALS:
+ void fontChanged();
+ void implicitWidthChanged3();
+ void implicitHeightChanged3();
+ void backgroundChanged();
+ void placeholderTextChanged();
+ void focusReasonChanged();
+ void pressAndHold(QQuickMouseEvent *event);
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void pressed(QQuickMouseEvent *event);
+ Q_REVISION(2, 1) void released(QQuickMouseEvent *event);
+ Q_REVISION(2, 1) void hoveredChanged();
+ Q_REVISION(2, 1) void hoverEnabledChanged();
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) void placeholderTextColorChanged();
+ Q_REVISION(2, 5) void implicitBackgroundWidthChanged();
+ Q_REVISION(2, 5) void implicitBackgroundHeightChanged();
+ Q_REVISION(2, 5) void topInsetChanged();
+ Q_REVISION(2, 5) void leftInsetChanged();
+ Q_REVISION(2, 5) void rightInsetChanged();
+ Q_REVISION(2, 5) void bottomInsetChanged();
+
+protected:
+ friend struct QQuickPressHandler;
+
+ void classBegin() override;
+ void componentComplete() override;
+
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ virtual void insetChange(const QMarginsF &newInset, const QMarginsF &oldInset);
+
+ QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data) override;
+
+ void focusInEvent(QFocusEvent *event) override;
+ void focusOutEvent(QFocusEvent *event) override;
+#if QT_CONFIG(quicktemplates2_hover)
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
+#endif
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
+ void mouseDoubleClickEvent(QMouseEvent *event) override;
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ Q_DISABLE_COPY(QQuickTextField)
+ Q_DECLARE_PRIVATE(QQuickTextField)
+};
+
+struct QQuickTextFieldForeign
+{
+ Q_GADGET
+ QML_ANONYMOUS
+ QML_FOREIGN(QQuickTextInput)
+ QML_ADDED_IN_VERSION(2, 2)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTextField)
+
+#endif // QQUICKTEXTFIELD_P_H
diff --git a/src/quicktemplates2/qquicktextfield_p_p.h b/src/quicktemplates2/qquicktextfield_p_p.h
new file mode 100644
index 0000000000..d81289726b
--- /dev/null
+++ b/src/quicktemplates2/qquicktextfield_p_p.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTEXTFIELD_P_P_H
+#define QQUICKTEXTFIELD_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 <QtQml/private/qlazilyallocated_p.h>
+#include <QtQuick/private/qquicktextinput_p_p.h>
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickpresshandler_p_p.h>
+#include <QtQuickTemplates2/private/qquickdeferredpointer_p_p.h>
+#include <QtQuickTemplates2/private/qquicktheme_p.h>
+
+#include <QtQuickTemplates2/private/qquicktextfield_p.h>
+
+#if QT_CONFIG(accessibility)
+#include <QtGui/qaccessible.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTextFieldPrivate : public QQuickTextInputPrivate, public QQuickItemChangeListener
+#if QT_CONFIG(accessibility)
+ , public QAccessible::ActivationObserver
+#endif
+{
+ Q_DECLARE_PUBLIC(QQuickTextField)
+
+public:
+ QQuickTextFieldPrivate();
+ ~QQuickTextFieldPrivate();
+
+ static QQuickTextFieldPrivate *get(QQuickTextField *item) {
+ return static_cast<QQuickTextFieldPrivate *>(QObjectPrivate::get(item)); }
+
+ inline QMarginsF getInset() const { return QMarginsF(getLeftInset(), getTopInset(), getRightInset(), getBottomInset()); }
+ inline qreal getTopInset() const { return extra.isAllocated() ? extra->topInset : 0; }
+ inline qreal getLeftInset() const { return extra.isAllocated() ? extra->leftInset : 0; }
+ inline qreal getRightInset() const { return extra.isAllocated() ? extra->rightInset : 0; }
+ inline qreal getBottomInset() const { return extra.isAllocated() ? extra->bottomInset : 0; }
+
+ void setTopInset(qreal value, bool reset = false);
+ void setLeftInset(qreal value, bool reset = false);
+ void setRightInset(qreal value, bool reset = false);
+ void setBottomInset(qreal value, bool reset = false);
+
+ void resizeBackground();
+
+ void resolveFont();
+ void inheritFont(const QFont &font);
+ void updateFont(const QFont &font);
+ inline void setFont_helper(const QFont &font) {
+ if (sourceFont.resolveMask() == font.resolveMask() && sourceFont == font)
+ return;
+ updateFont(font);
+ }
+
+#if QT_CONFIG(quicktemplates2_hover)
+ void updateHoverEnabled(bool h, bool e);
+#endif
+
+ qreal getImplicitWidth() const override;
+ qreal getImplicitHeight() const override;
+
+ void implicitWidthChanged() override;
+ void implicitHeightChanged() override;
+
+ void readOnlyChanged(bool isReadOnly);
+ void echoModeChanged(QQuickTextField::EchoMode echoMode);
+
+#if QT_CONFIG(accessibility)
+ void accessibilityActiveChanged(bool active) override;
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+ void cancelBackground();
+ void executeBackground(bool complete = false);
+
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QPalette defaultPalette() const override;
+
+#if QT_CONFIG(quicktemplates2_hover)
+ bool hovered = false;
+ bool explicitHoverEnabled = false;
+#endif
+
+ struct ExtraData {
+ bool hasTopInset = false;
+ bool hasLeftInset = false;
+ bool hasRightInset = false;
+ bool hasBottomInset = false;
+ bool hasBackgroundWidth = false;
+ bool hasBackgroundHeight = false;
+ qreal topInset = 0;
+ qreal leftInset = 0;
+ qreal rightInset = 0;
+ qreal bottomInset = 0;
+ QFont requestedFont;
+ };
+ QLazilyAllocated<ExtraData> extra;
+
+ bool resizingBackground = false;
+ QQuickDeferredPointer<QQuickItem> background;
+ QString placeholder;
+ QColor placeholderColor;
+ Qt::FocusReason focusReason = Qt::OtherFocusReason;
+ QQuickPressHandler pressHandler;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTEXTFIELD_P_P_H
diff --git a/src/quicktemplates2/qquicktheme.cpp b/src/quicktemplates2/qquicktheme.cpp
new file mode 100644
index 0000000000..b94b419845
--- /dev/null
+++ b/src/quicktemplates2/qquicktheme.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktheme_p.h"
+#include "qquicktheme_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+std::unique_ptr<QQuickTheme> QQuickThemePrivate::instance;
+
+static void cleanup_instance()
+{
+ QQuickThemePrivate::instance.reset();
+}
+
+static void install_instance_cleanuper()
+{
+ qAddPostRoutine(cleanup_instance);
+}
+
+Q_COREAPP_STARTUP_FUNCTION(install_instance_cleanuper)
+
+static QPlatformTheme::Font platformFont(QQuickTheme::Scope scope)
+{
+ switch (scope) {
+ case QQuickTheme::Button: return QPlatformTheme::PushButtonFont;
+ case QQuickTheme::CheckBox: return QPlatformTheme::CheckBoxFont;
+ case QQuickTheme::ComboBox: return QPlatformTheme::ComboMenuItemFont;
+ case QQuickTheme::GroupBox: return QPlatformTheme::GroupBoxTitleFont;
+ case QQuickTheme::ItemView: return QPlatformTheme::ItemViewFont;
+ case QQuickTheme::Label: return QPlatformTheme::LabelFont;
+ case QQuickTheme::ListView: return QPlatformTheme::ListViewFont;
+ case QQuickTheme::Menu: return QPlatformTheme::MenuFont;
+ case QQuickTheme::MenuBar: return QPlatformTheme::MenuBarFont;
+ case QQuickTheme::RadioButton: return QPlatformTheme::RadioButtonFont;
+ case QQuickTheme::SpinBox: return QPlatformTheme::EditorFont;
+ case QQuickTheme::Switch: return QPlatformTheme::CheckBoxFont;
+ case QQuickTheme::TabBar: return QPlatformTheme::TabButtonFont;
+ case QQuickTheme::TextArea: return QPlatformTheme::EditorFont;
+ case QQuickTheme::TextField: return QPlatformTheme::EditorFont;
+ case QQuickTheme::ToolBar: return QPlatformTheme::ToolButtonFont;
+ case QQuickTheme::ToolTip: return QPlatformTheme::TipLabelFont;
+ case QQuickTheme::Tumbler: return QPlatformTheme::ItemViewFont;
+ default: return QPlatformTheme::SystemFont;
+ }
+}
+
+static QPlatformTheme::Palette platformPalette(QQuickTheme::Scope scope)
+{
+ switch (scope) {
+ case QQuickTheme::Button: return QPlatformTheme::ButtonPalette;
+ case QQuickTheme::CheckBox: return QPlatformTheme::CheckBoxPalette;
+ case QQuickTheme::ComboBox: return QPlatformTheme::ComboBoxPalette;
+ case QQuickTheme::GroupBox: return QPlatformTheme::GroupBoxPalette;
+ case QQuickTheme::ItemView: return QPlatformTheme::ItemViewPalette;
+ case QQuickTheme::Label: return QPlatformTheme::LabelPalette;
+ case QQuickTheme::ListView: return QPlatformTheme::ItemViewPalette;
+ case QQuickTheme::Menu: return QPlatformTheme::MenuPalette;
+ case QQuickTheme::MenuBar: return QPlatformTheme::MenuBarPalette;
+ case QQuickTheme::RadioButton: return QPlatformTheme::RadioButtonPalette;
+ case QQuickTheme::SpinBox: return QPlatformTheme::TextLineEditPalette;
+ case QQuickTheme::Switch: return QPlatformTheme::CheckBoxPalette;
+ case QQuickTheme::TabBar: return QPlatformTheme::TabBarPalette;
+ case QQuickTheme::TextArea: return QPlatformTheme::TextEditPalette;
+ case QQuickTheme::TextField: return QPlatformTheme::TextLineEditPalette;
+ case QQuickTheme::ToolBar: return QPlatformTheme::ToolButtonPalette;
+ case QQuickTheme::ToolTip: return QPlatformTheme::ToolTipPalette;
+ case QQuickTheme::Tumbler: return QPlatformTheme::ItemViewPalette;
+ default: return QPlatformTheme::SystemPalette;
+ }
+}
+
+QQuickTheme::QQuickTheme()
+ : d_ptr(new QQuickThemePrivate)
+{
+}
+
+QQuickTheme::~QQuickTheme()
+{
+}
+
+QQuickTheme *QQuickTheme::instance()
+{
+ return QQuickThemePrivate::instance.get();
+}
+
+QFont QQuickTheme::font(Scope scope)
+{
+ const QFont *font = nullptr;
+ if (QQuickTheme *theme = instance())
+ font = QQuickThemePrivate::get(theme)->fonts[scope].data();
+ else if (QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ font = theme->font(platformFont(scope));
+
+ if (font) {
+ QFont f = *font;
+ if (scope == System)
+ f.setResolveMask(0);
+ return f;
+ }
+
+ if (scope != System)
+ return QQuickTheme::font(System);
+
+ return QFont();
+}
+
+QPalette QQuickTheme::palette(Scope scope)
+{
+ const QPalette *palette = nullptr;
+ if (QQuickTheme *theme = instance())
+ palette = QQuickThemePrivate::get(theme)->palettes[scope].data();
+ else if (QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
+ palette = theme->palette(platformPalette(scope));
+
+ if (palette) {
+ QPalette f = *palette;
+ if (scope == System)
+ f.setResolveMask(0);
+ return f;
+ }
+
+ if (scope != System)
+ return QQuickTheme::palette(System);
+
+ return QPalette();
+}
+
+void QQuickTheme::setFont(Scope scope, const QFont &font)
+{
+ Q_D(QQuickTheme);
+ d->fonts[scope] = QSharedPointer<QFont>::create(d->defaultFont ? d->defaultFont->resolve(font) : font);
+}
+
+void QQuickTheme::setPalette(Scope scope, const QPalette &palette)
+{
+ Q_D(QQuickTheme);
+ d->palettes[scope] = QSharedPointer<QPalette>::create(d->defaultPalette ? d->defaultPalette->resolve(palette) : palette);
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquicktheme_p.h b/src/quicktemplates2/qquicktheme_p.h
new file mode 100644
index 0000000000..d51cc5b658
--- /dev/null
+++ b/src/quicktemplates2/qquicktheme_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTHEME_P_H
+#define QQUICKTHEME_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 <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qpalette.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickThemePrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTheme
+{
+public:
+ QQuickTheme();
+ ~QQuickTheme();
+
+ static QQuickTheme *instance();
+
+ enum Scope {
+ System,
+ Button,
+ CheckBox,
+ ComboBox,
+ GroupBox,
+ ItemView,
+ Label,
+ ListView,
+ Menu,
+ MenuBar,
+ RadioButton,
+ SpinBox,
+ Switch,
+ TabBar,
+ TextArea,
+ TextField,
+ ToolBar,
+ ToolTip,
+ Tumbler
+ };
+
+ static QFont font(Scope scope);
+ static QPalette palette(Scope scope);
+
+ void setFont(Scope scope, const QFont &font);
+ void setPalette(Scope scope, const QPalette &palette);
+
+private:
+ Q_DISABLE_COPY(QQuickTheme)
+ Q_DECLARE_PRIVATE(QQuickTheme)
+ QScopedPointer<QQuickThemePrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTHEME_P_H
diff --git a/src/quicktemplates2/qquicktheme_p_p.h b/src/quicktemplates2/qquicktheme_p_p.h
new file mode 100644
index 0000000000..b2c40eeb41
--- /dev/null
+++ b/src/quicktemplates2/qquicktheme_p_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTHEME_P_P_H
+#define QQUICKTHEME_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 <QtQuickTemplates2/private/qquicktheme_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickThemePrivate
+{
+public:
+ static QQuickThemePrivate *get(QQuickTheme *theme)
+ {
+ return theme->d_func();
+ }
+
+ static std::unique_ptr<QQuickTheme> instance;
+
+ static const int NScopes = QQuickTheme::Tumbler + 1;
+
+ QScopedPointer<const QFont> defaultFont;
+ QScopedPointer<const QPalette> defaultPalette;
+ QSharedPointer<QFont> fonts[NScopes];
+ QSharedPointer<QPalette> palettes[NScopes];
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTHEME_P_P_H
diff --git a/src/quicktemplates2/qquicktoolbar.cpp b/src/quicktemplates2/qquicktoolbar.cpp
new file mode 100644
index 0000000000..ea08d84930
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolbar.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktoolbar_p.h"
+#include "qquickpane_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ToolBar
+ \inherits Pane
+//! \instantiates QQuickToolBar
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-containers
+ \brief Container for context-sensitive controls.
+
+ ToolBar is a container of application-wide and context sensitive
+ actions and controls, such as navigation buttons and search fields.
+ ToolBar is commonly used as a \l {ApplicationWindow::header}{header}
+ or a \l {ApplicationWindow::footer}{footer} of an \l ApplicationWindow.
+
+ ToolBar does not provide a layout of its own, but requires you to
+ position its contents, for instance by creating a \l RowLayout. If only
+ a single item is used within the ToolBar, it will resize to fit the
+ implicit size of its contained item. This makes it particularly suitable
+ for use together with layouts.
+
+ \image qtquickcontrols2-toolbar.png
+
+ \code
+ ApplicationWindow {
+ visible:true
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ ToolButton {
+ text: qsTr("‹")
+ onClicked: stack.pop()
+ }
+ Label {
+ text: "Title"
+ elide: Label.ElideRight
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ Layout.fillWidth: true
+ }
+ ToolButton {
+ text: qsTr("â‹®")
+ onClicked: menu.open()
+ }
+ }
+ }
+
+ StackView {
+ id: stack
+ anchors.fill: parent
+ }
+ }
+ \endcode
+
+ \sa ApplicationWindow, ToolButton, {Customizing ToolBar}, {Container Controls}
+*/
+
+class QQuickToolBarPrivate : public QQuickPanePrivate
+{
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolBar); }
+
+ QQuickToolBar::Position position = QQuickToolBar::Header;
+};
+
+QQuickToolBar::QQuickToolBar(QQuickItem *parent)
+ : QQuickPane(*(new QQuickToolBarPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::ToolBar::position
+
+ This property holds the position of the toolbar.
+
+ \note If the toolbar is assigned as a header or footer of \l ApplicationWindow
+ or \l Page, the appropriate position is set automatically.
+
+ Possible values:
+ \value ToolBar.Header The toolbar is at the top, as a window or page header.
+ \value ToolBar.Footer The toolbar is at the bottom, as a window or page footer.
+
+ The default value is style-specific.
+
+ \sa ApplicationWindow::header, ApplicationWindow::footer, Page::header, Page::footer
+*/
+QQuickToolBar::Position QQuickToolBar::position() const
+{
+ Q_D(const QQuickToolBar);
+ return d->position;
+}
+
+void QQuickToolBar::setPosition(Position position)
+{
+ Q_D(QQuickToolBar);
+ if (d->position == position)
+ return;
+
+ d->position = position;
+ emit positionChanged();
+}
+
+QFont QQuickToolBar::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ToolBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickToolBar::accessibleRole() const
+{
+ return QAccessible::ToolBar;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktoolbar_p.cpp"
diff --git a/src/quicktemplates2/qquicktoolbar_p.h b/src/quicktemplates2/qquicktoolbar_p.h
new file mode 100644
index 0000000000..cefdeaa14a
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolbar_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTOOLBAR_P_H
+#define QQUICKTOOLBAR_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 <QtQuickTemplates2/private/qquickpane_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickToolBarPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolBar : public QQuickPane
+{
+ Q_OBJECT
+ Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ QML_NAMED_ELEMENT(ToolBar)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickToolBar(QQuickItem *parent = nullptr);
+
+ enum Position {
+ Header,
+ Footer
+ };
+ Q_ENUM(Position)
+
+ Position position() const;
+ void setPosition(Position position);
+
+Q_SIGNALS:
+ void positionChanged();
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickToolBar)
+ Q_DECLARE_PRIVATE(QQuickToolBar)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickToolBar)
+
+#endif // QQUICKTOOLBAR_P_H
diff --git a/src/quicktemplates2/qquicktoolbutton.cpp b/src/quicktemplates2/qquicktoolbutton.cpp
new file mode 100644
index 0000000000..100cf06a09
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolbutton.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktoolbutton_p.h"
+#include "qquickcontrol_p_p.h"
+#include "qquickbutton_p_p.h"
+
+#include <QtGui/qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ToolButton
+ \inherits Button
+//! \instantiates QQuickToolButton
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-buttons
+ \brief Button with a look suitable for a ToolBar.
+
+ ToolButton is functionally similar to \l Button, but provides a look that
+ is more suitable within a \l ToolBar.
+
+ \image qtquickcontrols2-toolbar.png
+
+ \snippet qtquickcontrols2-toolbar.qml 1
+
+ ToolButton inherits its API from AbstractButton. For instance, you can set
+ \l {AbstractButton::text}{text}, display an \l {Icons in Qt Quick Controls}{icon},
+ and react to \l {AbstractButton::clicked}{clicks} using the AbstractButton API.
+
+ \sa ToolBar, {Customizing ToolButton}, {Button Controls}
+*/
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolPrivate : public QQuickButtonPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickToolButton)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolBar); }
+};
+
+QQuickToolButton::QQuickToolButton(QQuickItem *parent)
+ : QQuickButton(*(new QQuickToolPrivate), parent)
+{
+}
+
+QFont QQuickToolButton::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ToolBar);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktoolbutton_p.cpp"
diff --git a/src/quicktemplates2/qquicktoolbutton_p.h b/src/quicktemplates2/qquicktoolbutton_p.h
new file mode 100644
index 0000000000..2db052f640
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolbutton_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTOOLBUTTON_P_H
+#define QQUICKTOOLBUTTON_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 <QtQuickTemplates2/private/qquickbutton_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickToolButtonPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolButton : public QQuickButton
+{
+ Q_OBJECT
+ QML_NAMED_ELEMENT(ToolButton)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickToolButton(QQuickItem *parent = nullptr);
+
+protected:
+ QFont defaultFont() const override;
+
+private:
+ Q_DECLARE_PRIVATE(QQuickToolButton)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickToolButton)
+
+#endif // QQUICKTOOLBUTTON_P_H
diff --git a/src/quicktemplates2/qquicktoolseparator.cpp b/src/quicktemplates2/qquicktoolseparator.cpp
new file mode 100644
index 0000000000..21d496434a
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolseparator.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktoolseparator_p.h"
+
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ToolSeparator
+ \inherits Control
+//! \instantiates QQuickToolSeparator
+ \inqmlmodule QtQuick.Controls
+ \since 5.8
+ \ingroup qtquickcontrols2-separators
+ \brief Separates a group of items in a toolbar from adjacent items.
+
+ ToolSeparator is used to visually distinguish between groups of items in a
+ toolbar by separating them with a line. It can be used in horizontal or
+ vertical toolbars by setting the \l orientation property to \c Qt.Vertical
+ or \c Qt.Horizontal, respectively.
+
+ \image qtquickcontrols2-toolseparator.png
+
+ \snippet qtquickcontrols2-toolseparator.qml 1
+
+ \sa {Customizing ToolSeparator}, {Separator Controls}
+*/
+
+class QQuickToolSeparatorPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickToolSeparator)
+
+public:
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolBar); }
+
+ Qt::Orientation orientation = Qt::Vertical;
+};
+
+QQuickToolSeparator::QQuickToolSeparator(QQuickItem *parent)
+ : QQuickControl(*(new QQuickToolSeparatorPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::ToolSeparator::orientation
+
+ This property holds the orientation of the tool separator.
+
+ Possible values:
+ \value Qt.Horizontal A horizontal separator is used in a vertical toolbar.
+ \value Qt.Vertical A vertical separator is used in a horizontal toolbar. (default)
+*/
+Qt::Orientation QQuickToolSeparator::orientation() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation;
+}
+
+void QQuickToolSeparator::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickToolSeparator);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ emit orientationChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick.Controls::ToolSeparator::horizontal
+
+ This property holds whether \l orientation is equal to \c Qt.Horizontal.
+
+ It is useful for \l {Customizing ToolSeparator}{customizing ToolSeparator}.
+
+ \sa orientation, vertical
+*/
+bool QQuickToolSeparator::isHorizontal() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick.Controls::ToolSeparator::vertical
+
+ This property holds whether \l orientation is equal to \c Qt.Vertical.
+
+ It is useful for \l {Customizing ToolSeparator}{customizing ToolSeparator}.
+
+ \sa orientation, horizontal
+*/
+bool QQuickToolSeparator::isVertical() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation == Qt::Vertical;
+}
+
+QFont QQuickToolSeparator::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ToolBar);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickToolSeparator::accessibleRole() const
+{
+ return QAccessible::Separator;
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktoolseparator_p.cpp"
diff --git a/src/quicktemplates2/qquicktoolseparator_p.h b/src/quicktemplates2/qquicktoolseparator_p.h
new file mode 100644
index 0000000000..e4692154d2
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolseparator_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTOOLSEPARATOR_P_H
+#define QQUICKTOOLSEPARATOR_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 <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickToolSeparatorPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolSeparator : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL)
+ QML_NAMED_ELEMENT(ToolSeparator)
+ QML_ADDED_IN_VERSION(2, 1)
+
+public:
+ explicit QQuickToolSeparator(QQuickItem *parent = nullptr);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+Q_SIGNALS:
+ void orientationChanged();
+
+protected:
+ QFont defaultFont() const override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickToolSeparator)
+ Q_DECLARE_PRIVATE(QQuickToolSeparator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickToolSeparator)
+
+#endif // QQUICKTOOLSEPARATOR_P_H
diff --git a/src/quicktemplates2/qquicktooltip.cpp b/src/quicktemplates2/qquicktooltip.cpp
new file mode 100644
index 0000000000..9d64360fd9
--- /dev/null
+++ b/src/quicktemplates2/qquicktooltip.cpp
@@ -0,0 +1,576 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktooltip_p.h"
+#include "qquickpopup_p_p.h"
+#include "qquickpopupitem_p_p.h"
+#include "qquickcontrol_p_p.h"
+
+#include <QtCore/qbasictimer.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuick/qquickwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ToolTip
+ \inherits Popup
+//! \instantiates QQuickToolTip
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-popups
+ \brief Provides tool tips for any control.
+
+ A tool tip is a short piece of text that informs the user of a control's
+ function. It is typically placed above or below the parent control. The
+ tip text can be any \l{Rich Text Processing}{rich text} formatted string.
+
+ \image qtquickcontrols2-tooltip.png
+
+ \section2 Attached Tool Tips
+
+ The most straight-forward way to setup tool tips for controls is to
+ specify \l text and \l {visible}{visibility} via attached properties.
+ The following example illustrates this approach:
+
+ \snippet qtquickcontrols2-tooltip.qml 1
+
+ Under normal circumstances, there is only one tool tip visible at a time.
+ In order to save resources, all items that use the ToolTip attached property
+ share the same visual tool tip label instance. Even though the visuals are
+ shared, \c text, \c timeout and \c delay are stored individually for each item
+ that uses the respective attached property. However, multiple items cannot
+ make the shared tool tip visible at the same time. The shared tool tip is only
+ shown for the last item that made it visible. The position of the shared tool
+ tip is determined by the framework.
+
+ \include qquicktooltip.qdocinc customize-note
+
+ \section2 Delay and Timeout
+
+ Tool tips are typically transient in a sense that they are shown as a
+ result of a certain external event or user interaction, and they usually
+ hide after a certain timeout. It is possible to control the delay when
+ a tool tip is shown, and the timeout when it is hidden. This makes it
+ possible to implement varying strategies for showing and hiding tool tips.
+
+ For example, on touch screens, it is a common pattern to show a tool tip
+ as a result of pressing and holding down a button. The following example
+ demonstrates how to delay showing a tool tip until the press-and-hold
+ interval is reached. In this example, the tool tip hides as soon as the
+ button is released.
+
+ \snippet qtquickcontrols2-tooltip-pressandhold.qml 1
+
+ With pointer devices, however, it might be desired to show a tool tip as
+ a result of hovering a button for a while. The following example presents
+ how to show a tool tip after hovering a button for a second, and hide it
+ after a timeout of five seconds.
+
+ \snippet qtquickcontrols2-tooltip-hover.qml 1
+
+ \section2 Custom Tool Tips
+
+ Should one need more fine-grained control over the tool tip position, or
+ multiple simultaneous tool tip instances are needed, it is also possible
+ to create local tool tip instances. This way, it is possible to
+ \l {Customizing ToolTip}{customize} the tool tip, and the whole \l Popup
+ API is available. The following example presents a tool tip that presents
+ the value of a slider when the handle is dragged.
+
+ \image qtquickcontrols2-tooltip-slider.png
+
+ \snippet qtquickcontrols2-tooltip-slider.qml 1
+
+ \sa {Customizing ToolTip}, {Popup Controls},
+ {QtQuick.Controls::Popup::closePolicy}{closePolicy}
+*/
+
+class QQuickToolTipPrivate : public QQuickPopupPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickToolTip)
+
+public:
+ void startDelay();
+ void stopDelay();
+
+ void startTimeout();
+ void stopTimeout();
+
+ void opened() override;
+
+ QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::ToolTip); }
+
+ int delay = 0;
+ int timeout = -1;
+ QString text;
+ QBasicTimer delayTimer;
+ QBasicTimer timeoutTimer;
+};
+
+void QQuickToolTipPrivate::startDelay()
+{
+ Q_Q(QQuickToolTip);
+ if (delay > 0)
+ delayTimer.start(delay, q);
+}
+
+void QQuickToolTipPrivate::stopDelay()
+{
+ delayTimer.stop();
+}
+
+void QQuickToolTipPrivate::startTimeout()
+{
+ Q_Q(QQuickToolTip);
+ if (timeout > 0)
+ timeoutTimer.start(timeout, q);
+}
+
+void QQuickToolTipPrivate::stopTimeout()
+{
+ timeoutTimer.stop();
+}
+
+void QQuickToolTipPrivate::opened()
+{
+ QQuickPopupPrivate::opened();
+ startTimeout();
+}
+
+QQuickToolTip::QQuickToolTip(QQuickItem *parent)
+ : QQuickPopup(*(new QQuickToolTipPrivate), parent)
+{
+ Q_D(QQuickToolTip);
+ d->allowVerticalFlip = true;
+ d->allowHorizontalFlip = true;
+ d->popupItem->setHoverEnabled(false); // QTBUG-63644
+}
+
+/*!
+ \qmlproperty string QtQuick.Controls::ToolTip::text
+
+ This property holds the text shown on the tool tip.
+*/
+QString QQuickToolTip::text() const
+{
+ Q_D(const QQuickToolTip);
+ return d->text;
+}
+
+void QQuickToolTip::setText(const QString &text)
+{
+ Q_D(QQuickToolTip);
+ if (d->text == text)
+ return;
+
+ d->text = text;
+ maybeSetAccessibleName(text);
+ emit textChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::ToolTip::delay
+
+ This property holds the delay (milliseconds) after which the tool tip is
+ shown. A tooltip with a negative delay is shown immediately. The default
+ value is \c 0.
+
+ \sa {Delay and Timeout}
+*/
+int QQuickToolTip::delay() const
+{
+ Q_D(const QQuickToolTip);
+ return d->delay;
+}
+
+void QQuickToolTip::setDelay(int delay)
+{
+ Q_D(QQuickToolTip);
+ if (d->delay == delay)
+ return;
+
+ d->delay = delay;
+ emit delayChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::ToolTip::timeout
+
+ This property holds the timeout (milliseconds) after which the tool tip is
+ hidden. A tooltip with a negative timeout does not hide automatically. The
+ default value is \c -1.
+
+ \sa {Delay and Timeout}
+*/
+int QQuickToolTip::timeout() const
+{
+ Q_D(const QQuickToolTip);
+ return d->timeout;
+}
+
+void QQuickToolTip::setTimeout(int timeout)
+{
+ Q_D(QQuickToolTip);
+ if (d->timeout == timeout)
+ return;
+
+ d->timeout = timeout;
+
+ if (timeout <= 0)
+ d->stopTimeout();
+ else if (isOpened())
+ d->startTimeout();
+
+ emit timeoutChanged();
+}
+
+void QQuickToolTip::setVisible(bool visible)
+{
+ Q_D(QQuickToolTip);
+ if (visible) {
+ if (!d->visible) {
+ // We are being made visible, and we weren't before.
+ if (d->delay > 0) {
+ d->startDelay();
+ return;
+ }
+ }
+ } else {
+ d->stopDelay();
+ }
+ QQuickPopup::setVisible(visible);
+}
+
+QQuickToolTipAttached *QQuickToolTip::qmlAttachedProperties(QObject *object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (!item)
+ qmlWarning(object) << "ToolTip must be attached to an Item";
+
+ return new QQuickToolTipAttached(object);
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlmethod void QtQuick.Controls::ToolTip::show(string text, int timeout)
+
+ This method shows the \a text as a tooltip, which times out in
+ \a timeout (milliseconds).
+*/
+void QQuickToolTip::show(const QString &text, int ms)
+{
+ if (ms >= 0)
+ setTimeout(ms);
+ setText(text);
+ open();
+}
+
+/*!
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+ \qmlmethod void QtQuick.Controls::ToolTip::hide()
+
+ This method hides the tooltip.
+*/
+void QQuickToolTip::hide()
+{
+ close();
+}
+
+QFont QQuickToolTip::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::ToolTip);
+}
+
+void QQuickToolTip::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data)
+{
+ Q_D(QQuickToolTip);
+ QQuickPopup::itemChange(change, data);
+ if (change == QQuickItem::ItemVisibleHasChanged) {
+ if (!data.boolValue)
+ d->stopTimeout();
+
+ QQuickToolTipAttached *attached = qobject_cast<QQuickToolTipAttached *>(qmlAttachedPropertiesObject<QQuickToolTip>(d->parentItem, false));
+ if (attached)
+ emit attached->visibleChanged();
+ }
+}
+
+void QQuickToolTip::timerEvent(QTimerEvent *event)
+{
+ Q_D(QQuickToolTip);
+ if (event->timerId() == d->timeoutTimer.timerId()) {
+ d->stopTimeout();
+ QQuickPopup::setVisible(false);
+ return;
+ }
+ if (event->timerId() == d->delayTimer.timerId()) {
+ d->stopDelay();
+ QQuickPopup::setVisible(true);
+ return;
+ }
+ QQuickPopup::timerEvent(event);
+}
+
+#if QT_CONFIG(accessibility)
+QAccessible::Role QQuickToolTip::accessibleRole() const
+{
+ return QAccessible::ToolTip;
+}
+
+void QQuickToolTip::accessibilityActiveChanged(bool active)
+{
+ Q_D(QQuickToolTip);
+ QQuickPopup::accessibilityActiveChanged(active);
+
+ if (active)
+ maybeSetAccessibleName(d->text);
+}
+#endif
+
+class QQuickToolTipAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickToolTipAttached)
+
+public:
+ QQuickToolTip *instance(bool create) const;
+
+ int delay = 0;
+ int timeout = -1;
+ QString text;
+};
+
+QQuickToolTip *QQuickToolTipAttachedPrivate::instance(bool create) const
+{
+ QQmlEngine *engine = qmlEngine(parent);
+ if (!engine)
+ return nullptr;
+
+ static const char *name = "_q_QQuickToolTip";
+
+ QQuickToolTip *tip = engine->property(name).value<QQuickToolTip *>();
+ if (!tip && create) {
+ // TODO: a cleaner way to create the instance? QQml(Meta)Type?
+ QQmlComponent component(engine);
+ component.setData("import QtQuick.Controls; ToolTip { }", QUrl());
+
+ QObject *object = component.create();
+ if (object)
+ object->setParent(engine);
+
+ tip = qobject_cast<QQuickToolTip *>(object);
+ if (!tip)
+ delete object;
+ else
+ engine->setProperty(name, QVariant::fromValue(object));
+ }
+ return tip;
+}
+
+QQuickToolTipAttached::QQuickToolTipAttached(QObject *parent)
+ : QObject(*(new QQuickToolTipAttachedPrivate), parent)
+{
+}
+
+/*!
+ \qmlattachedproperty string QtQuick.Controls::ToolTip::text
+
+ This attached property holds the text of the shared tool tip.
+ The property can be attached to any item.
+
+ \sa {Attached Tool Tips}
+*/
+QString QQuickToolTipAttached::text() const
+{
+ Q_D(const QQuickToolTipAttached);
+ return d->text;
+}
+
+void QQuickToolTipAttached::setText(const QString &text)
+{
+ Q_D(QQuickToolTipAttached);
+ if (d->text == text)
+ return;
+
+ d->text = text;
+ emit textChanged();
+
+ if (isVisible())
+ d->instance(true)->setText(text);
+}
+
+/*!
+ \qmlattachedproperty int QtQuick.Controls::ToolTip::delay
+
+ This attached property holds the delay (milliseconds) of the shared tool tip.
+ The property can be attached to any item.
+
+ \sa {Attached Tool Tips}, {Delay and Timeout}
+*/
+int QQuickToolTipAttached::delay() const
+{
+ Q_D(const QQuickToolTipAttached);
+ return d->delay;
+}
+
+void QQuickToolTipAttached::setDelay(int delay)
+{
+ Q_D(QQuickToolTipAttached);
+ if (d->delay == delay)
+ return;
+
+ d->delay = delay;
+ emit delayChanged();
+
+ if (isVisible())
+ d->instance(true)->setDelay(delay);
+}
+
+/*!
+ \qmlattachedproperty int QtQuick.Controls::ToolTip::timeout
+
+ This attached property holds the timeout (milliseconds) of the shared tool tip.
+ The property can be attached to any item.
+
+ \sa {Attached Tool Tips}, {Delay and Timeout}
+*/
+int QQuickToolTipAttached::timeout() const
+{
+ Q_D(const QQuickToolTipAttached);
+ return d->timeout;
+}
+
+void QQuickToolTipAttached::setTimeout(int timeout)
+{
+ Q_D(QQuickToolTipAttached);
+ if (d->timeout == timeout)
+ return;
+
+ d->timeout = timeout;
+ emit timeoutChanged();
+
+ if (isVisible())
+ d->instance(true)->setTimeout(timeout);
+}
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::ToolTip::visible
+
+ This attached property holds whether the shared tool tip is visible.
+ The property can be attached to any item.
+
+ \sa {Attached Tool Tips}
+*/
+bool QQuickToolTipAttached::isVisible() const
+{
+ Q_D(const QQuickToolTipAttached);
+ QQuickToolTip *tip = d->instance(false);
+ if (!tip)
+ return false;
+
+ return tip->isVisible() && tip->parentItem() == parent();
+}
+
+void QQuickToolTipAttached::setVisible(bool visible)
+{
+ Q_D(QQuickToolTipAttached);
+ if (visible)
+ show(d->text);
+ else
+ hide();
+}
+
+/*!
+ \qmlattachedproperty ToolTip QtQuick.Controls::ToolTip::toolTip
+
+ This attached property holds the shared tool tip instance. The property
+ can be attached to any item.
+
+ \sa {Attached Tool Tips}
+*/
+QQuickToolTip *QQuickToolTipAttached::toolTip() const
+{
+ Q_D(const QQuickToolTipAttached);
+ return d->instance(true);
+}
+
+/*!
+ \qmlattachedmethod void QtQuick.Controls::ToolTip::show(string text, int timeout = -1)
+
+ This attached method shows the shared tooltip with \a text and \a timeout (milliseconds).
+ The method can be attached to any item.
+
+ \sa {Attached Tool Tips}
+*/
+void QQuickToolTipAttached::show(const QString &text, int ms)
+{
+ Q_D(QQuickToolTipAttached);
+ QQuickToolTip *tip = d->instance(true);
+ if (!tip)
+ return;
+
+ tip->resetWidth();
+ tip->resetHeight();
+ tip->setParentItem(qobject_cast<QQuickItem *>(parent()));
+ tip->setDelay(d->delay);
+ tip->setTimeout(ms >= 0 ? ms : d->timeout);
+ tip->show(text);
+}
+
+/*!
+ \qmlattachedmethod void QtQuick.Controls::ToolTip::hide()
+
+ This attached method hides the shared tooltip. The method can be attached to any item.
+
+ \sa {Attached Tool Tips}
+*/
+void QQuickToolTipAttached::hide()
+{
+ Q_D(QQuickToolTipAttached);
+ QQuickToolTip *tip = d->instance(false);
+ if (!tip)
+ return;
+ // check the parent item to prevent unexpectedly closing tooltip by new created invisible tooltip
+ if (parent() == tip->parentItem())
+ tip->close();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktooltip_p.cpp"
diff --git a/src/quicktemplates2/qquicktooltip_p.h b/src/quicktemplates2/qquicktooltip_p.h
new file mode 100644
index 0000000000..5be22fd8c2
--- /dev/null
+++ b/src/quicktemplates2/qquicktooltip_p.h
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTOOLTIP_P_H
+#define QQUICKTOOLTIP_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 <QtQuickTemplates2/private/qquickpopup_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickToolTipPrivate;
+class QQuickToolTipAttached;
+class QQuickToolTipAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolTip : public QQuickPopup
+{
+ Q_OBJECT
+ Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL)
+ Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged FINAL)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ QML_NAMED_ELEMENT(ToolTip)
+ QML_ATTACHED(QQuickToolTipAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickToolTip(QQuickItem *parent = nullptr);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ int delay() const;
+ void setDelay(int delay);
+
+ int timeout() const;
+ void setTimeout(int timeout);
+
+ void setVisible(bool visible) override;
+
+ static QQuickToolTipAttached *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void textChanged();
+ void delayChanged();
+ void timeoutChanged();
+
+public Q_SLOTS:
+ Q_REVISION(2, 5) void show(const QString &text, int ms = -1);
+ Q_REVISION(2, 5) void hide();
+
+protected:
+ QFont defaultFont() const override;
+
+ void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) override;
+ void timerEvent(QTimerEvent *event) override;
+
+#if QT_CONFIG(accessibility)
+ QAccessible::Role accessibleRole() const override;
+ void accessibilityActiveChanged(bool active) override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickToolTip)
+ Q_DECLARE_PRIVATE(QQuickToolTip)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolTipAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(int delay READ delay WRITE setDelay NOTIFY delayChanged FINAL)
+ Q_PROPERTY(int timeout READ timeout WRITE setTimeout NOTIFY timeoutChanged FINAL)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged FINAL)
+ Q_PROPERTY(QQuickToolTip *toolTip READ toolTip CONSTANT FINAL)
+
+public:
+ explicit QQuickToolTipAttached(QObject *parent = nullptr);
+
+ QString text() const;
+ void setText(const QString &text);
+
+ int delay() const;
+ void setDelay(int delay);
+
+ int timeout() const;
+ void setTimeout(int timeout);
+
+ bool isVisible() const;
+ void setVisible(bool visible);
+
+ QQuickToolTip *toolTip() const;
+
+Q_SIGNALS:
+ void textChanged();
+ void delayChanged();
+ void timeoutChanged();
+ void visibleChanged();
+
+public Q_SLOTS:
+ void show(const QString &text, int ms = -1);
+ void hide();
+
+private:
+ Q_DISABLE_COPY(QQuickToolTipAttached)
+ Q_DECLARE_PRIVATE(QQuickToolTipAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickToolTip)
+QML_DECLARE_TYPEINFO(QQuickToolTip, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTOOLTIP_P_H
diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp
new file mode 100644
index 0000000000..f66428b83e
--- /dev/null
+++ b/src/quicktemplates2/qquicktumbler.cpp
@@ -0,0 +1,1047 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktumbler_p.h"
+
+#include <QtCore/qloggingcategory.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qqmlinfo.h>
+#include <QtQuick/private/qquickflickable_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuickTemplates2/private/qquicktumbler_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcTumbler, "qt.quick.controls.tumbler")
+
+/*!
+ \qmltype Tumbler
+ \inherits Control
+//! \instantiates QQuickTumbler
+ \inqmlmodule QtQuick.Controls
+ \since 5.7
+ \ingroup qtquickcontrols2-input
+ \brief Spinnable wheel of items that can be selected.
+
+ \image qtquickcontrols2-tumbler-wrap.gif
+
+ \code
+ Tumbler {
+ model: 5
+ // ...
+ }
+ \endcode
+
+ Tumbler allows the user to select an option from a spinnable \e "wheel" of
+ items. It is useful for when there are too many options to use, for
+ example, a RadioButton, and too few options to require the use of an
+ editable SpinBox. It is convenient in that it requires no keyboard usage
+ and wraps around at each end when there are a large number of items.
+
+ The API is similar to that of views like \l ListView and \l PathView; a
+ \l model and \l delegate can be set, and the \l count and \l currentItem
+ properties provide read-only access to information about the view. To
+ position the view at a certain index, use \l positionViewAtIndex().
+
+ Unlike views like \l PathView and \l ListView, however, there is always a
+ current item (when the model isn't empty). This means that when \l count is
+ equal to \c 0, \l currentIndex will be \c -1. In all other cases, it will
+ be greater than or equal to \c 0.
+
+ By default, Tumbler \l {wrap}{wraps} when it reaches the top and bottom, as
+ long as there are more items in the model than there are visible items;
+ that is, when \l count is greater than \l visibleItemCount:
+
+ \snippet qtquickcontrols2-tumbler-timePicker.qml tumbler
+
+ \sa {Customizing Tumbler}, {Input Controls}
+*/
+
+namespace {
+ static inline qreal delegateHeight(const QQuickTumbler *tumbler)
+ {
+ return tumbler->availableHeight() / tumbler->visibleItemCount();
+ }
+}
+
+/*
+ Finds the contentItem of the view that is a child of the control's \a contentItem.
+ The type is stored in \a type.
+*/
+QQuickItem *QQuickTumblerPrivate::determineViewType(QQuickItem *contentItem)
+{
+ if (!contentItem) {
+ resetViewData();
+ return nullptr;
+ }
+
+ if (contentItem->inherits("QQuickPathView")) {
+ view = contentItem;
+ viewContentItem = contentItem;
+ viewContentItemType = PathViewContentItem;
+ viewOffset = 0;
+
+ return contentItem;
+ } else if (contentItem->inherits("QQuickListView")) {
+ view = contentItem;
+ viewContentItem = qobject_cast<QQuickFlickable*>(contentItem)->contentItem();
+ viewContentItemType = ListViewContentItem;
+ viewContentY = 0;
+
+ return contentItem;
+ } else {
+ const auto childItems = contentItem->childItems();
+ for (QQuickItem *childItem : childItems) {
+ QQuickItem *item = determineViewType(childItem);
+ if (item)
+ return item;
+ }
+ }
+
+ resetViewData();
+ viewContentItemType = UnsupportedContentItemType;
+ return nullptr;
+}
+
+void QQuickTumblerPrivate::resetViewData()
+{
+ view = nullptr;
+ viewContentItem = nullptr;
+ if (viewContentItemType == PathViewContentItem)
+ viewOffset = 0;
+ else if (viewContentItemType == ListViewContentItem)
+ viewContentY = 0;
+ viewContentItemType = NoContentItem;
+}
+
+QList<QQuickItem *> QQuickTumblerPrivate::viewContentItemChildItems() const
+{
+ if (!viewContentItem)
+ return QList<QQuickItem *>();
+
+ return viewContentItem->childItems();
+}
+
+QQuickTumblerPrivate *QQuickTumblerPrivate::get(QQuickTumbler *tumbler)
+{
+ return tumbler->d_func();
+}
+
+void QQuickTumblerPrivate::_q_updateItemHeights()
+{
+ if (ignoreSignals)
+ return;
+
+ // Can't use our own private padding members here, as the padding property might be set,
+ // which doesn't affect them, only their getters.
+ Q_Q(const QQuickTumbler);
+ const qreal itemHeight = delegateHeight(q);
+ const auto items = viewContentItemChildItems();
+ for (QQuickItem *childItem : items)
+ childItem->setHeight(itemHeight);
+}
+
+void QQuickTumblerPrivate::_q_updateItemWidths()
+{
+ if (ignoreSignals)
+ return;
+
+ Q_Q(const QQuickTumbler);
+ const qreal availableWidth = q->availableWidth();
+ const auto items = viewContentItemChildItems();
+ for (QQuickItem *childItem : items)
+ childItem->setWidth(availableWidth);
+}
+
+void QQuickTumblerPrivate::_q_onViewCurrentIndexChanged()
+{
+ Q_Q(QQuickTumbler);
+ if (!view || ignoreCurrentIndexChanges || currentIndexSetDuringModelChange) {
+ // If the user set currentIndex in the onModelChanged handler,
+ // we have to respect that currentIndex by ignoring changes in the view
+ // until the model has finished being set.
+ qCDebug(lcTumbler).nospace() << "view currentIndex changed to "
+ << (view ? view->property("currentIndex").toString() : QStringLiteral("unknown index (no view)"))
+ << ", but we're ignoring it because one or more of the following conditions are true:"
+ << "\n- !view: " << !view
+ << "\n- ignoreCurrentIndexChanges: " << ignoreCurrentIndexChanges
+ << "\n- currentIndexSetDuringModelChange: " << currentIndexSetDuringModelChange;
+ return;
+ }
+
+ const int oldCurrentIndex = currentIndex;
+ currentIndex = view->property("currentIndex").toInt();
+
+ qCDebug(lcTumbler).nospace() << "view currentIndex changed to "
+ << (view ? view->property("currentIndex").toString() : QStringLiteral("unknown index (no view)"))
+ << ", our old currentIndex was " << oldCurrentIndex;
+
+ if (oldCurrentIndex != currentIndex)
+ emit q->currentIndexChanged();
+}
+
+void QQuickTumblerPrivate::_q_onViewCountChanged()
+{
+ Q_Q(QQuickTumbler);
+ qCDebug(lcTumbler) << "view count changed - ignoring signals?" << ignoreSignals;
+ if (ignoreSignals)
+ return;
+
+ setCount(view->property("count").toInt());
+
+ if (count > 0) {
+ if (pendingCurrentIndex != -1) {
+ // If there was an attempt to set currentIndex at creation, try to finish that attempt now.
+ // componentComplete() is too early, because the count might only be known sometime after completion.
+ setCurrentIndex(pendingCurrentIndex);
+ // If we could successfully set the currentIndex, consider it done.
+ // Otherwise, we'll try again later in updatePolish().
+ if (currentIndex == pendingCurrentIndex)
+ setPendingCurrentIndex(-1);
+ else
+ q->polish();
+ } else if (currentIndex == -1) {
+ // If new items were added and our currentIndex was -1, we must
+ // enforce our rule of a non-negative currentIndex when count > 0.
+ setCurrentIndex(0);
+ }
+ } else {
+ setCurrentIndex(-1);
+ }
+}
+
+void QQuickTumblerPrivate::_q_onViewOffsetChanged()
+{
+ viewOffset = view->property("offset").toReal();
+ calculateDisplacements();
+}
+
+void QQuickTumblerPrivate::_q_onViewContentYChanged()
+{
+ viewContentY = view->property("contentY").toReal();
+ calculateDisplacements();
+}
+
+void QQuickTumblerPrivate::calculateDisplacements()
+{
+ const auto items = viewContentItemChildItems();
+ for (QQuickItem *childItem : items) {
+ QQuickTumblerAttached *attached = qobject_cast<QQuickTumblerAttached *>(qmlAttachedPropertiesObject<QQuickTumbler>(childItem, false));
+ if (attached)
+ QQuickTumblerAttachedPrivate::get(attached)->calculateDisplacement();
+ }
+}
+
+void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *)
+{
+ _q_updateItemWidths();
+ _q_updateItemHeights();
+}
+
+void QQuickTumblerPrivate::itemChildRemoved(QQuickItem *, QQuickItem *)
+{
+ _q_updateItemWidths();
+ _q_updateItemHeights();
+}
+
+void QQuickTumblerPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
+{
+ QQuickControlPrivate::itemGeometryChanged(item, change, diff);
+ if (change.sizeChange())
+ calculateDisplacements();
+}
+
+QPalette QQuickTumblerPrivate::defaultPalette() const
+{
+ return QQuickTheme::palette(QQuickTheme::Tumbler);
+}
+
+QQuickTumbler::QQuickTumbler(QQuickItem *parent)
+ : QQuickControl(*(new QQuickTumblerPrivate), parent)
+{
+ setActiveFocusOnTab(true);
+
+ connect(this, SIGNAL(leftPaddingChanged()), this, SLOT(_q_updateItemWidths()));
+ connect(this, SIGNAL(rightPaddingChanged()), this, SLOT(_q_updateItemWidths()));
+ connect(this, SIGNAL(topPaddingChanged()), this, SLOT(_q_updateItemHeights()));
+ connect(this, SIGNAL(bottomPaddingChanged()), this, SLOT(_q_updateItemHeights()));
+}
+
+QQuickTumbler::~QQuickTumbler()
+{
+ Q_D(QQuickTumbler);
+ // Ensure that the item change listener is removed.
+ d->disconnectFromView();
+}
+
+/*!
+ \qmlproperty variant QtQuick.Controls::Tumbler::model
+
+ This property holds the model that provides data for this tumbler.
+*/
+QVariant QQuickTumbler::model() const
+{
+ Q_D(const QQuickTumbler);
+ return d->model;
+}
+
+void QQuickTumbler::setModel(const QVariant &model)
+{
+ Q_D(QQuickTumbler);
+ if (model == d->model)
+ return;
+
+ d->beginSetModel();
+
+ d->model = model;
+ emit modelChanged();
+
+ d->endSetModel();
+
+ d->currentIndexSetDuringModelChange = false;
+
+ // Don't try to correct the currentIndex if count() isn't known yet.
+ // We can check in setupViewData() instead.
+ if (isComponentComplete() && d->view && count() == 0)
+ d->setCurrentIndex(-1);
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::Tumbler::count
+ \readonly
+
+ This property holds the number of items in the model.
+*/
+int QQuickTumbler::count() const
+{
+ Q_D(const QQuickTumbler);
+ return d->count;
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::Tumbler::currentIndex
+
+ This property holds the index of the current item.
+
+ The value of this property is \c -1 when \l count is equal to \c 0. In all
+ other cases, it will be greater than or equal to \c 0.
+
+ \sa currentItem, positionViewAtIndex()
+*/
+int QQuickTumbler::currentIndex() const
+{
+ Q_D(const QQuickTumbler);
+ return d->currentIndex;
+}
+
+void QQuickTumbler::setCurrentIndex(int currentIndex)
+{
+ Q_D(QQuickTumbler);
+ if (d->modelBeingSet)
+ d->currentIndexSetDuringModelChange = true;
+ d->setCurrentIndex(currentIndex, QQuickTumblerPrivate::UserChange);
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Tumbler::currentItem
+ \readonly
+
+ This property holds the item at the current index.
+
+ \sa currentIndex, positionViewAtIndex()
+*/
+QQuickItem *QQuickTumbler::currentItem() const
+{
+ Q_D(const QQuickTumbler);
+ return d->view ? d->view->property("currentItem").value<QQuickItem*>() : nullptr;
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::Tumbler::delegate
+
+ This property holds the delegate used to display each item.
+*/
+QQmlComponent *QQuickTumbler::delegate() const
+{
+ Q_D(const QQuickTumbler);
+ return d->delegate;
+}
+
+void QQuickTumbler::setDelegate(QQmlComponent *delegate)
+{
+ Q_D(QQuickTumbler);
+ if (delegate == d->delegate)
+ return;
+
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+/*!
+ \qmlproperty int QtQuick.Controls::Tumbler::visibleItemCount
+
+ This property holds the number of items visible in the tumbler. It must be
+ an odd number, as the current item is always vertically centered.
+*/
+int QQuickTumbler::visibleItemCount() const
+{
+ Q_D(const QQuickTumbler);
+ return d->visibleItemCount;
+}
+
+void QQuickTumbler::setVisibleItemCount(int visibleItemCount)
+{
+ Q_D(QQuickTumbler);
+ if (visibleItemCount == d->visibleItemCount)
+ return;
+
+ d->visibleItemCount = visibleItemCount;
+ d->_q_updateItemHeights();
+ emit visibleItemCountChanged();
+}
+
+QQuickTumblerAttached *QQuickTumbler::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickTumblerAttached(object);
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Tumbler::wrap
+ \since QtQuick.Controls 2.1 (Qt 5.8)
+
+ This property determines whether or not the tumbler wraps around when it
+ reaches the top or bottom.
+
+ The default value is \c false when \l count is less than
+ \l visibleItemCount, as it is simpler to interact with a non-wrapping Tumbler
+ when there are only a few items. To override this behavior, explicitly set
+ the value of this property. To return to the default behavior, set this
+ property to \c undefined.
+*/
+bool QQuickTumbler::wrap() const
+{
+ Q_D(const QQuickTumbler);
+ return d->wrap;
+}
+
+void QQuickTumbler::setWrap(bool wrap)
+{
+ Q_D(QQuickTumbler);
+ d->setWrap(wrap, true);
+}
+
+void QQuickTumbler::resetWrap()
+{
+ Q_D(QQuickTumbler);
+ d->explicitWrap = false;
+ d->setWrapBasedOnCount();
+}
+
+/*!
+ \qmlproperty bool QtQuick.Controls::Tumbler::moving
+ \since QtQuick.Controls 2.2 (Qt 5.9)
+
+ This property describes whether the tumbler is currently moving, due to
+ the user either dragging or flicking it.
+*/
+bool QQuickTumbler::isMoving() const
+{
+ Q_D(const QQuickTumbler);
+ return d->view && d->view->property("moving").toBool();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Tumbler::positionViewAtIndex(int index, PositionMode mode)
+ \since QtQuick.Controls 2.5 (Qt 5.12)
+
+ Positions the view so that the \a index is at the position specified by \a mode.
+
+ For example:
+
+ \code
+ positionViewAtIndex(10, Tumbler.Center)
+ \endcode
+
+ If \l wrap is true (the default), the modes available to \l {PathView}'s
+ \l {PathView::}{positionViewAtIndex()} function
+ are available, otherwise the modes available to \l {ListView}'s
+ \l {ListView::}{positionViewAtIndex()} function
+ are available.
+
+ \note There is a known limitation that using \c Tumbler.Beginning when \l
+ wrap is \c true will result in the wrong item being positioned at the top
+ of view. As a workaround, pass \c {index - 1}.
+
+ \sa currentIndex
+*/
+void QQuickTumbler::positionViewAtIndex(int index, QQuickTumbler::PositionMode mode)
+{
+ Q_D(QQuickTumbler);
+ if (!d->view) {
+ d->warnAboutIncorrectContentItem();
+ return;
+ }
+
+ QMetaObject::invokeMethod(d->view, "positionViewAtIndex", Q_ARG(int, index), Q_ARG(int, mode));
+}
+
+void QQuickTumbler::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickTumbler);
+
+ QQuickControl::geometryChange(newGeometry, oldGeometry);
+
+ d->_q_updateItemHeights();
+
+ if (newGeometry.width() != oldGeometry.width())
+ d->_q_updateItemWidths();
+}
+
+void QQuickTumbler::componentComplete()
+{
+ Q_D(QQuickTumbler);
+ qCDebug(lcTumbler) << "componentComplete()";
+ QQuickControl::componentComplete();
+
+ if (!d->view) {
+ // Force the view to be created.
+ qCDebug(lcTumbler) << "emitting wrapChanged() to force view to be created";
+ emit wrapChanged();
+ // Determine the type of view for attached properties, etc.
+ d->setupViewData(d->contentItem);
+ }
+
+ // If there was no contentItem or it was of an unsupported type,
+ // we don't have anything else to do.
+ if (!d->view)
+ return;
+
+ // Update item heights after we've populated the model,
+ // otherwise ignoreSignals will cause these functions to return early.
+ d->_q_updateItemHeights();
+ d->_q_updateItemWidths();
+ d->_q_onViewCountChanged();
+
+ qCDebug(lcTumbler) << "componentComplete() is done";
+}
+
+void QQuickTumbler::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickTumbler);
+
+ QQuickControl::contentItemChange(newItem, oldItem);
+
+ if (oldItem)
+ d->disconnectFromView();
+
+ if (newItem) {
+ // We wait until wrap is set to that we know which type of view to create.
+ // If we try to set up the view too early, we'll issue warnings about it not existing.
+ if (isComponentComplete()) {
+ // Make sure we use the new content item and not the current one, as that won't
+ // be changed until after contentItemChange() has finished.
+ d->setupViewData(newItem);
+
+ d->_q_updateItemHeights();
+ d->_q_updateItemWidths();
+ }
+ }
+}
+
+void QQuickTumblerPrivate::disconnectFromView()
+{
+ Q_Q(QQuickTumbler);
+ if (!view) {
+ // If a custom content item is declared, it can happen that
+ // the original contentItem exists without the view etc. having been
+ // determined yet, and then this is called when the custom content item
+ // is eventually set.
+ return;
+ }
+
+ QObject::disconnect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
+ QObject::disconnect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
+ QObject::disconnect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
+ QObject::disconnect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged()));
+
+ if (viewContentItemType == PathViewContentItem)
+ QObject::disconnect(view, SIGNAL(offsetChanged()), q, SLOT(_q_onViewOffsetChanged()));
+ else
+ QObject::disconnect(view, SIGNAL(contentYChanged()), q, SLOT(_q_onViewContentYChanged()));
+
+ QQuickItemPrivate *oldViewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
+ oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children | QQuickItemPrivate::Geometry);
+
+ resetViewData();
+}
+
+void QQuickTumblerPrivate::setupViewData(QQuickItem *newControlContentItem)
+{
+ // Don't do anything if we've already set up.
+ if (view)
+ return;
+
+ determineViewType(newControlContentItem);
+
+ if (viewContentItemType == QQuickTumblerPrivate::NoContentItem)
+ return;
+
+ if (viewContentItemType == QQuickTumblerPrivate::UnsupportedContentItemType) {
+ warnAboutIncorrectContentItem();
+ return;
+ }
+
+ Q_Q(QQuickTumbler);
+ QObject::connect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
+ QObject::connect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
+ QObject::connect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
+ QObject::connect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged()));
+
+ if (viewContentItemType == PathViewContentItem) {
+ QObject::connect(view, SIGNAL(offsetChanged()), q, SLOT(_q_onViewOffsetChanged()));
+ _q_onViewOffsetChanged();
+ } else {
+ QObject::connect(view, SIGNAL(contentYChanged()), q, SLOT(_q_onViewContentYChanged()));
+ _q_onViewContentYChanged();
+ }
+
+ QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
+ viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children | QQuickItemPrivate::Geometry);
+
+ // Sync the view's currentIndex with ours.
+ syncCurrentIndex();
+
+ calculateDisplacements();
+}
+
+void QQuickTumblerPrivate::warnAboutIncorrectContentItem()
+{
+ Q_Q(QQuickTumbler);
+ qmlWarning(q) << "Tumbler: contentItem must contain either a PathView or a ListView";
+}
+
+void QQuickTumblerPrivate::syncCurrentIndex()
+{
+ const int actualViewIndex = view->property("currentIndex").toInt();
+ Q_Q(QQuickTumbler);
+
+ const bool isPendingCurrentIndex = pendingCurrentIndex != -1;
+ const int indexToSet = isPendingCurrentIndex ? pendingCurrentIndex : currentIndex;
+
+ // Nothing to do.
+ if (actualViewIndex == indexToSet) {
+ setPendingCurrentIndex(-1);
+ return;
+ }
+
+ // actualViewIndex might be 0 or -1 for PathView and ListView respectively,
+ // but we always use -1 for that.
+ if (q->count() == 0 && actualViewIndex <= 0)
+ return;
+
+ ignoreCurrentIndexChanges = true;
+ view->setProperty("currentIndex", QVariant(indexToSet));
+ ignoreCurrentIndexChanges = false;
+
+ if (view->property("currentIndex").toInt() == indexToSet)
+ setPendingCurrentIndex(-1);
+ else if (isPendingCurrentIndex)
+ q->polish();
+}
+
+void QQuickTumblerPrivate::setPendingCurrentIndex(int index)
+{
+ qCDebug(lcTumbler) << "setting pendingCurrentIndex to" << index;
+ pendingCurrentIndex = index;
+}
+
+QString QQuickTumblerPrivate::propertyChangeReasonToString(
+ QQuickTumblerPrivate::PropertyChangeReason changeReason)
+{
+ return changeReason == UserChange ? QStringLiteral("UserChange") : QStringLiteral("InternalChange");
+}
+
+void QQuickTumblerPrivate::setCurrentIndex(int newCurrentIndex,
+ QQuickTumblerPrivate::PropertyChangeReason changeReason)
+{
+ Q_Q(QQuickTumbler);
+ qCDebug(lcTumbler).nospace() << "setting currentIndex to " << newCurrentIndex
+ << ", old currentIndex was " << currentIndex
+ << ", changeReason is " << propertyChangeReasonToString(changeReason);
+ if (newCurrentIndex == currentIndex || newCurrentIndex < -1)
+ return;
+
+ if (!q->isComponentComplete()) {
+ // Views can't set currentIndex until they're ready.
+ qCDebug(lcTumbler) << "we're not complete; setting pendingCurrentIndex instead";
+ setPendingCurrentIndex(newCurrentIndex);
+ return;
+ }
+
+ if (modelBeingSet && changeReason == UserChange) {
+ // If modelBeingSet is true and the user set the currentIndex,
+ // the model is in the process of being set and the user has set
+ // the currentIndex in onModelChanged. We have to queue the currentIndex
+ // change until we're ready.
+ qCDebug(lcTumbler) << "a model is being set; setting pendingCurrentIndex instead";
+ setPendingCurrentIndex(newCurrentIndex);
+ return;
+ }
+
+ // -1 doesn't make sense for a non-empty Tumbler, because unlike
+ // e.g. ListView, there's always one item selected.
+ // Wait until the component has finished before enforcing this rule, though,
+ // because the count might not be known yet.
+ if ((count > 0 && newCurrentIndex == -1) || (newCurrentIndex >= count)) {
+ return;
+ }
+
+ // The view might not have been created yet, as is the case
+ // if you create a Tumbler component and pass e.g. { currentIndex: 2 }
+ // to createObject().
+ if (view) {
+ // Only actually set our currentIndex if the view was able to set theirs.
+ bool couldSet = false;
+ if (count == 0 && newCurrentIndex == -1) {
+ // PathView insists on using 0 as the currentIndex when there are no items.
+ couldSet = true;
+ } else {
+ ignoreCurrentIndexChanges = true;
+ ignoreSignals = true;
+ view->setProperty("currentIndex", newCurrentIndex);
+ ignoreSignals = false;
+ ignoreCurrentIndexChanges = false;
+
+ couldSet = view->property("currentIndex").toInt() == newCurrentIndex;
+ }
+
+ if (couldSet) {
+ // The view's currentIndex might not have actually changed, but ours has,
+ // and that's what user code sees.
+ currentIndex = newCurrentIndex;
+ emit q->currentIndexChanged();
+ }
+
+ qCDebug(lcTumbler) << "view's currentIndex is now" << view->property("currentIndex").toInt()
+ << "and ours is" << currentIndex;
+ }
+}
+
+void QQuickTumblerPrivate::setCount(int newCount)
+{
+ qCDebug(lcTumbler).nospace() << "setting count to " << newCount
+ << ", old count was " << count;
+ if (newCount == count)
+ return;
+
+ count = newCount;
+
+ Q_Q(QQuickTumbler);
+ setWrapBasedOnCount();
+
+ emit q->countChanged();
+}
+
+void QQuickTumblerPrivate::setWrapBasedOnCount()
+{
+ if (count == 0 || explicitWrap || modelBeingSet)
+ return;
+
+ setWrap(count >= visibleItemCount, false);
+}
+
+void QQuickTumblerPrivate::setWrap(bool shouldWrap, bool isExplicit)
+{
+ qCDebug(lcTumbler) << "setting wrap to" << shouldWrap << "- exlicit?" << isExplicit;
+ if (isExplicit)
+ explicitWrap = true;
+
+ Q_Q(QQuickTumbler);
+ if (q->isComponentComplete() && shouldWrap == wrap)
+ return;
+
+ // Since we use the currentIndex of the contentItem directly, we must
+ // ensure that we keep track of the currentIndex so it doesn't get lost
+ // between view changes.
+ const int oldCurrentIndex = currentIndex;
+
+ disconnectFromView();
+
+ wrap = shouldWrap;
+
+ // New views will set their currentIndex upon creation, which we'd otherwise
+ // take as the correct one, so we must ignore them.
+ ignoreCurrentIndexChanges = true;
+
+ // This will cause the view to be created if our contentItem is a TumblerView.
+ emit q->wrapChanged();
+
+ ignoreCurrentIndexChanges = false;
+
+ // If isComponentComplete() is true, we require a contentItem. If it's not
+ // true, it might not have been created yet, so we wait until
+ // componentComplete() is called.
+ //
+ // When the contentItem (usually QQuickTumblerView) has been created, we
+ // can start determining its type, etc. If the delegates use attached
+ // properties, this will have already been called, in which case it will
+ // return early. If the delegate doesn't use attached properties, we need
+ // to call it here.
+ if (q->isComponentComplete() || contentItem)
+ setupViewData(contentItem);
+
+ setCurrentIndex(oldCurrentIndex);
+}
+
+void QQuickTumblerPrivate::beginSetModel()
+{
+ modelBeingSet = true;
+}
+
+void QQuickTumblerPrivate::endSetModel()
+{
+ modelBeingSet = false;
+ setWrapBasedOnCount();
+}
+
+void QQuickTumbler::keyPressEvent(QKeyEvent *event)
+{
+ QQuickControl::keyPressEvent(event);
+
+ Q_D(QQuickTumbler);
+ if (event->isAutoRepeat() || !d->view)
+ return;
+
+ if (event->key() == Qt::Key_Up) {
+ QMetaObject::invokeMethod(d->view, "decrementCurrentIndex");
+ } else if (event->key() == Qt::Key_Down) {
+ QMetaObject::invokeMethod(d->view, "incrementCurrentIndex");
+ }
+}
+
+void QQuickTumbler::updatePolish()
+{
+ Q_D(QQuickTumbler);
+ if (d->pendingCurrentIndex != -1) {
+ // Update our count, as ignoreSignals might have been true
+ // when _q_onViewCountChanged() was last called.
+ d->setCount(d->view->property("count").toInt());
+
+ // If the count is still 0, it's not going to happen.
+ if (d->count == 0) {
+ d->setPendingCurrentIndex(-1);
+ return;
+ }
+
+ // If there is a pending currentIndex at this stage, it means that
+ // the view wouldn't set our currentIndex in _q_onViewCountChanged
+ // because it wasn't ready. Try one last time here.
+ d->setCurrentIndex(d->pendingCurrentIndex);
+
+ if (d->currentIndex != d->pendingCurrentIndex && d->currentIndex == -1) {
+ // If we *still* couldn't set it, it's probably invalid.
+ // See if we can at least enforce our rule of "non-negative currentIndex when count > 0" instead.
+ d->setCurrentIndex(0);
+ }
+
+ d->setPendingCurrentIndex(-1);
+ }
+}
+
+QFont QQuickTumbler::defaultFont() const
+{
+ return QQuickTheme::font(QQuickTheme::Tumbler);
+}
+
+void QQuickTumblerAttachedPrivate::init(QQuickItem *delegateItem)
+{
+ Q_Q(QQuickTumblerAttached);
+ if (!delegateItem->parentItem()) {
+ qmlWarning(q) << "Tumbler: attached properties must be accessed through a delegate item that has a parent";
+ return;
+ }
+
+ QVariant indexContextProperty = qmlContext(delegateItem)->contextProperty(QStringLiteral("index"));
+ if (!indexContextProperty.isValid()) {
+ qmlWarning(q) << "Tumbler: attempting to access attached property on item without an \"index\" property";
+ return;
+ }
+
+ index = indexContextProperty.toInt();
+
+ QQuickItem *parentItem = delegateItem;
+ while ((parentItem = parentItem->parentItem())) {
+ if ((tumbler = qobject_cast<QQuickTumbler*>(parentItem)))
+ break;
+ }
+}
+
+void QQuickTumblerAttachedPrivate::calculateDisplacement()
+{
+ const qreal previousDisplacement = displacement;
+ displacement = 0;
+
+ if (!tumbler) {
+ // Can happen if the attached properties are accessed on the wrong type of item or the tumbler was destroyed.
+ // We don't want to emit the change signal though, as this could cause warnings about Tumbler.tumbler being null.
+ return;
+ }
+
+ // Can happen if there is no ListView or PathView within the contentItem.
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(tumbler);
+ if (!tumblerPrivate->viewContentItem) {
+ emitIfDisplacementChanged(previousDisplacement, displacement);
+ return;
+ }
+
+ // The attached property gets created before our count is updated, so just cheat here
+ // to avoid having to listen to count changes.
+ const int count = tumblerPrivate->view->property("count").toInt();
+ // This can happen in tests, so it may happen in normal usage too.
+ if (count == 0) {
+ emitIfDisplacementChanged(previousDisplacement, displacement);
+ return;
+ }
+
+ if (tumblerPrivate->viewContentItemType == QQuickTumblerPrivate::PathViewContentItem) {
+ const qreal offset = tumblerPrivate->viewOffset;
+
+ displacement = count > 1 ? count - index - offset : 0;
+ // Don't add 1 if count <= visibleItemCount
+ const int visibleItems = tumbler->visibleItemCount();
+ const int halfVisibleItems = visibleItems / 2 + (visibleItems < count ? 1 : 0);
+ if (displacement > halfVisibleItems)
+ displacement -= count;
+ else if (displacement < -halfVisibleItems)
+ displacement += count;
+ } else {
+ const qreal contentY = tumblerPrivate->viewContentY;
+ const qreal delegateH = delegateHeight(tumbler);
+ const qreal preferredHighlightBegin = tumblerPrivate->view->property("preferredHighlightBegin").toReal();
+ const qreal itemY = qobject_cast<QQuickItem*>(parent)->y();
+ qreal currentItemY = 0;
+ auto currentItem = tumblerPrivate->view->property("currentItem").value<QQuickItem*>();
+ if (currentItem)
+ currentItemY = currentItem->y();
+ // Start from the y position of the current item.
+ const qreal topOfCurrentItemInViewport = currentItemY - contentY;
+ // Then, calculate the distance between it and the preferredHighlightBegin.
+ const qreal relativePositionToPreferredHighlightBegin = topOfCurrentItemInViewport - preferredHighlightBegin;
+ // Next, calculate the distance between us and the current item.
+ const qreal distanceFromCurrentItem = currentItemY - itemY;
+ const qreal displacementInPixels = distanceFromCurrentItem - relativePositionToPreferredHighlightBegin;
+ // Convert it from pixels to a floating point index.
+ displacement = displacementInPixels / delegateH;
+ }
+
+ emitIfDisplacementChanged(previousDisplacement, displacement);
+}
+
+void QQuickTumblerAttachedPrivate::emitIfDisplacementChanged(qreal oldDisplacement, qreal newDisplacement)
+{
+ Q_Q(QQuickTumblerAttached);
+ if (newDisplacement != oldDisplacement)
+ emit q->displacementChanged();
+}
+
+QQuickTumblerAttached::QQuickTumblerAttached(QObject *parent)
+ : QObject(*(new QQuickTumblerAttachedPrivate), parent)
+{
+ Q_D(QQuickTumblerAttached);
+ QQuickItem *delegateItem = qobject_cast<QQuickItem *>(parent);
+ if (delegateItem)
+ d->init(delegateItem);
+ else if (parent)
+ qmlWarning(parent) << "Tumbler: attached properties of Tumbler must be accessed through a delegate item";
+
+ if (d->tumbler) {
+ // When the Tumbler is completed, wrapChanged() is emitted to let QQuickTumblerView
+ // know that it can create the view. The view itself might instantiate delegates
+ // that use attached properties. At this point, setupViewData() hasn't been called yet
+ // (it's called on the next line in componentComplete()), so we call it here so that
+ // we have access to the view.
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(d->tumbler);
+ tumblerPrivate->setupViewData(tumblerPrivate->contentItem);
+
+ if (delegateItem && delegateItem->parentItem() == tumblerPrivate->viewContentItem) {
+ // This item belongs to the "new" view, meaning that the tumbler's contentItem
+ // was probably assigned declaratively. If they're not equal, calling
+ // calculateDisplacement() would use the old contentItem data, which is bad.
+ d->calculateDisplacement();
+ }
+ }
+}
+
+/*!
+ \qmlattachedproperty Tumbler QtQuick.Controls::Tumbler::tumbler
+ \readonly
+
+ This attached property holds the tumbler. The property can be attached to
+ a tumbler delegate. The value is \c null if the item is not a tumbler delegate.
+*/
+QQuickTumbler *QQuickTumblerAttached::tumbler() const
+{
+ Q_D(const QQuickTumblerAttached);
+ return d->tumbler;
+}
+
+/*!
+ \qmlattachedproperty real QtQuick.Controls::Tumbler::displacement
+ \readonly
+
+ This attached property holds a value from \c {-visibleItemCount / 2} to
+ \c {visibleItemCount / 2}, which represents how far away this item is from
+ being the current item, with \c 0 being completely current.
+
+ For example, the item below will be 40% opaque when it is not the current item,
+ and transition to 100% opacity when it becomes the current item:
+
+ \code
+ delegate: Text {
+ text: modelData
+ opacity: 0.4 + Math.max(0, 1 - Math.abs(Tumbler.displacement)) * 0.6
+ }
+ \endcode
+*/
+qreal QQuickTumblerAttached::displacement() const
+{
+ Q_D(const QQuickTumblerAttached);
+ return d->displacement;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qquicktumbler_p.cpp"
diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h
new file mode 100644
index 0000000000..f9d5a13bef
--- /dev/null
+++ b/src/quicktemplates2/qquicktumbler_p.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTUMBLER_P_H
+#define QQUICKTUMBLER_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/qvariant.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTumblerAttached;
+class QQuickTumblerPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumbler : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL)
+ Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
+ Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
+ Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ Q_PROPERTY(int visibleItemCount READ visibleItemCount WRITE setVisibleItemCount NOTIFY visibleItemCountChanged FINAL)
+ // 2.1 (Qt 5.8)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap RESET resetWrap NOTIFY wrapChanged FINAL REVISION(2, 1))
+ // 2.2 (Qt 5.9)
+ Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged FINAL REVISION(2, 2))
+ QML_NAMED_ELEMENT(Tumbler)
+ QML_ATTACHED(QQuickTumblerAttached)
+ QML_ADDED_IN_VERSION(2, 0)
+
+public:
+ explicit QQuickTumbler(QQuickItem *parent = nullptr);
+ ~QQuickTumbler();
+
+ QVariant model() const;
+ void setModel(const QVariant &model);
+
+ int count() const;
+
+ int currentIndex() const;
+ void setCurrentIndex(int currentIndex);
+ QQuickItem *currentItem() const;
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ int visibleItemCount() const;
+ void setVisibleItemCount(int visibleItemCount);
+
+ static QQuickTumblerAttached *qmlAttachedProperties(QObject *object);
+
+ // 2.1 (Qt 5.8)
+ bool wrap() const;
+ void setWrap(bool wrap);
+ void resetWrap();
+
+ // 2.2 (Qt 5.9)
+ bool isMoving() const;
+
+ enum PositionMode {
+ Beginning,
+ Center,
+ End,
+ Visible, // ListView-only
+ Contain,
+ SnapPosition
+ };
+ Q_ENUM(PositionMode)
+
+ // 2.5 (Qt 5.12)
+ Q_REVISION(2, 5) Q_INVOKABLE void positionViewAtIndex(int index, PositionMode mode);
+
+Q_SIGNALS:
+ void modelChanged();
+ void countChanged();
+ void currentIndexChanged();
+ void currentItemChanged();
+ void delegateChanged();
+ void visibleItemCountChanged();
+ // 2.1 (Qt 5.8)
+ Q_REVISION(2, 1) void wrapChanged();
+ // 2.2 (Qt 5.9)
+ Q_REVISION(2, 2) void movingChanged();
+
+protected:
+ void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void componentComplete() override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ void keyPressEvent(QKeyEvent *event) override;
+ void updatePolish() override;
+
+ QFont defaultFont() const override;
+
+private:
+ Q_DISABLE_COPY(QQuickTumbler)
+ Q_DECLARE_PRIVATE(QQuickTumbler)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_updateItemWidths())
+ Q_PRIVATE_SLOT(d_func(), void _q_updateItemHeights())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewCurrentIndexChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewCountChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewOffsetChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewContentYChanged())
+};
+
+class QQuickTumblerAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickTumbler *tumbler READ tumbler CONSTANT FINAL)
+ Q_PROPERTY(qreal displacement READ displacement NOTIFY displacementChanged FINAL)
+
+public:
+ explicit QQuickTumblerAttached(QObject *parent = nullptr);
+
+ QQuickTumbler *tumbler() const;
+ qreal displacement() const;
+
+Q_SIGNALS:
+ void displacementChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickTumblerAttached)
+ Q_DECLARE_PRIVATE(QQuickTumblerAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickTumbler)
+QML_DECLARE_TYPEINFO(QQuickTumbler, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKTUMBLER_P_H
diff --git a/src/quicktemplates2/qquicktumbler_p_p.h b/src/quicktemplates2/qquicktumbler_p_p.h
new file mode 100644
index 0000000000..aa5d58c076
--- /dev/null
+++ b/src/quicktemplates2/qquicktumbler_p_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTUMBLER_P_P_H
+#define QQUICKTUMBLER_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 <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuickTemplates2/private/qquicktumbler_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTumbler)
+
+public:
+ enum ContentItemType {
+ NoContentItem,
+ UnsupportedContentItemType,
+ PathViewContentItem,
+ ListViewContentItem
+ };
+
+ QQuickItem *determineViewType(QQuickItem *contentItem);
+ void resetViewData();
+ QList<QQuickItem *> viewContentItemChildItems() const;
+
+ static QQuickTumblerPrivate *get(QQuickTumbler *tumbler);
+
+ QPalette defaultPalette() const override;
+
+ QVariant model;
+ QQmlComponent *delegate = nullptr;
+ int visibleItemCount = 5;
+ bool wrap = true;
+ bool explicitWrap = false;
+ bool modelBeingSet = false;
+ bool currentIndexSetDuringModelChange = false;
+ QQuickItem *view = nullptr;
+ QQuickItem *viewContentItem = nullptr;
+ ContentItemType viewContentItemType = UnsupportedContentItemType;
+ union {
+ qreal viewOffset; // PathView
+ qreal viewContentY; // ListView
+ };
+ int currentIndex = -1;
+ int pendingCurrentIndex = -1;
+ bool ignoreCurrentIndexChanges = false;
+ int count = 0;
+ bool ignoreSignals = false;
+
+ void _q_updateItemHeights();
+ void _q_updateItemWidths();
+ void _q_onViewCurrentIndexChanged();
+ void _q_onViewCountChanged();
+ void _q_onViewOffsetChanged();
+ void _q_onViewContentYChanged();
+
+ void calculateDisplacements();
+
+ void disconnectFromView();
+ void setupViewData(QQuickItem *newControlContentItem);
+ void warnAboutIncorrectContentItem();
+ void syncCurrentIndex();
+ void setPendingCurrentIndex(int index);
+
+ enum PropertyChangeReason {
+ UserChange,
+ InternalChange
+ };
+
+ static QString propertyChangeReasonToString(PropertyChangeReason changeReason);
+
+ void setCurrentIndex(int newCurrentIndex, PropertyChangeReason changeReason = InternalChange);
+ void setCount(int newCount);
+ void setWrapBasedOnCount();
+ void setWrap(bool shouldWrap, bool isExplicit);
+ void beginSetModel();
+ void endSetModel();
+
+ void itemChildAdded(QQuickItem *, QQuickItem *) override;
+ void itemChildRemoved(QQuickItem *, QQuickItem *) override;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange , const QRectF &) override;
+};
+
+class QQuickTumblerAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickTumblerAttached)
+
+public:
+ static QQuickTumblerAttachedPrivate *get(QQuickTumblerAttached *attached)
+ {
+ return attached->d_func();
+ }
+
+ void init(QQuickItem *delegateItem);
+
+ void calculateDisplacement();
+ void emitIfDisplacementChanged(qreal oldDisplacement, qreal newDisplacement);
+
+ // The Tumbler that contains the delegate. Required to calculated the displacement.
+ QPointer<QQuickTumbler> tumbler;
+ // The index of the delegate. Used to calculate the displacement.
+ int index = -1;
+ // The displacement for our delegate.
+ qreal displacement = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTUMBLER_P_P_H
diff --git a/src/quicktemplates2/qquickvelocitycalculator.cpp b/src/quicktemplates2/qquickvelocitycalculator.cpp
new file mode 100644
index 0000000000..a0c5ec0d26
--- /dev/null
+++ b/src/quicktemplates2/qquickvelocitycalculator.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickvelocitycalculator_p_p.h"
+
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Usage:
+
+ QQuickVelocityCalculator velocityCalculator;
+
+ // ...
+
+ velocityCalcular.startMeasuring(event->pos(), event->timestamp());
+ velocityCalcular.stopMeasuring(event->pos(), event->timestamp());
+
+ // ...
+
+ if (velocityCalculator.velocity().x() > someAmount)
+ doSomething();
+ else if (velocityCalculator.velocity().x() < -someAmount)
+ doSomethingElse();
+*/
+
+void QQuickVelocityCalculator::startMeasuring(const QPointF &point1, qint64 timestamp)
+{
+ m_point1 = point1;
+
+ if (timestamp != 0)
+ m_point1Timestamp = timestamp;
+ else
+ m_timer.start();
+}
+
+void QQuickVelocityCalculator::stopMeasuring(const QPointF &point2, qint64 timestamp)
+{
+ if (timestamp == 0 && !m_timer.isValid()) {
+ qWarning() << "QQuickVelocityCalculator: a call to stopMeasuring() must be preceded by a call to startMeasuring()";
+ return;
+ }
+
+ m_point2 = point2;
+ m_point2Timestamp = timestamp != 0 ? timestamp : m_timer.elapsed();
+ m_timer.invalidate();
+}
+
+void QQuickVelocityCalculator::reset()
+{
+ m_point1 = QPointF();
+ m_point2 = QPointF();
+ m_point1Timestamp = 0;
+ m_point2Timestamp = 0;
+ m_timer.invalidate();
+}
+
+QPointF QQuickVelocityCalculator::velocity() const
+{
+ if ((m_point2Timestamp == 0 || m_point1Timestamp == m_point2Timestamp) && !m_timer.isValid())
+ return QPointF();
+
+ const qreal secondsElapsed = (m_point2Timestamp != 0 ? m_point2Timestamp - m_point1Timestamp : m_timer.elapsed()) / 1000.0;
+ const QPointF distance = m_point2 - m_point1;
+ return distance / secondsElapsed;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickvelocitycalculator_p_p.h b/src/quicktemplates2/qquickvelocitycalculator_p_p.h
new file mode 100644
index 0000000000..2b13ff07e4
--- /dev/null
+++ b/src/quicktemplates2/qquickvelocitycalculator_p_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKVELOCITYCALCULATOR_P_P_H
+#define QQUICKVELOCITYCALCULATOR_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 <QtCore/qpoint.h>
+#include <QtCore/qelapsedtimer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickVelocityCalculator
+{
+public:
+ void startMeasuring(const QPointF &point1, qint64 timestamp = 0);
+ void stopMeasuring(const QPointF &m_point2, qint64 timestamp = 0);
+ void reset();
+ QPointF velocity() const;
+
+private:
+ QPointF m_point1;
+ QPointF m_point2;
+ qint64 m_point1Timestamp = 0;
+ qint64 m_point2Timestamp = 0;
+ // When a timestamp isn't available, we must use a timer.
+ // When stopMeasuring() has been called, we store the elapsed time in point2timestamp.
+ QElapsedTimer m_timer;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKVELOCITYCALCULATOR_P_P_H
diff --git a/src/quicktemplates2/qt_cmdline.cmake b/src/quicktemplates2/qt_cmdline.cmake
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/quicktemplates2/qt_cmdline.cmake
diff --git a/src/quicktemplates2/qtquicktemplates2global.cpp b/src/quicktemplates2/qtquicktemplates2global.cpp
new file mode 100644
index 0000000000..5100e610bc
--- /dev/null
+++ b/src/quicktemplates2/qtquicktemplates2global.cpp
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtquicktemplates2global_p.h"
+
+#include <QtGui/qtguiglobal.h>
+
+#if QT_CONFIG(accessibility)
+#include "qquickpage_p.h"
+#include "accessible/qaccessiblequickpage_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if QT_CONFIG(accessibility)
+static QAccessibleInterface *qQuickAccessibleFactory(const QString &classname, QObject *object)
+{
+ if (classname == u"QQuickPage") {
+ return new QAccessibleQuickPage(qobject_cast<QQuickPage *>(object));
+ }
+ return nullptr;
+}
+#endif
+
+void QQuickTemplates_initializeModule()
+{
+#if QT_CONFIG(accessibility)
+ QAccessible::installFactory(&qQuickAccessibleFactory);
+#endif
+}
+
+Q_CONSTRUCTOR_FUNCTION(QQuickTemplates_initializeModule)
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qtquicktemplates2global_p.h b/src/quicktemplates2/qtquicktemplates2global_p.h
new file mode 100644
index 0000000000..db848229d5
--- /dev/null
+++ b/src/quicktemplates2/qtquicktemplates2global_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTQUICKTEMPLATES2GLOBAL_P_H
+#define QTQUICKTEMPLATES2GLOBAL_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>
+#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2-config_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_STATIC
+# if defined(QT_BUILD_QUICKTEMPLATES2_LIB)
+# define Q_QUICKTEMPLATES2_PRIVATE_EXPORT Q_DECL_EXPORT
+# else
+# define Q_QUICKTEMPLATES2_PRIVATE_EXPORT Q_DECL_IMPORT
+# endif
+#else
+# define Q_QUICKTEMPLATES2_PRIVATE_EXPORT
+#endif
+
+Q_QUICKTEMPLATES2_PRIVATE_EXPORT void QQuickTemplates_initializeModule();
+
+QT_END_NAMESPACE
+
+Q_QUICKTEMPLATES2_PRIVATE_EXPORT void qml_register_types_QtQuick_Templates();
+
+#endif // QTQUICKTEMPLATES2GLOBAL_P_H
diff --git a/src/quicktemplates2/qtquicktemplates2plugin.cpp b/src/quicktemplates2/qtquicktemplates2plugin.cpp
new file mode 100644
index 0000000000..0c0683e834
--- /dev/null
+++ b/src/quicktemplates2/qtquicktemplates2plugin.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqmlextensionplugin.h>
+#include <QtQml/private/qqmlglobal_p.h>
+#include <QtQuickTemplates2/private/qtquicktemplates2global_p.h>
+
+#if QT_CONFIG(shortcut)
+#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h>
+
+// qtdeclarative/src/quick/util/qquickshortcut.cpp
+typedef bool (*ShortcutContextMatcher)(QObject *, Qt::ShortcutContext);
+extern ShortcutContextMatcher qt_quick_shortcut_context_matcher();
+extern void qt_quick_set_shortcut_context_matcher(ShortcutContextMatcher matcher);
+#endif
+
+Q_GHS_KEEP_REFERENCE(qml_register_types_QtQuick_Templates);
+Q_GHS_KEEP_REFERENCE(QQuickTemplates_initializeModule);
+
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickTemplates2Plugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuickTemplates2Plugin(QObject *parent = nullptr);
+ ~QtQuickTemplates2Plugin();
+
+ void registerTypes(const char *uri) override;
+ void unregisterTypes() override;
+
+private:
+ bool registered;
+#if QT_CONFIG(shortcut)
+ ShortcutContextMatcher originalContextMatcher;
+#endif
+};
+
+QtQuickTemplates2Plugin::QtQuickTemplates2Plugin(QObject *parent)
+ : QQmlExtensionPlugin(parent), registered(false)
+{
+ volatile auto registration = &qml_register_types_QtQuick_Templates;
+ volatile auto initialization = &QQuickTemplates_initializeModule;
+
+ Q_UNUSED(registration)
+ Q_UNUSED(initialization)
+}
+
+QtQuickTemplates2Plugin::~QtQuickTemplates2Plugin()
+{
+ // Intentionally empty: we use register/unregisterTypes() to do
+ // initialization and cleanup, as plugins are not unloaded on macOS.
+}
+
+void QtQuickTemplates2Plugin::registerTypes(const char * /*uri*/)
+{
+#if QT_CONFIG(shortcut)
+ originalContextMatcher = qt_quick_shortcut_context_matcher();
+ qt_quick_set_shortcut_context_matcher(QQuickShortcutContext::matcher);
+#endif
+
+ registered = true;
+}
+
+void QtQuickTemplates2Plugin::unregisterTypes()
+{
+#if QT_CONFIG(shortcut)
+ qt_quick_set_shortcut_context_matcher(originalContextMatcher);
+#endif
+}
+
+QT_END_NAMESPACE
+
+#include "qtquicktemplates2plugin.moc"
diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri
new file mode 100644
index 0000000000..0f19de5e9d
--- /dev/null
+++ b/src/quicktemplates2/quicktemplates2.pri
@@ -0,0 +1,182 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qquickabstractbutton_p.h \
+ $$PWD/qquickabstractbutton_p_p.h \
+ $$PWD/qquickaction_p.h \
+ $$PWD/qquickactiongroup_p.h \
+ $$PWD/qquickapplicationwindow_p.h \
+ $$PWD/qquickbusyindicator_p.h \
+ $$PWD/qquickbutton_p.h \
+ $$PWD/qquickbutton_p_p.h \
+ $$PWD/qquickbuttongroup_p.h \
+ $$PWD/qquickcheckbox_p.h \
+ $$PWD/qquickcheckdelegate_p.h \
+ $$PWD/qquickcombobox_p.h \
+ $$PWD/qquickcontainer_p.h \
+ $$PWD/qquickcontainer_p_p.h \
+ $$PWD/qquickcontentitem_p.h \
+ $$PWD/qquickcontrol_p.h \
+ $$PWD/qquickcontrol_p_p.h \
+ $$PWD/qquickdeferredexecute_p_p.h \
+ $$PWD/qquickdeferredpointer_p_p.h \
+ $$PWD/qquickdelaybutton_p.h \
+ $$PWD/qquickdial_p.h \
+ $$PWD/qquickdialog_p.h \
+ $$PWD/qquickdialog_p_p.h \
+ $$PWD/qquickdialogbuttonbox_p.h \
+ $$PWD/qquickdialogbuttonbox_p_p.h \
+ $$PWD/qquickdrawer_p.h \
+ $$PWD/qquickdrawer_p_p.h \
+ $$PWD/qquickframe_p.h \
+ $$PWD/qquickframe_p_p.h \
+ $$PWD/qquickgroupbox_p.h \
+ $$PWD/qquickheaderview_p.h \
+ $$PWD/qquickheaderview_p_p.h \
+ $$PWD/qquickicon_p.h \
+ $$PWD/qquickindicatorbutton_p.h \
+ $$PWD/qquickitemdelegate_p.h \
+ $$PWD/qquickitemdelegate_p_p.h \
+ $$PWD/qquicklabel_p.h \
+ $$PWD/qquicklabel_p_p.h \
+ $$PWD/qquickmenu_p.h \
+ $$PWD/qquickmenu_p_p.h \
+ $$PWD/qquickmenubar_p.h \
+ $$PWD/qquickmenubar_p_p.h \
+ $$PWD/qquickmenubaritem_p.h \
+ $$PWD/qquickmenubaritem_p_p.h \
+ $$PWD/qquickmenuitem_p.h \
+ $$PWD/qquickmenuitem_p_p.h \
+ $$PWD/qquickmenuseparator_p.h \
+ $$PWD/qquickoverlay_p.h \
+ $$PWD/qquickoverlay_p_p.h \
+ $$PWD/qquickpage_p.h \
+ $$PWD/qquickpage_p_p.h \
+ $$PWD/qquickpageindicator_p.h \
+ $$PWD/qquickpane_p.h \
+ $$PWD/qquickpane_p_p.h \
+ $$PWD/qquickpopup_p.h \
+ $$PWD/qquickpopup_p_p.h \
+ $$PWD/qquickpopupanchors_p.h \
+ $$PWD/qquickpopupanchors_p_p.h \
+ $$PWD/qquickpopupitem_p_p.h \
+ $$PWD/qquickpopuppositioner_p_p.h \
+ $$PWD/qquickpresshandler_p_p.h \
+ $$PWD/qquickprogressbar_p.h \
+ $$PWD/qquickradiobutton_p.h \
+ $$PWD/qquickradiodelegate_p.h \
+ $$PWD/qquickrangeslider_p.h \
+ $$PWD/qquickroundbutton_p.h \
+ $$PWD/qquickscrollbar_p.h \
+ $$PWD/qquickscrollbar_p_p.h \
+ $$PWD/qquickscrollindicator_p.h \
+ $$PWD/qquickscrollview_p.h \
+ $$PWD/qquickselectionrectangle_p.h \
+ $$PWD/qquickselectionrectangle_p_p.h \
+ $$PWD/qquickshortcutcontext_p_p.h \
+ $$PWD/qquickslider_p.h \
+ $$PWD/qquickspinbox_p.h \
+ $$PWD/qquicksplitview_p.h \
+ $$PWD/qquickstackelement_p_p.h \
+ $$PWD/qquickstacktransition_p_p.h \
+ $$PWD/qquickstackview_p.h \
+ $$PWD/qquickstackview_p_p.h \
+ $$PWD/qquickswipe_p.h \
+ $$PWD/qquickswipedelegate_p.h \
+ $$PWD/qquickswipedelegate_p_p.h \
+ $$PWD/qquickswipeview_p.h \
+ $$PWD/qquickswitch_p.h \
+ $$PWD/qquickswitchdelegate_p.h \
+ $$PWD/qquicktabbar_p.h \
+ $$PWD/qquicktabbutton_p.h \
+ $$PWD/qquicktextarea_p.h \
+ $$PWD/qquicktextarea_p_p.h \
+ $$PWD/qquicktextfield_p.h \
+ $$PWD/qquicktextfield_p_p.h \
+ $$PWD/qquicktheme_p.h \
+ $$PWD/qquicktheme_p_p.h \
+ $$PWD/qquicktoolbar_p.h \
+ $$PWD/qquicktoolbutton_p.h \
+ $$PWD/qquicktoolseparator_p.h \
+ $$PWD/qquicktooltip_p.h \
+ $$PWD/qquickvelocitycalculator_p_p.h
+
+SOURCES += \
+ $$PWD/qquickabstractbutton.cpp \
+ $$PWD/qquickaction.cpp \
+ $$PWD/qquickactiongroup.cpp \
+ $$PWD/qquickapplicationwindow.cpp \
+ $$PWD/qquickbusyindicator.cpp \
+ $$PWD/qquickbutton.cpp \
+ $$PWD/qquickbuttongroup.cpp \
+ $$PWD/qquickcheckbox.cpp \
+ $$PWD/qquickcheckdelegate.cpp \
+ $$PWD/qquickcombobox.cpp \
+ $$PWD/qquickcontainer.cpp \
+ $$PWD/qquickcontentitem.cpp \
+ $$PWD/qquickcontrol.cpp \
+ $$PWD/qquickdeferredexecute.cpp \
+ $$PWD/qquickdelaybutton.cpp \
+ $$PWD/qquickdial.cpp \
+ $$PWD/qquickdialog.cpp \
+ $$PWD/qquickdialogbuttonbox.cpp \
+ $$PWD/qquickdrawer.cpp \
+ $$PWD/qquickframe.cpp \
+ $$PWD/qquickgroupbox.cpp \
+ $$PWD/qquickheaderview.cpp \
+ $$PWD/qquickicon.cpp \
+ $$PWD/qquickindicatorbutton_p.cpp \
+ $$PWD/qquickitemdelegate.cpp \
+ $$PWD/qquicklabel.cpp \
+ $$PWD/qquickmenu.cpp \
+ $$PWD/qquickmenubar.cpp \
+ $$PWD/qquickmenubaritem.cpp \
+ $$PWD/qquickmenuitem.cpp \
+ $$PWD/qquickmenuseparator.cpp \
+ $$PWD/qquickoverlay.cpp \
+ $$PWD/qquickpage.cpp \
+ $$PWD/qquickpageindicator.cpp \
+ $$PWD/qquickpane.cpp \
+ $$PWD/qquickpopup.cpp \
+ $$PWD/qquickpopupanchors.cpp \
+ $$PWD/qquickpopupitem.cpp \
+ $$PWD/qquickpopuppositioner.cpp \
+ $$PWD/qquickpresshandler.cpp \
+ $$PWD/qquickprogressbar.cpp \
+ $$PWD/qquickradiobutton.cpp \
+ $$PWD/qquickradiodelegate.cpp \
+ $$PWD/qquickrangeslider.cpp \
+ $$PWD/qquickroundbutton.cpp \
+ $$PWD/qquickscrollbar.cpp \
+ $$PWD/qquickscrollindicator.cpp \
+ $$PWD/qquickscrollview.cpp \
+ $$PWD/qquickshortcutcontext.cpp \
+ $$PWD/qquickslider.cpp \
+ $$PWD/qquickspinbox.cpp \
+ $$PWD/qquicksplitview.cpp \
+ $$PWD/qquickstackelement.cpp \
+ $$PWD/qquickstacktransition.cpp \
+ $$PWD/qquickstackview.cpp \
+ $$PWD/qquickstackview_p.cpp \
+ $$PWD/qquickswipedelegate.cpp \
+ $$PWD/qquickswipeview.cpp \
+ $$PWD/qquickswitch.cpp \
+ $$PWD/qquickswitchdelegate.cpp \
+ $$PWD/qquicktabbar.cpp \
+ $$PWD/qquicktabbutton.cpp \
+ $$PWD/qquicktextarea.cpp \
+ $$PWD/qquicktextfield.cpp \
+ $$PWD/qquicktheme.cpp \
+ $$PWD/qquicktoolbar.cpp \
+ $$PWD/qquicktoolbutton.cpp \
+ $$PWD/qquicktoolseparator.cpp \
+ $$PWD/qquicktooltip.cpp \
+ $$PWD/qquickvelocitycalculator.cpp
+
+qtConfig(quick-listview):qtConfig(quick-pathview) {
+ HEADERS += \
+ $$PWD/qquicktumbler_p.h \
+ $$PWD/qquicktumbler_p_p.h
+ SOURCES += \
+ $$PWD/qquicktumbler.cpp
+}
diff --git a/src/quicktestutils/CMakeLists.txt b/src/quicktestutils/CMakeLists.txt
new file mode 100644
index 0000000000..ce629037e8
--- /dev/null
+++ b/src/quicktestutils/CMakeLists.txt
@@ -0,0 +1,45 @@
+if(TARGET Qt::Quick)
+ set (quick_sources
+ quick/geometrytestutils.cpp
+ quick/geometrytestutils_p.h
+ quick/viewtestutils.cpp
+ quick/viewtestutils_p.h
+ quick/visualtestutils.cpp
+ quick/visualtestutils_p.h
+ )
+endif()
+
+qt_internal_add_module(QuickTestUtilsPrivate
+ CONFIG_MODULE_NAME quicktestutilsprivate
+ STATIC
+ INTERNAL_MODULE
+ SOURCES
+ qml/platforminputcontext_p.h
+ qml/platformquirks_p.h
+ qml/qmlutils.cpp
+ qml/qmlutils_p.h
+ qml/qqmljsastdumper.cpp
+ qml/qqmljsastdumper_p.h
+ qml/testhttpserver.cpp
+ qml/testhttpserver_p.h
+ ${quick_sources}
+ DEFINES
+ QT_BUILD_SHARED_QML_TEST_UTILS_LIB
+ INCLUDE_DIRECTORIES
+ ${CMAKE_CURRENT_SOURCE_DIR}
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::Test
+ Qt::Network
+ Qt::Qml
+ Qt::QmlPrivate
+)
+
+if(TARGET Qt::Quick)
+ qt_internal_extend_target(QuickTestUtilsPrivate
+ LIBRARIES
+ Qt::Quick
+ Qt::QuickPrivate
+ Qt::QuickTest
+ )
+endif()
diff --git a/src/quicktestutils/qml/platforminputcontext_p.h b/src/quicktestutils/qml/platforminputcontext_p.h
new file mode 100644
index 0000000000..2f75767409
--- /dev/null
+++ b/src/quicktestutils/qml/platforminputcontext_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLATFORMINPUTCONTEXT_P_H
+#define PLATFORMINPUTCONTEXT_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 <qpa/qplatforminputcontext.h>
+#include <QtGui/QInputMethod>
+
+QT_BEGIN_NAMESPACE
+
+class PlatformInputContext : public QPlatformInputContext
+{
+public:
+ PlatformInputContext()
+ : m_visible(false), m_action(QInputMethod::Click), m_cursorPosition(0),
+ m_invokeActionCallCount(0), m_showInputPanelCallCount(0), m_hideInputPanelCallCount(0),
+ m_updateCallCount(0), m_direction(Qt::LeftToRight)
+ {
+ }
+
+ void showInputPanel() override
+ {
+ m_visible = true;
+ m_showInputPanelCallCount++;
+ }
+ void hideInputPanel() override
+ {
+ m_visible = false;
+ m_hideInputPanelCallCount++;
+ }
+ bool isInputPanelVisible() const override
+ {
+ return m_visible;
+ }
+ void invokeAction(QInputMethod::Action action, int cursorPosition) override
+ {
+ m_invokeActionCallCount++;
+ m_action = action;
+ m_cursorPosition = cursorPosition;
+ }
+ void update(Qt::InputMethodQueries) override
+ {
+ m_updateCallCount++;
+ }
+
+ QLocale locale() const override
+ {
+ if (m_direction == Qt::RightToLeft)
+ return QLocale(QLocale::Arabic);
+ else
+ return QLocale(QLocale::English);
+ }
+
+ Qt::LayoutDirection inputDirection() const override
+ {
+ return m_direction;
+ }
+
+ void setInputDirection(Qt::LayoutDirection direction) {
+ m_direction = direction;
+ emitLocaleChanged();
+ emitInputDirectionChanged(inputDirection());
+ }
+
+ void clear() {
+ m_cursorPosition = 0;
+ m_invokeActionCallCount = 0;
+ m_visible = false;
+ m_showInputPanelCallCount = 0;
+ m_hideInputPanelCallCount = 0;
+ m_updateCallCount = 0;
+ }
+
+ bool m_visible;
+ QInputMethod::Action m_action;
+ int m_cursorPosition;
+ int m_invokeActionCallCount;
+ int m_showInputPanelCallCount;
+ int m_hideInputPanelCallCount;
+ int m_updateCallCount;
+ Qt::LayoutDirection m_direction;
+};
+
+QT_END_NAMESPACE
+
+#endif // PLATFORMINPUTCONTEXT_P_H
diff --git a/src/quicktestutils/qml/platformquirks_p.h b/src/quicktestutils/qml/platformquirks_p.h
new file mode 100644
index 0000000000..16aa160d7c
--- /dev/null
+++ b/src/quicktestutils/qml/platformquirks_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PLATFORMQUIRKS_P_H
+#define PLATFORMQUIRKS_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 <qglobal.h>
+
+#ifdef Q_OS_OSX
+#include <Carbon/Carbon.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+struct PlatformQuirks
+{
+ static inline bool isClipboardAvailable()
+ {
+#if !QT_CONFIG(clipboard)
+ return false;
+#elif defined(Q_OS_OSX)
+ PasteboardRef pasteboard;
+ OSStatus status = PasteboardCreate(0, &pasteboard);
+ if (status == noErr)
+ CFRelease(pasteboard);
+ return status == noErr;
+#else
+ return true;
+#endif
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/quicktestutils/qml/qmlutils.cpp b/src/quicktestutils/qml/qmlutils.cpp
new file mode 100644
index 0000000000..2398ce20a3
--- /dev/null
+++ b/src/quicktestutils/qml/qmlutils.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmlutils_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QMutexLocker>
+#include <QtQml/QQmlComponent>
+#include <QtQml/QQmlEngine>
+
+QT_BEGIN_NAMESPACE
+
+QQmlDataTest *QQmlDataTest::m_instance = 0;
+
+QQmlDataTest::QQmlDataTest(const char *qmlTestDataDir) :
+ m_qmlTestDataDir(qmlTestDataDir),
+#ifdef QT_TESTCASE_BUILDDIR
+ m_dataDirectory(QTest::qFindTestData("data", m_qmlTestDataDir, 0, QT_TESTCASE_BUILDDIR)),
+#else
+ m_dataDirectory(QTest::qFindTestData("data", m_qmlTestDataDir, 0)),
+#endif
+
+ m_dataDirectoryUrl(m_dataDirectory.startsWith(QLatin1Char(':'))
+ ? QUrl(QLatin1String("qrc") + m_dataDirectory + QLatin1Char('/'))
+ : QUrl::fromLocalFile(m_dataDirectory + QLatin1Char('/')))
+{
+ m_instance = this;
+}
+
+QQmlDataTest::~QQmlDataTest()
+{
+ m_instance = 0;
+}
+
+void QQmlDataTest::initTestCase()
+{
+ QVERIFY2(!m_dataDirectory.isEmpty(), qPrintable(QLatin1String(
+ "'data' directory not found in ") + QFileInfo(QString::fromUtf8(m_qmlTestDataDir)).absolutePath()));
+ m_directory = QFileInfo(m_dataDirectory).absolutePath();
+ if (m_dataDirectoryUrl.scheme() != QLatin1String("qrc"))
+ QVERIFY2(QDir::setCurrent(m_directory), qPrintable(QLatin1String("Could not chdir to ") + m_directory));
+}
+
+QString QQmlDataTest::testFile(const QString &fileName) const
+{
+ if (m_directory.isEmpty())
+ qFatal("QQmlDataTest::initTestCase() not called.");
+ QString result = m_dataDirectory;
+ result += QLatin1Char('/');
+ result += fileName;
+ return result;
+}
+
+bool QQmlDataTest::canImportModule(const QString &importTestQmlSource) const
+{
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(importTestQmlSource.toLatin1(), QUrl());
+ return !component.isError();
+}
+
+Q_GLOBAL_STATIC(QMutex, qQmlTestMessageHandlerMutex)
+
+QQmlTestMessageHandler *QQmlTestMessageHandler::m_instance = 0;
+
+void QQmlTestMessageHandler::messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message)
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ if (QQmlTestMessageHandler::m_instance) {
+ if (QQmlTestMessageHandler::m_instance->m_includeCategories) {
+ QQmlTestMessageHandler::m_instance->m_messages.push_back(
+ QString::fromLatin1("%1: %2").arg(QString::fromUtf8(context.category), message));
+ } else {
+ QQmlTestMessageHandler::m_instance->m_messages.push_back(message);
+ }
+ }
+}
+
+QQmlTestMessageHandler::QQmlTestMessageHandler()
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ Q_ASSERT(!QQmlTestMessageHandler::m_instance);
+ QQmlTestMessageHandler::m_instance = this;
+ m_oldHandler = qInstallMessageHandler(messageHandler);
+ m_includeCategories = false;
+}
+
+QQmlTestMessageHandler::~QQmlTestMessageHandler()
+{
+ QMutexLocker locker(qQmlTestMessageHandlerMutex());
+ Q_ASSERT(QQmlTestMessageHandler::m_instance);
+ qInstallMessageHandler(m_oldHandler);
+ QQmlTestMessageHandler::m_instance = 0;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qmlutils_p.cpp"
diff --git a/src/quicktestutils/qml/qmlutils_p.h b/src/quicktestutils/qml/qmlutils_p.h
new file mode 100644
index 0000000000..9df1ac2f1b
--- /dev/null
+++ b/src/quicktestutils/qml/qmlutils_p.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLTESTUTILS_P_H
+#define QQMLTESTUTILS_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/QDir>
+#include <QtCore/QUrl>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QStringList>
+#include <QtTest/QTest>
+
+QT_BEGIN_NAMESPACE
+
+/* Base class for tests with data that are located in a "data" subfolder. */
+
+class QQmlDataTest : public QObject
+{
+ Q_OBJECT
+public:
+ QQmlDataTest(const char *qmlTestDataDir);
+ virtual ~QQmlDataTest();
+
+ QString testFile(const QString &fileName) const;
+ inline QString testFile(const char *fileName) const
+ { return testFile(QLatin1String(fileName)); }
+ inline QUrl testFileUrl(const QString &fileName) const
+ {
+ const QString fn = testFile(fileName);
+ return fn.startsWith(QLatin1Char(':'))
+ ? QUrl(QLatin1String("qrc") + fn)
+ : QUrl::fromLocalFile(fn);
+ }
+ inline QUrl testFileUrl(const char *fileName) const
+ { return testFileUrl(QLatin1String(fileName)); }
+
+ inline QString dataDirectory() const { return m_dataDirectory; }
+ inline QUrl dataDirectoryUrl() const { return m_dataDirectoryUrl; }
+ inline QString directory() const { return m_directory; }
+
+ static inline QQmlDataTest *instance() { return m_instance; }
+
+ bool canImportModule(const QString &importTestQmlSource) const;
+
+public slots:
+ virtual void initTestCase();
+
+private:
+ static QQmlDataTest *m_instance;
+
+ // The directory in which to search for the "data" directory.
+ const char *m_qmlTestDataDir = nullptr;
+ // The path to the "data" directory, if found.
+ const QString m_dataDirectory;
+ const QUrl m_dataDirectoryUrl;
+ QString m_directory;
+};
+
+class QQmlTestMessageHandler
+{
+ Q_DISABLE_COPY(QQmlTestMessageHandler)
+public:
+ QQmlTestMessageHandler();
+ ~QQmlTestMessageHandler();
+
+ const QStringList &messages() const { return m_messages; }
+ const QString messageString() const { return m_messages.join(QLatin1Char('\n')); }
+
+ void clear() { m_messages.clear(); }
+
+ void setIncludeCategoriesEnabled(bool enabled) { m_includeCategories = enabled; }
+
+private:
+ static void messageHandler(QtMsgType, const QMessageLogContext &context, const QString &message);
+
+ static QQmlTestMessageHandler *m_instance;
+ QStringList m_messages;
+ QtMessageHandler m_oldHandler;
+ bool m_includeCategories;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLTESTUTILS_P_H
diff --git a/src/quicktestutils/qml/qqmljsastdumper.cpp b/src/quicktestutils/qml/qqmljsastdumper.cpp
new file mode 100644
index 0000000000..4882d6c1ff
--- /dev/null
+++ b/src/quicktestutils/qml/qqmljsastdumper.cpp
@@ -0,0 +1,1088 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**/
+#include "qqmljsastdumper_p.h"
+#include <private/qqmljsast_p.h>
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <QtCore/QTextStream>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+using namespace AST;
+/*!
+\internal
+\enum QQmlJS::DumperOptions
+
+This enum type specifies the options for the AstDumper.
+The values can be combined with the '|' operator, and checked using the '&' operator.
+
+\value None
+ Default dumping options
+\value NoLocations
+ Does not dump SourceLocations, allowing one to compare equivalent AST
+ generated by code formatted differently
+\value NoAnnotations
+ Does not dump annotations
+\value DumpNode
+ Does dump a <Node></Node> in preVisit/postVisit
+*/
+
+/*!
+\internal
+\class QQmlJS::AstDumper
+\brief Dumps or compares AST in an xml like format, mostly for testing/debugging
+
+Initialize it with a lambda that dumps a string, and configure it with .setX methods.
+If \l{indent} is set to a non zero value the xml is indented by that amount, and
+\l{baseIndent} is the initial indent.
+If \l{emitNode} is true the node tag is emitted in the preVisit/postVisit.
+If \l{emitLocation} is true the SourceLocations are emitted.
+If \l{emitAnnotations} is true annotations are emitted
+
+The implementation has unnecessary roundtrips to QString, but it is supposed to be used
+for debugging purposes...
+
+Probably you will not use the visitor at all but rather the static method diff or
+the qDebug() and ostream operator << that use the visitor...
+
+\fn AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent)
+
+\brief compares the two AST::Node n1 and n2 and returns a string describing their first difference
+
+If there are no differences the empty string is returned, so .isEmpty() can be use to check
+for no differences.
+\l{nContext} decides how much context is printed out.
+
+*/
+
+
+QDebug operator<<(QDebug d, AST::Node *n) {
+ QDebug noQuote = d.noquote().nospace();
+ AstDumper visitor([&noQuote](const QString &s){ noQuote << s; });
+ Node::accept(n, &visitor);
+ return d;
+}
+
+
+std::ostream &operator<<(std::ostream &stream, AST::Node *n) {
+ AstDumper visitor([&stream](const QString &s){ stream << s.toStdString(); });
+ Node::accept(n, &visitor);
+ return stream;
+}
+
+bool operator & (DumperOptions lhs, DumperOptions rhs) {
+ return bool(static_cast<int>(lhs) & static_cast<int>(rhs));
+}
+
+DumperOptions operator | (DumperOptions lhs, DumperOptions rhs) {
+ return DumperOptions(static_cast<int>(lhs) | static_cast<int>(rhs));
+}
+
+QString AstDumper::diff(AST::Node *n1, AST::Node *n2, int nContext, DumperOptions opt, int indent) {
+ QString s1, s2;
+ QTextStream d1(&s1), d2(&s2);
+ AstDumper visitor1=AstDumper([&d1](const QString &s){ d1 << s; }, opt, indent);
+ AstDumper visitor2=AstDumper([&d2](const QString &s){ d2 << s; }, opt, indent);
+ Node::accept(n1, &visitor1);
+ Node::accept(n2, &visitor2);
+ d1.seek(0);
+ d2.seek(0);
+ std::vector<QString> preLines(nContext);
+ int nLine = 0;
+ bool same = true;
+ QString l1, l2;
+ while (same && !d1.atEnd() && !d2.atEnd()) {
+ l1=d1.readLine();
+ l2=d2.readLine();
+ if (l1 == l2)
+ preLines[nLine++ % nContext] = l1;
+ else
+ same = false;
+ }
+ QString res;
+ QTextStream ss(&res);
+ if (!same || !d1.atEnd() || !d2.atEnd()) {
+ for (int iline = qMin(nLine, nContext); iline > 0; --iline) {
+ ss << QLatin1String(" ") << preLines[(nLine - iline) % nContext] << QLatin1String("\n");
+ }
+ int iline = 0;
+ if (!same) {
+ ss << QLatin1String("-") << l1 << QLatin1String("\n");
+ ++iline;
+ }
+ if (same && nContext == 0)
+ nContext = 1;
+ for (;iline < nContext && !d1.atEnd(); iline ++) {
+ l1 = d1.readLine();
+ ss << QLatin1String("-") << l1 << QLatin1String("\n");
+ }
+ iline = 0;
+ if (!same) {
+ ss << QLatin1String("+") << l2 << QLatin1String("\n");
+ ++iline;
+ }
+ for (;iline < nContext && !d2.atEnd(); iline ++) {
+ l2 = d2.readLine();
+ ss << QLatin1String("+") << l2 << QLatin1String("\n");
+ }
+ }
+ return res;
+}
+
+QString AstDumper::printNode(Node *n, DumperOptions opt, int indent, int baseIndent)
+{
+ QString res;
+ QTextStream d(&res);
+ AstDumper visitor=AstDumper([&d](const QString &s){ d << s; }, opt, indent, baseIndent);
+ Node::accept(n, &visitor);
+ return res;
+}
+
+AstDumper::AstDumper(const std::function<void(const QString &)> &dumper, DumperOptions options, int indent, int baseIndent):
+ dumper(dumper), options(options), indent(indent), baseIndent(baseIndent) {}
+
+void AstDumper::start(const QString &str) {
+ dumper(QString::fromLatin1(" ").repeated(baseIndent));
+ dumper(QLatin1String("<"));
+ dumper(str);
+ dumper(QLatin1String(">\n"));
+ baseIndent += indent;
+}
+
+void AstDumper::start(const char *str) {
+ start(QLatin1String(str));
+}
+
+void AstDumper::stop(const QString &str) {
+ baseIndent -= indent;
+ dumper(QString::fromLatin1(" ").repeated(baseIndent));
+ dumper(QLatin1String("</"));
+ dumper(str);
+ dumper(QLatin1String(">\n"));
+}
+
+void AstDumper::stop(const char *str) {
+ stop(QLatin1String(str));
+}
+
+QString AstDumper::qs(const QString &s) {
+ QString res(s);
+ return QLatin1String("\"") + res
+ .replace(QLatin1String("\\"), QLatin1String("\\\\"))
+ .replace(QLatin1String("\""), QLatin1String("\\\"")) + QLatin1String("\"");
+}
+
+QString AstDumper::qs(const char *s) {
+ return qs(QLatin1String(s));
+}
+
+QString AstDumper::qs(QStringView s) {
+ return qs(s.toString());
+}
+
+QString AstDumper::loc(const SourceLocation &s) {
+ if (noLocations() || !s.isValid())
+ return QLatin1String("\"\"");
+ else {
+ return QLatin1String("\"off:%1 len:%2 l:%3 c:%4\"").arg(QString::number(s.offset), QString::number(s.length), QString::number(s.startLine), QString::number(s.startColumn));
+ }
+}
+
+QString AstDumper::boolStr(bool v) { return (v ? qs("true"): qs("false")); }
+
+bool AstDumper::preVisit(Node *) { if (dumpNode()) start("Node"); return true; }
+
+void AstDumper::postVisit(Node *) { if (dumpNode()) stop("Node"); }
+
+bool AstDumper::visit(UiProgram *) { start("UiProgram"); return true; }
+
+bool AstDumper::visit(UiHeaderItemList *) { start("UiHeaderItemList"); return true; }
+
+bool AstDumper::visit(UiPragma *el) {
+ start(QLatin1String("UiPragma name=%1 pragmaToken=%2 semicolonToken=%3")
+ .arg(qs(el->name), loc(el->pragmaToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiImport *el)
+{
+ start(QLatin1String("UiImport fileName=%1 importId=%2 importToken=%3 fileNameToken=%4 asToken=%5 importIdToken=%6 semicolonToken=%7")
+ .arg(qs(el->fileName), qs(el->importId), loc(el->importToken), loc(el->fileNameToken), loc(el->asToken), loc(el->importIdToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiPublicMember *el) {
+ QString typeStr = ((el->type == UiPublicMember::Signal) ? QLatin1String("Signal") :
+ (el->type == UiPublicMember::Property) ? QLatin1String("Property") : QStringLiteral("Unexpected(%1)").arg(el->type));
+ start(QLatin1String("UiPublicMember type=%1 typeModifier=%2 name=%3 isDefaultMember=%4 isReadonlyMember=%5 isRequired=%6 "
+ "defaultToken=%7 readonlyToken=%8 propertyToken=%9 requiredToken=%10 typeModifierToken=%11 typeToken=%12 "
+ "identifierToken=%13 colonToken=%14 semicolonToken=%15")
+ .arg(qs(typeStr), qs(el->typeModifier), qs(el->name),
+ boolStr(el->isDefaultMember), boolStr(el->isReadonlyMember), boolStr(el->isRequired),
+ loc(el->defaultToken), loc(el->readonlyToken), loc(el->propertyToken),
+ loc(el->requiredToken), loc(el->typeModifierToken), loc(el->typeToken),
+ loc(el->identifierToken), loc(el->colonToken), loc(el->semicolonToken)
+ ));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ Node::accept(el->memberType, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiSourceElement *el) {
+ start(QLatin1String("UiSourceElement"));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectDefinition *el) {
+ start("UiObjectDefinition");
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectInitializer *el) {
+ start(QLatin1String("UiObjectInitializer lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectBinding *el) {
+ start(QLatin1String("UiObjectBinding colonToken=%1 hasOnToken=%2")
+ .arg(loc(el->colonToken), boolStr(el->hasOnToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiScriptBinding *el) {
+ start(QLatin1String("UiScriptBinding colonToken=%1")
+ .arg(loc(el->colonToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiArrayBinding *el) {
+ start(QLatin1String("UiArrayBinding colonToken=%1 lbracketToken=%2 rbracketToken=%3")
+ .arg(loc(el->colonToken), loc(el->lbracketToken), loc(el->rbracketToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiParameterList *el) {
+ start(QLatin1String("UiArrayBinding name=%1 commaToken=%2 propertyTypeToken=%3 identifierToken=%4 colonToken=%5")
+ .arg(qs(el->name), loc(el->commaToken), loc(el->propertyTypeToken), loc(el->identifierToken), loc(el->colonToken)));
+ Node::accept(el->type, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiObjectMemberList *) { start("UiObjectMemberList"); return true; }
+
+bool AstDumper::visit(AST::UiArrayMemberList *el) {
+ start(QLatin1String("UiArrayMemberList commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiQualifiedId *el) {
+ start(QLatin1String("UiQualifiedId name=%1 identifierToken=%2")
+ .arg(qs(el->name), loc(el->identifierToken)));
+ Node::accept(el->next, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiEnumDeclaration *el) {
+ start(QLatin1String("UiEnumDeclaration enumToken=%1 rbraceToken=%2 name=%3")
+ .arg(loc(el->enumToken), loc(el->rbraceToken), qs(el->name)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(AST::UiEnumMemberList *el) {
+ start(QLatin1String("UiEnumMemberList member=%1 value=%2 memberToken=%3 valueToken=%4")
+ .arg(qs(el->member), qs(QString::number(el->value)), loc(el->memberToken), loc(el->valueToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiVersionSpecifier *el) {
+ start(QLatin1String("UiVersionSpecifier majorVersion=%1 minorVersion=%2 majorToken=%3 minorToken=%4")
+ .arg(qs(QString::number(el->version.majorVersion())),
+ qs(QString::number(el->version.minorVersion())),
+ loc(el->majorToken), loc(el->minorToken)));
+ return true;
+}
+
+bool AstDumper::visit(AST::UiInlineComponent *el) {
+ start(QLatin1String("UiInlineComponent name=%1 componentToken=%2")
+ .arg(qs(el->name), loc(el->componentToken)));
+ if (!noAnnotations()) // put annotations inside the node they refer to
+ Node::accept(el->annotations, this);
+ return true;
+}
+
+bool AstDumper::visit(UiRequired *el)
+{
+ start(QLatin1String("UiRequired name=%1 requiredToken=%2 semicolonToken=%3")
+ .arg(qs(el->name), loc(el->requiredToken), loc(el->semicolonToken)));
+ return true;
+}
+
+bool AstDumper::visit(UiAnnotation *)
+{
+ start(QLatin1String("UiAnnotation"));
+ return true;
+}
+
+bool AstDumper::visit(UiAnnotationList *)
+{
+ start(QLatin1String("UiAnnotationList"));
+ return true;
+}
+
+void AstDumper::endVisit(AST::UiProgram *) { stop("UiProgram"); }
+
+void AstDumper::endVisit(AST::UiImport *el) {
+ Node::accept(el->version, this);
+ stop("UiImport");
+}
+
+void AstDumper::endVisit(AST::UiHeaderItemList *) { stop("UiHeaderItemList"); }
+
+void AstDumper::endVisit(AST::UiPragma *) { stop("UiPragma"); }
+
+void AstDumper::endVisit(AST::UiPublicMember *el) {
+ Node::accept(el->parameters, this);
+ stop("UiPublicMember");
+}
+
+void AstDumper::endVisit(AST::UiSourceElement *) { stop("UiSourceElement"); }
+void AstDumper::endVisit(AST::UiObjectDefinition *) { stop("UiObjectDefinition"); }
+void AstDumper::endVisit(AST::UiObjectInitializer *) { stop("UiObjectInitializer"); }
+void AstDumper::endVisit(AST::UiObjectBinding *) { stop("UiObjectBinding"); }
+void AstDumper::endVisit(AST::UiScriptBinding *) { stop("UiScriptBinding"); }
+void AstDumper::endVisit(AST::UiArrayBinding *) { stop("UiArrayBinding"); }
+void AstDumper::endVisit(AST::UiParameterList *el) {
+ stop("UiParameterList");
+ Node::accept(el->next, this); // put other args at the same level as this one...
+}
+void AstDumper::endVisit(AST::UiObjectMemberList *) { stop("UiObjectMemberList"); }
+void AstDumper::endVisit(AST::UiArrayMemberList *) { stop("UiArrayMemberList"); }
+void AstDumper::endVisit(AST::UiQualifiedId *) { stop("UiQualifiedId"); }
+void AstDumper::endVisit(AST::UiEnumDeclaration *) { stop("UiEnumDeclaration"); }
+void AstDumper::endVisit(AST::UiEnumMemberList *el) {
+ stop("UiEnumMemberList");
+ Node::accept(el->next, this); // put other enum members at the same level as this one...
+}
+void AstDumper::endVisit(AST::UiVersionSpecifier *) { stop("UiVersionSpecifier"); }
+void AstDumper::endVisit(AST::UiInlineComponent *) { stop("UiInlineComponent"); }
+void AstDumper::endVisit(UiRequired *) { stop("UiRequired"); }
+void AstDumper::endVisit(UiAnnotation *) { stop("UiAnnotation"); }
+void AstDumper::endVisit(UiAnnotationList *) { stop("UiAnnotationList"); }
+
+// QQmlJS
+bool AstDumper::visit(AST::TypeExpression *el) {
+ Q_UNUSED(el);
+ start("TypeExpression");
+ return true;
+}
+void AstDumper::endVisit(AST::TypeExpression *) { stop("TypeExpression"); }
+
+bool AstDumper::visit(AST::ThisExpression *el) {
+ start(QLatin1String("ThisExpression thisToken=%1")
+ .arg(loc(el->thisToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ThisExpression *) { stop("ThisExpression"); }
+
+bool AstDumper::visit(AST::IdentifierExpression *el) {
+ start(QLatin1String("IdentifierExpression name=%1 identiferToken=%2")
+ .arg(qs(el->name), loc(el->identifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IdentifierExpression *) { stop("IdentifierExpression"); }
+
+bool AstDumper::visit(AST::NullExpression *el) {
+ start(QLatin1String("NullExpression nullToken=%1")
+ .arg(loc(el->nullToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NullExpression *) { stop("NullExpression"); }
+
+bool AstDumper::visit(AST::TrueLiteral *el) {
+ start(QLatin1String("TrueLiteral trueToken=%1")
+ .arg(loc(el->trueToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TrueLiteral *) { stop("TrueLiteral"); }
+
+bool AstDumper::visit(AST::FalseLiteral *el) {
+ start(QLatin1String("FalseLiteral falseToken=%1")
+ .arg(loc(el->falseToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FalseLiteral *) { stop("FalseLiteral"); }
+
+bool AstDumper::visit(AST::SuperLiteral *el) {
+ start(QLatin1String("SuperLiteral superToken=%1")
+ .arg(loc(el->superToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::SuperLiteral *) { stop("SuperLiteral"); }
+
+bool AstDumper::visit(AST::StringLiteral *el) {
+ start(QLatin1String("StringLiteral value=%1 literalToken=%2")
+ .arg(qs(el->value), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::StringLiteral *) { stop("StringLiteral"); }
+
+bool AstDumper::visit(AST::TemplateLiteral *el) {
+ start(QLatin1String("TemplateLiteral value=%1 rawValue=%2 literalToken=%3")
+ .arg(qs(el->value), qs(el->rawValue), loc(el->literalToken)));
+ Node::accept(el->expression, this);
+ return true;
+}
+void AstDumper::endVisit(AST::TemplateLiteral *) { stop("TemplateLiteral"); }
+
+bool AstDumper::visit(AST::NumericLiteral *el) {
+ start(QLatin1String("NumericLiteral value=%1 literalToken=%2")
+ .arg(qs(QString::number(el->value)), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NumericLiteral *) { stop("NumericLiteral"); }
+
+bool AstDumper::visit(AST::RegExpLiteral *el) {
+ start(QLatin1String("RegExpLiteral pattern=%1 flags=%2 literalToken=%3")
+ .arg(qs(el->pattern), qs(QString::number(el->flags, 16)), loc(el->literalToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::RegExpLiteral *) { stop("RegExpLiteral"); }
+
+bool AstDumper::visit(AST::ArrayPattern *el) {
+ start(QLatin1String("ArrayPattern lbracketToken=%1, commaToken=%2, rbracketToken=%3 parseMode=%4")
+ .arg(loc(el->lbracketToken),loc(el->commaToken),loc(el->rbracketToken), qs(QString::number(el->parseMode, 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ArrayPattern *) { stop("ArrayPattern"); }
+
+bool AstDumper::visit(AST::ObjectPattern *el) {
+ start(QLatin1String("ObjectPattern lbraceToken=%1 rbraceToken=%2 parseMode=%3")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken), qs(QString::number(el->parseMode, 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ObjectPattern *) { stop("ObjectPattern"); }
+
+bool AstDumper::visit(AST::PatternElementList *) { start("PatternElementList"); return true; }
+void AstDumper::endVisit(AST::PatternElementList *) { stop("PatternElementList"); }
+
+bool AstDumper::visit(AST::PatternPropertyList *) { start("PatternPropertyList"); return true; }
+void AstDumper::endVisit(AST::PatternPropertyList *) { stop("PatternPropertyList"); }
+
+bool AstDumper::visit(AST::PatternElement *el) {
+ start(QLatin1String("PatternElement identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5")
+ .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)),
+ qs(QString::number(static_cast<int>(el->scope), 16)), boolStr(el->isForDeclaration)));
+ return true;
+}
+void AstDumper::endVisit(AST::PatternElement *) { stop("PatternElement"); }
+
+bool AstDumper::visit(AST::PatternProperty *el) {
+ start(QLatin1String("PatternProperty identifierToken=%1 bindingIdentifier=%2 type=%3 scope=%4 isForDeclaration=%5 colonToken=%6")
+ .arg(loc(el->identifierToken), qs(el->bindingIdentifier), qs(QString::number(el->type, 16)),
+ qs(QString::number(static_cast<int>(el->scope), 16)), boolStr(el->isForDeclaration), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PatternProperty *) { stop("PatternProperty"); }
+
+bool AstDumper::visit(AST::Elision *el) {
+ start(QLatin1String("Elision commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Elision *el) {
+ stop("Elision");
+ Node::accept(el->next, this); // emit other elisions at the same level
+}
+
+bool AstDumper::visit(AST::NestedExpression *el) {
+ start(QLatin1String("NestedExpression lparenToken=%1 rparenToken=%2")
+ .arg(loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NestedExpression *) { stop("NestedExpression"); }
+
+bool AstDumper::visit(AST::IdentifierPropertyName *el) {
+ start(QLatin1String("IdentifierPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(el->id), loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IdentifierPropertyName *) { stop("IdentifierPropertyName"); }
+
+bool AstDumper::visit(AST::StringLiteralPropertyName *el) {
+ start(QLatin1String("StringLiteralPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(el->id), loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::StringLiteralPropertyName *) { stop("StringLiteralPropertyName"); }
+
+bool AstDumper::visit(AST::NumericLiteralPropertyName *el) {
+ start(QLatin1String("NumericLiteralPropertyName id=%1 propertyNameToken=%2")
+ .arg(qs(QString::number(el->id)),loc(el->propertyNameToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NumericLiteralPropertyName *) { stop("NumericLiteralPropertyName"); }
+
+bool AstDumper::visit(AST::ComputedPropertyName *) {
+ start(QLatin1String("ComputedPropertyName"));
+ return true;
+}
+void AstDumper::endVisit(AST::ComputedPropertyName *) { stop("ComputedPropertyName"); }
+
+bool AstDumper::visit(AST::ArrayMemberExpression *el) {
+ start(QLatin1String("ArrayMemberExpression lbraketToken=%1 rbraketToken=%2")
+ .arg(loc(el->lbracketToken), loc(el->rbracketToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ArrayMemberExpression *) { stop("ArrayMemberExpression"); }
+
+bool AstDumper::visit(AST::FieldMemberExpression *el) {
+ start(QLatin1String("FieldMemberExpression name=%1 dotToken=%2 identifierToken=%3")
+ .arg(qs(el->name), loc(el->dotToken), loc(el->identifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FieldMemberExpression *) { stop("FieldMemberExpression"); }
+
+bool AstDumper::visit(AST::TaggedTemplate *) {
+ start(QLatin1String("TaggedTemplate"));
+ return true;
+}
+void AstDumper::endVisit(AST::TaggedTemplate *) { stop("TaggedTemplate"); }
+
+bool AstDumper::visit(AST::NewMemberExpression *el) {
+ start(QLatin1String("NewMemberExpression newToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->newToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NewMemberExpression *) { stop("NewMemberExpression"); }
+
+bool AstDumper::visit(AST::NewExpression *el) {
+ start(QLatin1String("NewExpression newToken=%1")
+ .arg(loc(el->newToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NewExpression *) { stop("NewExpression"); }
+
+bool AstDumper::visit(AST::CallExpression *el) {
+ start(QLatin1String("CallExpression lparenToken=%1 rparenToken=%2")
+ .arg(loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CallExpression *) { stop("CallExpression"); }
+
+bool AstDumper::visit(AST::ArgumentList *el) {
+ start(QLatin1String("ArgumentList commaToken=%1 isSpreadElement=%2")
+ .arg(loc(el->commaToken), boolStr(el->isSpreadElement)));
+ return true;
+}
+void AstDumper::endVisit(AST::ArgumentList *) { stop("ArgumentList"); }
+
+bool AstDumper::visit(AST::PostIncrementExpression *el) {
+ start(QLatin1String("PostIncrementExpression incrementToken=%1")
+ .arg(loc(el->incrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PostIncrementExpression *) { stop("PostIncrementExpression"); }
+
+bool AstDumper::visit(AST::PostDecrementExpression *el) {
+ start(QLatin1String("PostDecrementExpression decrementToken=%1")
+ .arg(loc(el->decrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PostDecrementExpression *) { stop("PostDecrementExpression"); }
+
+bool AstDumper::visit(AST::DeleteExpression *el) {
+ start(QLatin1String("DeleteExpression deleteToken=%1")
+ .arg(loc(el->deleteToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DeleteExpression *) { stop("DeleteExpression"); }
+
+bool AstDumper::visit(AST::VoidExpression *el) {
+ start(QLatin1String("VoidExpression voidToken=%1")
+ .arg(loc(el->voidToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VoidExpression *) { stop("VoidExpression"); }
+
+bool AstDumper::visit(AST::TypeOfExpression *el) {
+ start(QLatin1String("TypeOfExpression typeofToken=%1")
+ .arg(loc(el->typeofToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeOfExpression *) { stop("TypeOfExpression"); }
+
+bool AstDumper::visit(AST::PreIncrementExpression *el) {
+ start(QLatin1String("PreIncrementExpression incrementToken=%1")
+ .arg(loc(el->incrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PreIncrementExpression *) { stop("PreIncrementExpression"); }
+
+bool AstDumper::visit(AST::PreDecrementExpression *el) {
+ start(QLatin1String("PreDecrementExpression decrementToken=%1")
+ .arg(loc(el->decrementToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::PreDecrementExpression *) { stop("PreDecrementExpression"); }
+
+bool AstDumper::visit(AST::UnaryPlusExpression *el) {
+ start(QLatin1String("UnaryPlusExpression plusToken=%1")
+ .arg(loc(el->plusToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::UnaryPlusExpression *) { stop("UnaryPlusExpression"); }
+
+bool AstDumper::visit(AST::UnaryMinusExpression *el) {
+ start(QLatin1String("UnaryMinusExpression minusToken=%1")
+ .arg(loc(el->minusToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::UnaryMinusExpression *) { stop("UnaryMinusExpression"); }
+
+bool AstDumper::visit(AST::TildeExpression *el) {
+ start(QLatin1String("TildeExpression tildeToken=%1")
+ .arg(loc(el->tildeToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TildeExpression *) { stop("TildeExpression"); }
+
+bool AstDumper::visit(AST::NotExpression *el) {
+ start(QLatin1String("NotExpression notToken=%1")
+ .arg(loc(el->notToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NotExpression *) { stop("NotExpression"); }
+
+bool AstDumper::visit(AST::BinaryExpression *el) {
+ start(QLatin1String("BinaryExpression op=%1 operatorToken=%2")
+ .arg(qs(QString::number(el->op,16)), loc(el->operatorToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::BinaryExpression *) { stop("BinaryExpression"); }
+
+bool AstDumper::visit(AST::ConditionalExpression *el) {
+ start(QLatin1String("ConditionalExpression questionToken=%1 colonToken=%2")
+ .arg(loc(el->questionToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ConditionalExpression *) { stop("ConditionalExpression"); }
+
+bool AstDumper::visit(AST::Expression *el) {
+ start(QLatin1String("Expression commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Expression *) { stop("Expression"); }
+
+bool AstDumper::visit(AST::Block *el) {
+ start(QLatin1String("Block lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Block *) { stop("Block"); }
+
+bool AstDumper::visit(AST::StatementList *) {
+ start(QLatin1String("StatementList"));
+ return true;
+}
+void AstDumper::endVisit(AST::StatementList *) { stop("StatementList"); }
+
+bool AstDumper::visit(AST::VariableStatement *el) {
+ start(QLatin1String("VariableStatement declarationKindToken=%1")
+ .arg(loc(el->declarationKindToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VariableStatement *) { stop("VariableStatement"); }
+
+bool AstDumper::visit(AST::VariableDeclarationList *el) {
+ start(QLatin1String("VariableDeclarationList commaToken=%1")
+ .arg(loc(el->commaToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::VariableDeclarationList *) { stop("VariableDeclarationList"); }
+
+bool AstDumper::visit(AST::EmptyStatement *el) {
+ start(QLatin1String("EmptyStatement semicolonToken=%1")
+ .arg(loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::EmptyStatement *) { stop("EmptyStatement"); }
+
+bool AstDumper::visit(AST::ExpressionStatement *el) {
+ start(QLatin1String("ExpressionStatement semicolonToken=%1")
+ .arg(loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExpressionStatement *) { stop("ExpressionStatement"); }
+
+bool AstDumper::visit(AST::IfStatement *el) {
+ start(QLatin1String("IfStatement ifToken=%1 lparenToken=%2 rparenToken=%3 elseToken=%4")
+ .arg(loc(el->ifToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->elseToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::IfStatement *) { stop("IfStatement"); }
+
+bool AstDumper::visit(AST::DoWhileStatement *el) {
+ start(QLatin1String("DoWhileStatement doToken=%1 whileToken=%2 lparenToken=%3 rparenToken=%4 semicolonToken=%5")
+ .arg(loc(el->doToken), loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DoWhileStatement *) { stop("DoWhileStatement"); }
+
+bool AstDumper::visit(AST::WhileStatement *el) {
+ start(QLatin1String("WhileStatement whileToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->whileToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::WhileStatement *) { stop("WhileStatement"); }
+
+bool AstDumper::visit(AST::ForStatement *el) {
+ start(QLatin1String("ForStatement forToken=%1 lparenToken=%2 firstSemicolonToken=%3 secondSemicolonToken=%4 rparenToken=%5")
+ .arg(loc(el->forToken), loc(el->lparenToken), loc(el->firstSemicolonToken), loc(el->secondSemicolonToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ForStatement *) { stop("ForStatement"); }
+
+bool AstDumper::visit(AST::ForEachStatement *el) {
+ start(QLatin1String("ForEachStatement forToken=%1 lparenToken=%2 inOfToken=%3 rparenToken=%4 type=%5")
+ .arg(loc(el->forToken), loc(el->lparenToken), loc(el->inOfToken), loc(el->rparenToken), qs(QString::number(static_cast<int>(el->type), 16))));
+ return true;
+}
+void AstDumper::endVisit(AST::ForEachStatement *) { stop("ForEachStatement"); }
+
+bool AstDumper::visit(AST::ContinueStatement *el) {
+ start(QLatin1String("ContinueStatement label=%1 continueToken=%2 identifierToken=%3 semicolonToken=%4")
+ .arg(qs(el->label), loc(el->continueToken), loc(el->identifierToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ContinueStatement *) { stop("ContinueStatement"); }
+
+bool AstDumper::visit(AST::BreakStatement *el) {
+ start(QLatin1String("BreakStatement label=%1 breakToken=%2 identifierToken=%3 semicolonToken=%4")
+ .arg(qs(el->label), loc(el->breakToken), loc(el->identifierToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::BreakStatement *) { stop("BreakStatement"); }
+
+bool AstDumper::visit(AST::ReturnStatement *el) {
+ start(QLatin1String("ReturnStatement returnToken=%1 semicolonToken=%2")
+ .arg(loc(el->returnToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ReturnStatement *) { stop("ReturnStatement"); }
+
+bool AstDumper::visit(AST::YieldExpression *el) {
+ start(QLatin1String("YieldExpression isYieldStar=%1 yieldToken=%2")
+ .arg(boolStr(el->isYieldStar), loc(el->yieldToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::YieldExpression *) { stop("YieldExpression"); }
+
+bool AstDumper::visit(AST::WithStatement *el) {
+ start(QLatin1String("WithStatement withToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->withToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::WithStatement *) { stop("WithStatement"); }
+
+bool AstDumper::visit(AST::SwitchStatement *el) {
+ start(QLatin1String("SwitchStatement switchToken=%1 lparenToken=%2 rparenToken=%3")
+ .arg(loc(el->switchToken), loc(el->lparenToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::SwitchStatement *) { stop("SwitchStatement"); }
+
+bool AstDumper::visit(AST::CaseBlock *el) {
+ start(QLatin1String("CaseBlock lbraceToken=%1 rbraceToken=%2")
+ .arg(loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseBlock *) { stop("CaseBlock"); }
+
+bool AstDumper::visit(AST::CaseClauses *) {
+ start(QLatin1String("CaseClauses"));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseClauses *) { stop("CaseClauses"); }
+
+bool AstDumper::visit(AST::CaseClause *el) {
+ start(QLatin1String("CaseClause caseToken=%1 colonToken=%2")
+ .arg(loc(el->caseToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::CaseClause *) { stop("CaseClause"); }
+
+bool AstDumper::visit(AST::DefaultClause *el) {
+ start(QLatin1String("DefaultClause defaultToken=%1 colonToken=%2")
+ .arg(loc(el->defaultToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DefaultClause *) { stop("DefaultClause"); }
+
+bool AstDumper::visit(AST::LabelledStatement *el) {
+ start(QLatin1String("LabelledStatement label=%1 identifierToken=%2 colonToken=%3")
+ .arg(qs(el->label), loc(el->identifierToken), loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::LabelledStatement *) { stop("LabelledStatement"); }
+
+bool AstDumper::visit(AST::ThrowStatement *el) {
+ start(QLatin1String("ThrowStatement throwToken=%1 semicolonToken=%2")
+ .arg(loc(el->throwToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ThrowStatement *) { stop("ThrowStatement"); }
+
+bool AstDumper::visit(AST::TryStatement *el) {
+ start(QLatin1String("TryStatement tryToken=%1")
+ .arg(loc(el->tryToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TryStatement *) { stop("TryStatement"); }
+
+bool AstDumper::visit(AST::Catch *el) {
+ start(QLatin1String("Catch catchToken=%1 lparenToken=%2 identifierToken=%3 rparenToken=%4")
+ .arg(loc(el->catchToken), loc(el->lparenToken), loc(el->identifierToken), loc(el->rparenToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Catch *) { stop("Catch"); }
+
+bool AstDumper::visit(AST::Finally *el) {
+ start(QLatin1String("Finally finallyToken=%1")
+ .arg(loc(el->finallyToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::Finally *) { stop("Finally"); }
+
+bool AstDumper::visit(AST::FunctionDeclaration *el) {
+ start(QLatin1String("FunctionDeclaration name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 "
+ "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9")
+ .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken),
+ loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken),
+ loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FunctionDeclaration *) { stop("FunctionDeclaration"); }
+
+bool AstDumper::visit(AST::FunctionExpression *el) {
+ start(QLatin1String("FunctionExpression name=%1 isArrowFunction=%2 isGenerator=%3 functionToken=%4 "
+ "identifierToken=%5 lparenToken=%6 rparenToken=%7 lbraceToken=%8 rbraceToken=%9")
+ .arg(qs(el->name), boolStr(el->isArrowFunction), boolStr(el->isGenerator), loc(el->functionToken),
+ loc(el->identifierToken), loc(el->lparenToken), loc(el->rparenToken), loc(el->lbraceToken),
+ loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::FunctionExpression *) { stop("FunctionExpression"); }
+
+bool AstDumper::visit(AST::FormalParameterList *) {
+ start(QLatin1String("FormalParameterList"));
+ return true;
+}
+void AstDumper::endVisit(AST::FormalParameterList *) { stop("FormalParameterList"); }
+
+bool AstDumper::visit(AST::ClassExpression *el) {
+ start(QLatin1String("ClassExpression name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5")
+ .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassExpression *) { stop("ClassExpression"); }
+
+bool AstDumper::visit(AST::ClassDeclaration *el) {
+ start(QLatin1String("ClassDeclaration name=%1 classToken=%2 identifierToken=%3 lbraceToken=%4 rbraceToken=%5")
+ .arg(qs(el->name), loc(el->classToken), loc(el->identifierToken), loc(el->lbraceToken), loc(el->rbraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassDeclaration *) { stop("ClassDeclaration"); }
+
+bool AstDumper::visit(AST::ClassElementList *el) {
+ start(QLatin1String("ClassElementList isStatic=%1")
+ .arg(boolStr(el->isStatic)));
+ return true;
+}
+void AstDumper::endVisit(AST::ClassElementList *) { stop("ClassElementList"); }
+
+bool AstDumper::visit(AST::Program *) {
+ start(QLatin1String("Program"));
+ return true;
+}
+void AstDumper::endVisit(AST::Program *) { stop("Program"); }
+
+bool AstDumper::visit(AST::NameSpaceImport *el) {
+ start(QLatin1String("NameSpaceImport starToken=%1 importedBindingToken=%2 importedBinding=%3")
+ .arg(loc(el->starToken), loc(el->importedBindingToken), qs(el->importedBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::NameSpaceImport *) { stop("NameSpaceImport"); }
+
+bool AstDumper::visit(AST::ImportSpecifier *el) {
+ start(QLatin1String("ImportSpecifier identifierToken=%1 importedBindingToken=%2 identifier=%3 importedBinding=%4")
+ .arg(loc(el->identifierToken), loc(el->importedBindingToken), qs(el->identifier), qs(el->importedBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportSpecifier *) { stop("ImportSpecifier"); }
+
+bool AstDumper::visit(AST::ImportsList *el) {
+ start(QLatin1String("ImportsList importSpecifierToken=%1")
+ .arg(loc(el->importSpecifierToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportsList *) { stop("ImportsList"); }
+
+bool AstDumper::visit(AST::NamedImports *el) {
+ start(QLatin1String("NamedImports leftBraceToken=%1 rightBraceToken=%2")
+ .arg(loc(el->leftBraceToken), loc(el->rightBraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::NamedImports *) { stop("NamedImports"); }
+
+bool AstDumper::visit(AST::FromClause *el) {
+ start(QLatin1String("FromClause fromToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3")
+ .arg(loc(el->fromToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::FromClause *) { stop("FromClause"); }
+
+bool AstDumper::visit(AST::ImportClause *el) {
+ start(QLatin1String("ImportClause importedDefaultBindingToken=%1 importedDefaultBinding=%2")
+ .arg(loc(el->importedDefaultBindingToken), qs(el->importedDefaultBinding)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportClause *) { stop("ImportClause"); }
+
+bool AstDumper::visit(AST::ImportDeclaration *el) {
+ start(QLatin1String("ImportDeclaration importToken=%1 moduleSpecifierToken=%2 moduleSpecifier=%3")
+ .arg(loc(el->importToken), loc(el->moduleSpecifierToken), qs(el->moduleSpecifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::ImportDeclaration *) { stop("ImportDeclaration"); }
+
+bool AstDumper::visit(AST::ExportSpecifier *el) {
+ start(QLatin1String("ExportSpecifier identifierToken=%1 exportedIdentifierToken=%2 identifier=%3 exportedIdentifier=%4")
+ .arg(loc(el->identifierToken), loc(el->exportedIdentifierToken), qs(el->identifier), qs(el->exportedIdentifier)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportSpecifier *) { stop("ExportSpecifier"); }
+
+bool AstDumper::visit(AST::ExportsList *) {
+ start(QLatin1String("ExportsList"));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportsList *) { stop("ExportsList"); }
+
+bool AstDumper::visit(AST::ExportClause *el) {
+ start(QLatin1String("ExportClause leftBraceToken=%1 rightBraceToken=%2")
+ .arg(loc(el->leftBraceToken), loc(el->rightBraceToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportClause *) { stop("ExportClause"); }
+
+bool AstDumper::visit(AST::ExportDeclaration *el) {
+ start(QLatin1String("ExportDeclaration exportToken=%1 exportAll=%2 exportDefault=%3")
+ .arg(loc(el->exportToken), boolStr(el->exportsAll()), boolStr(el->exportDefault)));
+ return true;
+}
+void AstDumper::endVisit(AST::ExportDeclaration *) { stop("ExportDeclaration"); }
+
+bool AstDumper::visit(AST::ESModule *) {
+ start(QLatin1String("ESModule"));
+ return true;
+}
+void AstDumper::endVisit(AST::ESModule *) { stop("ESModule"); }
+
+bool AstDumper::visit(AST::DebuggerStatement *el) {
+ start(QLatin1String("DebuggerStatement debuggerToken=%1 semicolonToken=%2")
+ .arg(loc(el->debuggerToken), loc(el->semicolonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::DebuggerStatement *) { stop("DebuggerStatement"); }
+
+bool AstDumper::visit(AST::Type *) {
+ start(QLatin1String("Type"));
+ return true;
+}
+void AstDumper::endVisit(AST::Type *) { stop("Type"); }
+
+bool AstDumper::visit(AST::TypeArgumentList *) {
+ start(QLatin1String("TypeArgumentList"));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeArgumentList *) { stop("TypeArgumentList"); }
+
+bool AstDumper::visit(AST::TypeAnnotation *el) {
+ start(QLatin1String("TypeAnnotation colonToken=%1")
+ .arg(loc(el->colonToken)));
+ return true;
+}
+void AstDumper::endVisit(AST::TypeAnnotation *) { stop("TypeAnnotation"); }
+
+void AstDumper::throwRecursionDepthError()
+{
+ qDebug() << "Maximum statement or expression depth exceeded in AstDumper";
+}
+
+bool AstDumper::dumpNode() {
+ return options & DumperOptions::DumpNode;
+}
+
+bool AstDumper::noLocations() {
+ return options & DumperOptions::NoLocations;
+}
+
+bool AstDumper::noAnnotations() {
+ return options & DumperOptions::NoAnnotations;
+}
+
+} // end namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/quicktestutils/qml/qqmljsastdumper_p.h b/src/quicktestutils/qml/qqmljsastdumper_p.h
new file mode 100644
index 0000000000..055303ae59
--- /dev/null
+++ b/src/quicktestutils/qml/qqmljsastdumper_p.h
@@ -0,0 +1,449 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**/
+#ifndef ASTDUMPER_P_H
+#define ASTDUMPER_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 <private/qqmljsglobal_p.h>
+#include <private/qqmljsastvisitor_p.h>
+#include <QtCore/QString>
+#include <functional>
+#include <ostream>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+
+namespace QQmlJS {
+
+enum class DumperOptions {
+ None=0,
+ NoLocations=0x1,
+ NoAnnotations=0x2,
+ DumpNode=0x4
+};
+bool operator & (DumperOptions lhs, DumperOptions rhs);
+DumperOptions operator | (DumperOptions lhs, DumperOptions rhs);
+
+// no export, currently just a supporting file...
+class AstDumper: public AST::BaseVisitor
+{
+public:
+ static QString printNode2(AST::Node *);
+
+ static QString diff(AST::Node *n1, AST::Node *n2, int nContext=3, DumperOptions opt=DumperOptions::None, int indent=0);
+ static QString printNode(AST::Node *n, DumperOptions opt=DumperOptions::None, int indent=1, int baseIndent=0);
+
+ AstDumper(const std::function <void (const QString &)> &dumper, DumperOptions options=DumperOptions::None,
+ int indent=1, int baseIndent=0);
+
+ void start(const QString &str);
+ void start(const char *str);
+ void stop(const QString &str);
+ void stop(const char *str);
+
+ QString qs(const QString &s);
+ QString qs(const char *s);
+ QString qs(QStringView s);
+
+ QString loc(const SourceLocation &s);
+
+ QString boolStr(bool v);
+
+ bool preVisit(AST::Node *el) override;
+ void postVisit(AST::Node *el) override;
+
+ // Ui
+ bool visit(AST::UiProgram *el) override;
+ bool visit(AST::UiHeaderItemList *) override;
+ bool visit(AST::UiPragma *el) override;
+ bool visit(AST::UiImport *el) override;
+ bool visit(AST::UiPublicMember *el) override;
+ bool visit(AST::UiSourceElement *) override;
+ bool visit(AST::UiObjectDefinition *) override;
+ bool visit(AST::UiObjectInitializer *) override;
+ bool visit(AST::UiObjectBinding *) override;
+ bool visit(AST::UiScriptBinding *) override;
+ bool visit(AST::UiArrayBinding *) override;
+ bool visit(AST::UiParameterList *) override;
+ bool visit(AST::UiObjectMemberList *) override;
+ bool visit(AST::UiArrayMemberList *) override;
+ bool visit(AST::UiQualifiedId *) override;
+ bool visit(AST::UiEnumDeclaration *) override;
+ bool visit(AST::UiEnumMemberList *) override;
+ bool visit(AST::UiVersionSpecifier *) override;
+ bool visit(AST::UiInlineComponent *) override;
+ bool visit(AST::UiRequired *) override;
+ bool visit(AST::UiAnnotation *) override;
+ bool visit(AST::UiAnnotationList *) override;
+
+ void endVisit(AST::UiProgram *) override;
+ void endVisit(AST::UiImport *) override;
+ void endVisit(AST::UiHeaderItemList *) override;
+ void endVisit(AST::UiPragma *) override;
+ void endVisit(AST::UiPublicMember *) override;
+ void endVisit(AST::UiSourceElement *) override;
+ void endVisit(AST::UiObjectDefinition *) override;
+ void endVisit(AST::UiObjectInitializer *) override;
+ void endVisit(AST::UiObjectBinding *) override;
+ void endVisit(AST::UiScriptBinding *) override;
+ void endVisit(AST::UiArrayBinding *) override;
+ void endVisit(AST::UiParameterList *) override;
+ void endVisit(AST::UiObjectMemberList *) override;
+ void endVisit(AST::UiArrayMemberList *) override;
+ void endVisit(AST::UiQualifiedId *) override;
+ void endVisit(AST::UiEnumDeclaration *) override;
+ void endVisit(AST::UiEnumMemberList *) override;
+ void endVisit(AST::UiVersionSpecifier *) override;
+ void endVisit(AST::UiInlineComponent *) override;
+ void endVisit(AST::UiRequired *) override;
+ void endVisit(AST::UiAnnotation *) override;
+ void endVisit(AST::UiAnnotationList *) override;
+
+ // QQmlJS
+ bool visit(AST::TypeExpression *) override;
+ void endVisit(AST::TypeExpression *) override;
+
+ bool visit(AST::ThisExpression *) override;
+ void endVisit(AST::ThisExpression *) override;
+
+ bool visit(AST::IdentifierExpression *) override;
+ void endVisit(AST::IdentifierExpression *) override;
+
+ bool visit(AST::NullExpression *) override;
+ void endVisit(AST::NullExpression *) override;
+
+ bool visit(AST::TrueLiteral *) override;
+ void endVisit(AST::TrueLiteral *) override;
+
+ bool visit(AST::FalseLiteral *) override;
+ void endVisit(AST::FalseLiteral *) override;
+
+ bool visit(AST::SuperLiteral *) override;
+ void endVisit(AST::SuperLiteral *) override;
+
+ bool visit(AST::StringLiteral *) override;
+ void endVisit(AST::StringLiteral *) override;
+
+ bool visit(AST::TemplateLiteral *) override;
+ void endVisit(AST::TemplateLiteral *) override;
+
+ bool visit(AST::NumericLiteral *) override;
+ void endVisit(AST::NumericLiteral *) override;
+
+ bool visit(AST::RegExpLiteral *) override;
+ void endVisit(AST::RegExpLiteral *) override;
+
+ bool visit(AST::ArrayPattern *) override;
+ void endVisit(AST::ArrayPattern *) override;
+
+ bool visit(AST::ObjectPattern *) override;
+ void endVisit(AST::ObjectPattern *) override;
+
+ bool visit(AST::PatternElementList *) override;
+ void endVisit(AST::PatternElementList *) override;
+
+ bool visit(AST::PatternPropertyList *) override;
+ void endVisit(AST::PatternPropertyList *) override;
+
+ bool visit(AST::PatternElement *) override;
+ void endVisit(AST::PatternElement *) override;
+
+ bool visit(AST::PatternProperty *) override;
+ void endVisit(AST::PatternProperty *) override;
+
+ bool visit(AST::Elision *) override;
+ void endVisit(AST::Elision *) override;
+
+ bool visit(AST::NestedExpression *) override;
+ void endVisit(AST::NestedExpression *) override;
+
+ bool visit(AST::IdentifierPropertyName *) override;
+ void endVisit(AST::IdentifierPropertyName *) override;
+
+ bool visit(AST::StringLiteralPropertyName *) override;
+ void endVisit(AST::StringLiteralPropertyName *) override;
+
+ bool visit(AST::NumericLiteralPropertyName *) override;
+ void endVisit(AST::NumericLiteralPropertyName *) override;
+
+ bool visit(AST::ComputedPropertyName *) override;
+ void endVisit(AST::ComputedPropertyName *) override;
+
+ bool visit(AST::ArrayMemberExpression *) override;
+ void endVisit(AST::ArrayMemberExpression *) override;
+
+ bool visit(AST::FieldMemberExpression *) override;
+ void endVisit(AST::FieldMemberExpression *) override;
+
+ bool visit(AST::TaggedTemplate *) override;
+ void endVisit(AST::TaggedTemplate *) override;
+
+ bool visit(AST::NewMemberExpression *) override;
+ void endVisit(AST::NewMemberExpression *) override;
+
+ bool visit(AST::NewExpression *) override;
+ void endVisit(AST::NewExpression *) override;
+
+ bool visit(AST::CallExpression *) override;
+ void endVisit(AST::CallExpression *) override;
+
+ bool visit(AST::ArgumentList *) override;
+ void endVisit(AST::ArgumentList *) override;
+
+ bool visit(AST::PostIncrementExpression *) override;
+ void endVisit(AST::PostIncrementExpression *) override;
+
+ bool visit(AST::PostDecrementExpression *) override;
+ void endVisit(AST::PostDecrementExpression *) override;
+
+ bool visit(AST::DeleteExpression *) override;
+ void endVisit(AST::DeleteExpression *) override;
+
+ bool visit(AST::VoidExpression *) override;
+ void endVisit(AST::VoidExpression *) override;
+
+ bool visit(AST::TypeOfExpression *) override;
+ void endVisit(AST::TypeOfExpression *) override;
+
+ bool visit(AST::PreIncrementExpression *) override;
+ void endVisit(AST::PreIncrementExpression *) override;
+
+ bool visit(AST::PreDecrementExpression *) override;
+ void endVisit(AST::PreDecrementExpression *) override;
+
+ bool visit(AST::UnaryPlusExpression *) override;
+ void endVisit(AST::UnaryPlusExpression *) override;
+
+ bool visit(AST::UnaryMinusExpression *) override;
+ void endVisit(AST::UnaryMinusExpression *) override;
+
+ bool visit(AST::TildeExpression *) override;
+ void endVisit(AST::TildeExpression *) override;
+
+ bool visit(AST::NotExpression *) override;
+ void endVisit(AST::NotExpression *) override;
+
+ bool visit(AST::BinaryExpression *) override;
+ void endVisit(AST::BinaryExpression *) override;
+
+ bool visit(AST::ConditionalExpression *) override;
+ void endVisit(AST::ConditionalExpression *) override;
+
+ bool visit(AST::Expression *) override;
+ void endVisit(AST::Expression *) override;
+
+ bool visit(AST::Block *) override;
+ void endVisit(AST::Block *) override;
+
+ bool visit(AST::StatementList *) override;
+ void endVisit(AST::StatementList *) override;
+
+ bool visit(AST::VariableStatement *) override;
+ void endVisit(AST::VariableStatement *) override;
+
+ bool visit(AST::VariableDeclarationList *) override;
+ void endVisit(AST::VariableDeclarationList *) override;
+
+ bool visit(AST::EmptyStatement *) override;
+ void endVisit(AST::EmptyStatement *) override;
+
+ bool visit(AST::ExpressionStatement *) override;
+ void endVisit(AST::ExpressionStatement *) override;
+
+ bool visit(AST::IfStatement *) override;
+ void endVisit(AST::IfStatement *) override;
+
+ bool visit(AST::DoWhileStatement *) override;
+ void endVisit(AST::DoWhileStatement *) override;
+
+ bool visit(AST::WhileStatement *) override;
+ void endVisit(AST::WhileStatement *) override;
+
+ bool visit(AST::ForStatement *) override;
+ void endVisit(AST::ForStatement *) override;
+
+ bool visit(AST::ForEachStatement *) override;
+ void endVisit(AST::ForEachStatement *) override;
+
+ bool visit(AST::ContinueStatement *) override;
+ void endVisit(AST::ContinueStatement *) override;
+
+ bool visit(AST::BreakStatement *) override;
+ void endVisit(AST::BreakStatement *) override;
+
+ bool visit(AST::ReturnStatement *) override;
+ void endVisit(AST::ReturnStatement *) override;
+
+ bool visit(AST::YieldExpression *) override;
+ void endVisit(AST::YieldExpression *) override;
+
+ bool visit(AST::WithStatement *) override;
+ void endVisit(AST::WithStatement *) override;
+
+ bool visit(AST::SwitchStatement *) override;
+ void endVisit(AST::SwitchStatement *) override;
+
+ bool visit(AST::CaseBlock *) override;
+ void endVisit(AST::CaseBlock *) override;
+
+ bool visit(AST::CaseClauses *) override;
+ void endVisit(AST::CaseClauses *) override;
+
+ bool visit(AST::CaseClause *) override;
+ void endVisit(AST::CaseClause *) override;
+
+ bool visit(AST::DefaultClause *) override;
+ void endVisit(AST::DefaultClause *) override;
+
+ bool visit(AST::LabelledStatement *) override;
+ void endVisit(AST::LabelledStatement *) override;
+
+ bool visit(AST::ThrowStatement *) override;
+ void endVisit(AST::ThrowStatement *) override;
+
+ bool visit(AST::TryStatement *) override;
+ void endVisit(AST::TryStatement *) override;
+
+ bool visit(AST::Catch *) override;
+ void endVisit(AST::Catch *) override;
+
+ bool visit(AST::Finally *) override;
+ void endVisit(AST::Finally *) override;
+
+ bool visit(AST::FunctionDeclaration *) override;
+ void endVisit(AST::FunctionDeclaration *) override;
+
+ bool visit(AST::FunctionExpression *) override;
+ void endVisit(AST::FunctionExpression *) override;
+
+ bool visit(AST::FormalParameterList *) override;
+ void endVisit(AST::FormalParameterList *) override;
+
+ bool visit(AST::ClassExpression *) override;
+ void endVisit(AST::ClassExpression *) override;
+
+ bool visit(AST::ClassDeclaration *) override;
+ void endVisit(AST::ClassDeclaration *) override;
+
+ bool visit(AST::ClassElementList *) override;
+ void endVisit(AST::ClassElementList *) override;
+
+ bool visit(AST::Program *) override;
+ void endVisit(AST::Program *) override;
+
+ bool visit(AST::NameSpaceImport *) override;
+ void endVisit(AST::NameSpaceImport *) override;
+
+ bool visit(AST::ImportSpecifier *) override;
+ void endVisit(AST::ImportSpecifier *) override;
+
+ bool visit(AST::ImportsList *) override;
+ void endVisit(AST::ImportsList *) override;
+
+ bool visit(AST::NamedImports *) override;
+ void endVisit(AST::NamedImports *) override;
+
+ bool visit(AST::FromClause *) override;
+ void endVisit(AST::FromClause *) override;
+
+ bool visit(AST::ImportClause *) override;
+ void endVisit(AST::ImportClause *) override;
+
+ bool visit(AST::ImportDeclaration *) override;
+ void endVisit(AST::ImportDeclaration *) override;
+
+ bool visit(AST::ExportSpecifier *) override;
+ void endVisit(AST::ExportSpecifier *) override;
+
+ bool visit(AST::ExportsList *) override;
+ void endVisit(AST::ExportsList *) override;
+
+ bool visit(AST::ExportClause *) override;
+ void endVisit(AST::ExportClause *) override;
+
+ bool visit(AST::ExportDeclaration *) override;
+ void endVisit(AST::ExportDeclaration *) override;
+
+ bool visit(AST::ESModule *) override;
+ void endVisit(AST::ESModule *) override;
+
+ bool visit(AST::DebuggerStatement *) override;
+ void endVisit(AST::DebuggerStatement *) override;
+
+ bool visit(AST::Type *) override;
+ void endVisit(AST::Type *) override;
+
+ bool visit(AST::TypeArgumentList *) override;
+ void endVisit(AST::TypeArgumentList *) override;
+
+ bool visit(AST::TypeAnnotation *) override;
+ void endVisit(AST::TypeAnnotation *) override;
+
+ void throwRecursionDepthError() override;
+
+private:
+ // attributes
+ std::function <void (const QString &)> dumper;
+ DumperOptions options = DumperOptions::None;
+ int indent = 0;
+ int baseIndent = 0;
+ bool dumpNode();
+ bool noLocations();
+ bool noAnnotations();
+};
+
+QDebug operator<<(QDebug d, AST::Node *n);
+
+std::ostream &operator<<(std::ostream &stream, AST::Node *n);
+
+} // namespace AST
+
+QT_END_NAMESPACE
+
+#endif // ASTDUMPER_P_H
diff --git a/src/quicktestutils/qml/testhttpserver.cpp b/src/quicktestutils/qml/testhttpserver.cpp
new file mode 100644
index 0000000000..8ac56d8ee9
--- /dev/null
+++ b/src/quicktestutils/qml/testhttpserver.cpp
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testhttpserver_p.h"
+#include <QTcpSocket>
+#include <QDebug>
+#include <QFile>
+#include <QTimer>
+#include <QTest>
+#include <QQmlFile>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+\internal
+\class TestHTTPServer
+\brief provides a very, very basic HTTP server for testing.
+
+Inside the test case, an instance of TestHTTPServer should be created, with the
+appropriate port to listen on. The server will listen on the localhost interface.
+
+Directories to serve can then be added to server, which will be added as "roots".
+Each root can be added as a Normal, Delay or Disconnect root. Requests for files
+within a Normal root are returned immediately. Request for files within a Delay
+root are delayed for 500ms, and then served. Requests for files within a Disconnect
+directory cause the server to disconnect immediately. A request for a file that isn't
+found in any root will return a 404 error.
+
+If you have the following directory structure:
+
+\code
+disconnect/disconnectTest.qml
+files/main.qml
+files/Button.qml
+files/content/WebView.qml
+slowFiles/slowMain.qml
+\endcode
+it can be added like this:
+\code
+TestHTTPServer server;
+QVERIFY2(server.listen(14445), qPrintable(server.errorString()));
+server.serveDirectory("disconnect", TestHTTPServer::Disconnect);
+server.serveDirectory("files");
+server.serveDirectory("slowFiles", TestHTTPServer::Delay);
+\endcode
+
+The following request urls will then result in the appropriate action:
+\table
+\header \li URL \li Action
+\row \li http://localhost:14445/disconnectTest.qml \li Disconnection
+\row \li http://localhost:14445/main.qml \li main.qml returned immediately
+\row \li http://localhost:14445/Button.qml \li Button.qml returned immediately
+\row \li http://localhost:14445/content/WebView.qml \li content/WebView.qml returned immediately
+\row \li http://localhost:14445/slowMain.qml \li slowMain.qml returned after 500ms
+\endtable
+*/
+
+static QList<QByteArrayView> ignoredHeaders = {
+ "HTTP2-Settings", // We ignore this
+ "Upgrade", // We ignore this as well
+};
+
+static QUrl localHostUrl(quint16 port)
+{
+ QUrl url;
+ url.setScheme(QStringLiteral("http"));
+ url.setHost(QStringLiteral("127.0.0.1"));
+ url.setPort(port);
+ return url;
+}
+
+TestHTTPServer::TestHTTPServer()
+ : m_state(AwaitingHeader)
+{
+ QObject::connect(&m_server, &QTcpServer::newConnection, this, &TestHTTPServer::newConnection);
+}
+
+bool TestHTTPServer::listen()
+{
+ return m_server.listen(QHostAddress::LocalHost, 0);
+}
+
+QUrl TestHTTPServer::baseUrl() const
+{
+ return localHostUrl(m_server.serverPort());
+}
+
+quint16 TestHTTPServer::port() const
+{
+ return m_server.serverPort();
+}
+
+QUrl TestHTTPServer::url(const QString &documentPath) const
+{
+ return baseUrl().resolved(documentPath);
+}
+
+QString TestHTTPServer::urlString(const QString &documentPath) const
+{
+ return url(documentPath).toString();
+}
+
+QString TestHTTPServer::errorString() const
+{
+ return m_server.errorString();
+}
+
+bool TestHTTPServer::serveDirectory(const QString &dir, Mode mode)
+{
+ m_directories.append(qMakePair(dir, mode));
+ return true;
+}
+
+/*
+ Add an alias, so that if filename is requested and does not exist,
+ alias may be returned.
+*/
+void TestHTTPServer::addAlias(const QString &filename, const QString &alias)
+{
+ m_aliases.insert(filename, alias);
+}
+
+void TestHTTPServer::addRedirect(const QString &filename, const QString &redirectName)
+{
+ m_redirects.insert(filename, redirectName);
+}
+
+void TestHTTPServer::registerFileNameForContentSubstitution(const QString &fileName)
+{
+ m_contentSubstitutedFileNames.insert(fileName);
+}
+
+bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
+{
+ m_state = AwaitingHeader;
+ m_data.clear();
+
+ QFile expectFile(QQmlFile::urlToLocalFileOrQrc(expect));
+ if (!expectFile.open(QIODevice::ReadOnly))
+ return false;
+
+ QFile replyFile(QQmlFile::urlToLocalFileOrQrc(reply));
+ if (!replyFile.open(QIODevice::ReadOnly))
+ return false;
+
+ m_bodyData = QByteArray();
+ if (body.isValid()) {
+ QFile bodyFile(QQmlFile::urlToLocalFileOrQrc(body));
+ if (!bodyFile.open(QIODevice::ReadOnly))
+ return false;
+ m_bodyData = bodyFile.readAll();
+ }
+
+ const QByteArray serverHostUrl
+ = QByteArrayLiteral("127.0.0.1:")+ QByteArray::number(m_server.serverPort());
+
+ QByteArray line;
+ bool headers_done = false;
+ while (!(line = expectFile.readLine()).isEmpty()) {
+ line.replace('\r', "");
+ if (line.at(0) == '\n') {
+ headers_done = true;
+ continue;
+ }
+ if (headers_done) {
+ m_waitData.body.append(line);
+ } else if (line.endsWith("{{Ignore}}\n")) {
+ m_waitData.headerPrefixes.append(line.left(line.length() - strlen("{{Ignore}}\n")));
+ } else {
+ line.replace("{{ServerHostUrl}}", serverHostUrl);
+ m_waitData.headerExactMatches.append(line);
+ }
+ }
+
+ m_replyData = replyFile.readAll();
+
+ if (!m_replyData.endsWith('\n'))
+ m_replyData.append('\n');
+ m_replyData.append("Content-length: ");
+ m_replyData.append(QByteArray::number(m_bodyData.length()));
+ m_replyData.append("\n\n");
+
+ for (int ii = 0; ii < m_replyData.count(); ++ii) {
+ if (m_replyData.at(ii) == '\n' && (!ii || m_replyData.at(ii - 1) != '\r')) {
+ m_replyData.insert(ii, '\r');
+ ++ii;
+ }
+ }
+ m_replyData.append(m_bodyData);
+
+ return true;
+}
+
+bool TestHTTPServer::hasFailed() const
+{
+ return m_state == Failed;
+}
+
+void TestHTTPServer::newConnection()
+{
+ QTcpSocket *socket = m_server.nextPendingConnection();
+ if (!socket)
+ return;
+
+ if (!m_directories.isEmpty())
+ m_dataCache.insert(socket, QByteArray());
+
+ QObject::connect(socket, &QAbstractSocket::disconnected, this, &TestHTTPServer::disconnected);
+ QObject::connect(socket, &QIODevice::readyRead, this, &TestHTTPServer::readyRead);
+}
+
+void TestHTTPServer::disconnected()
+{
+ QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+ if (!socket)
+ return;
+
+ m_dataCache.remove(socket);
+ for (int ii = 0; ii < m_toSend.count(); ++ii) {
+ if (m_toSend.at(ii).first == socket) {
+ m_toSend.removeAt(ii);
+ --ii;
+ }
+ }
+ socket->disconnect();
+ socket->deleteLater();
+}
+
+void TestHTTPServer::readyRead()
+{
+ QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
+ if (!socket || socket->state() == QTcpSocket::ClosingState)
+ return;
+
+ if (!m_directories.isEmpty()) {
+ serveGET(socket, socket->readAll());
+ return;
+ }
+
+ if (m_state == Failed || (m_waitData.body.isEmpty() && m_waitData.headerExactMatches.count() == 0)) {
+ qWarning() << "TestHTTPServer: Unexpected data" << socket->readAll();
+ return;
+ }
+
+ if (m_state == AwaitingHeader) {
+ QByteArray line;
+ while (!(line = socket->readLine()).isEmpty()) {
+ line.replace('\r', "");
+ if (line.at(0) == '\n') {
+ m_state = AwaitingData;
+ m_data += socket->readAll();
+ break;
+ } else {
+ bool prefixFound = false;
+ for (const QByteArray &prefix : m_waitData.headerPrefixes) {
+ if (line.startsWith(prefix)) {
+ prefixFound = true;
+ break;
+ }
+ }
+ for (QByteArrayView ignore : ignoredHeaders) {
+ if (line.startsWith(ignore)) {
+ prefixFound = true;
+ break;
+ }
+ }
+
+ if (!prefixFound && !m_waitData.headerExactMatches.contains(line)) {
+ qWarning() << "TestHTTPServer: Unexpected header:" << line
+ << "\nExpected exact headers: " << m_waitData.headerExactMatches
+ << "\nExpected header prefixes: " << m_waitData.headerPrefixes;
+ m_state = Failed;
+ socket->disconnectFromHost();
+ return;
+ }
+ }
+ }
+ } else {
+ m_data += socket->readAll();
+ }
+
+ if (!m_data.isEmpty() || m_waitData.body.isEmpty()) {
+ if (m_waitData.body != m_data) {
+ qWarning() << "TestHTTPServer: Unexpected data" << m_data << "\nExpected: " << m_waitData.body;
+ m_state = Failed;
+ } else {
+ socket->write(m_replyData);
+ }
+ socket->disconnectFromHost();
+ }
+}
+
+bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileNameIn)
+{
+ const QString fileName = QLatin1String(fileNameIn);
+ if (m_redirects.contains(fileName)) {
+ const QByteArray response
+ = "HTTP/1.1 302 Found\r\nContent-length: 0\r\nContent-type: text/html; charset=UTF-8\r\nLocation: "
+ + m_redirects.value(fileName).toUtf8() + "\r\n\r\n";
+ socket->write(response);
+ return true;
+ }
+
+ for (int ii = 0; ii < m_directories.count(); ++ii) {
+ const QString &dir = m_directories.at(ii).first;
+ const Mode mode = m_directories.at(ii).second;
+
+ QString dirFile = dir + QLatin1Char('/') + fileName;
+
+ if (!QFile::exists(dirFile)) {
+ const QHash<QString, QString>::const_iterator it = m_aliases.constFind(fileName);
+ if (it != m_aliases.constEnd())
+ dirFile = dir + QLatin1Char('/') + it.value();
+ }
+
+ QFile file(dirFile);
+ if (file.open(QIODevice::ReadOnly)) {
+
+ if (mode == Disconnect)
+ return true;
+
+ QByteArray data = file.readAll();
+ if (m_contentSubstitutedFileNames.contains(QLatin1Char('/') + fileName))
+ data.replace(QByteArrayLiteral("{{ServerBaseUrl}}"), baseUrl().toString().toUtf8());
+
+ QByteArray response
+ = "HTTP/1.0 200 OK\r\nContent-type: text/html; charset=UTF-8\r\nContent-length: ";
+ response += QByteArray::number(data.count());
+ response += "\r\n\r\n";
+ response += data;
+
+ if (mode == Delay) {
+ m_toSend.append(qMakePair(socket, response));
+ QTimer::singleShot(500, this, &TestHTTPServer::sendOne);
+ return false;
+ } else {
+ socket->write(response);
+ return true;
+ }
+ }
+ }
+
+ socket->write("HTTP/1.0 404 Not found\r\nContent-type: text/html; charset=UTF-8\r\n\r\n");
+
+ return true;
+}
+
+void TestHTTPServer::sendDelayedItem()
+{
+ sendOne();
+}
+
+void TestHTTPServer::sendOne()
+{
+ if (!m_toSend.isEmpty()) {
+ m_toSend.first().first->write(m_toSend.first().second);
+ m_toSend.first().first->close();
+ m_toSend.removeFirst();
+ }
+}
+
+void TestHTTPServer::serveGET(QTcpSocket *socket, const QByteArray &data)
+{
+ const QHash<QTcpSocket *, QByteArray>::iterator it = m_dataCache.find(socket);
+ if (it == m_dataCache.end())
+ return;
+
+ QByteArray &total = it.value();
+ total.append(data);
+
+ if (total.contains("\n\r\n")) {
+ bool close = true;
+ if (total.startsWith("GET /")) {
+ const int space = total.indexOf(' ', 4);
+ if (space != -1)
+ close = reply(socket, total.mid(5, space - 5));
+ }
+ m_dataCache.erase(it);
+ if (close)
+ socket->disconnectFromHost();
+ }
+}
+
+ThreadedTestHTTPServer::ThreadedTestHTTPServer(const QString &dir, TestHTTPServer::Mode mode) :
+ m_port(0)
+{
+ m_dirs[dir] = mode;
+ start();
+}
+
+ThreadedTestHTTPServer::ThreadedTestHTTPServer(const QHash<QString, TestHTTPServer::Mode> &dirs) :
+ m_dirs(dirs), m_port(0)
+{
+ start();
+}
+
+ThreadedTestHTTPServer::~ThreadedTestHTTPServer()
+{
+ quit();
+ wait();
+}
+
+QUrl ThreadedTestHTTPServer::baseUrl() const
+{
+ return localHostUrl(m_port);
+}
+
+QUrl ThreadedTestHTTPServer::url(const QString &documentPath) const
+{
+ return baseUrl().resolved(documentPath);
+}
+
+QString ThreadedTestHTTPServer::urlString(const QString &documentPath) const
+{
+ return url(documentPath).toString();
+}
+
+void ThreadedTestHTTPServer::run()
+{
+ TestHTTPServer server;
+ {
+ QMutexLocker locker(&m_mutex);
+ QVERIFY2(server.listen(), qPrintable(server.errorString()));
+ m_port = server.port();
+ for (QHash<QString, TestHTTPServer::Mode>::ConstIterator i = m_dirs.constBegin();
+ i != m_dirs.constEnd(); ++i) {
+ server.serveDirectory(i.key(), i.value());
+ }
+ m_condition.wakeAll();
+ }
+ exec();
+}
+
+void ThreadedTestHTTPServer::start()
+{
+ QMutexLocker locker(&m_mutex);
+ QThread::start();
+ m_condition.wait(&m_mutex);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_testhttpserver_p.cpp"
diff --git a/src/quicktestutils/qml/testhttpserver_p.h b/src/quicktestutils/qml/testhttpserver_p.h
new file mode 100644
index 0000000000..db99b348ca
--- /dev/null
+++ b/src/quicktestutils/qml/testhttpserver_p.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTHTTPSERVER_P_H
+#define TESTHTTPSERVER_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 <QTcpServer>
+#include <QUrl>
+#include <QPair>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+class TestHTTPServer : public QObject
+{
+ Q_OBJECT
+public:
+ TestHTTPServer();
+
+ bool listen();
+ quint16 port() const;
+ QUrl baseUrl() const;
+ QUrl url(const QString &documentPath) const;
+ QString urlString(const QString &documentPath) const;
+ QString errorString() const;
+
+ enum Mode { Normal, Delay, Disconnect };
+ bool serveDirectory(const QString &, Mode = Normal);
+
+ bool wait(const QUrl &expect, const QUrl &reply, const QUrl &body);
+ bool hasFailed() const;
+
+ void addAlias(const QString &filename, const QString &aliasName);
+ void addRedirect(const QString &filename, const QString &redirectName);
+
+ void registerFileNameForContentSubstitution(const QString &fileName);
+
+ // In Delay mode, each item needs one call to this function to be sent
+ void sendDelayedItem();
+
+private slots:
+ void newConnection();
+ void disconnected();
+ void readyRead();
+ void sendOne();
+
+private:
+ enum State {
+ AwaitingHeader,
+ AwaitingData,
+ Failed
+ };
+
+ void serveGET(QTcpSocket *, const QByteArray &);
+ bool reply(QTcpSocket *, const QByteArray &);
+
+ QList<QPair<QString, Mode> > m_directories;
+ QHash<QTcpSocket *, QByteArray> m_dataCache;
+ QList<QPair<QTcpSocket *, QByteArray> > m_toSend;
+ QSet<QString> m_contentSubstitutedFileNames;
+
+ struct WaitData {
+ QList<QByteArray> headerExactMatches;
+ QList<QByteArray> headerPrefixes;
+ QByteArray body;
+ } m_waitData;
+ QByteArray m_replyData;
+ QByteArray m_bodyData;
+ QByteArray m_data;
+ State m_state;
+
+ QHash<QString, QString> m_aliases;
+ QHash<QString, QString> m_redirects;
+
+ QTcpServer m_server;
+};
+
+class ThreadedTestHTTPServer : public QThread
+{
+ Q_OBJECT
+public:
+ ThreadedTestHTTPServer(const QString &dir, TestHTTPServer::Mode mode = TestHTTPServer::Normal);
+ ThreadedTestHTTPServer(const QHash<QString, TestHTTPServer::Mode> &dirs);
+ ~ThreadedTestHTTPServer();
+
+ QUrl baseUrl() const;
+ QUrl url(const QString &documentPath) const;
+ QString urlString(const QString &documentPath) const;
+
+protected:
+ void run() override;
+
+private:
+ void start();
+
+ QHash<QString, TestHTTPServer::Mode> m_dirs;
+ quint16 m_port;
+ QMutex m_mutex;
+ QWaitCondition m_condition;
+};
+
+QT_END_NAMESPACE
+
+#endif // TESTHTTPSERVER_P_H
+
diff --git a/src/quicktestutils/quick/geometrytestutils.cpp b/src/quicktestutils/quick/geometrytestutils.cpp
new file mode 100644
index 0000000000..27e36c2797
--- /dev/null
+++ b/src/quicktestutils/quick/geometrytestutils.cpp
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "geometrytestutils_p.h"
+
+#include <QQuickItem>
+
+QT_BEGIN_NAMESPACE
+
+QSizeChangeListener::QSizeChangeListener(QQuickItem *item) :
+ item(item)
+{
+ connect(item, &QQuickItem::widthChanged, this, &QSizeChangeListener::onSizeChanged);
+ connect(item, &QQuickItem::heightChanged, this, &QSizeChangeListener::onSizeChanged);
+}
+
+void QSizeChangeListener::onSizeChanged()
+{
+ append(QSize(item->width(), item->height()));
+}
+
+QT_END_NAMESPACE
+
+#include "moc_geometrytestutils_p.cpp"
diff --git a/src/quicktestutils/quick/geometrytestutils_p.h b/src/quicktestutils/quick/geometrytestutils_p.h
new file mode 100644
index 0000000000..867dddeda3
--- /dev/null
+++ b/src/quicktestutils/quick/geometrytestutils_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGEOMETRYTESTUTIL_P_H
+#define QQUICKGEOMETRYTESTUTIL_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 <QObject>
+#include <QVector>
+#include <QSize>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItem;
+
+class QSizeChangeListener : public QObject, public QVector<QSize>
+{
+ Q_OBJECT
+public:
+ explicit QSizeChangeListener(QQuickItem *item);
+private slots:
+ void onSizeChanged();
+private:
+ QQuickItem *item;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKGEOMETRYTESTUTIL_P_H
diff --git a/src/quicktestutils/quick/viewtestutils.cpp b/src/quicktestutils/quick/viewtestutils.cpp
new file mode 100644
index 0000000000..9051eb15a9
--- /dev/null
+++ b/src/quicktestutils/quick/viewtestutils.cpp
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "viewtestutils_p.h"
+
+#include <QtCore/QRandomGenerator>
+#include <QtQuick/QQuickView>
+#include <QtQuick/QQuickView>
+#include <QtGui/QScreen>
+
+#include <QtTest/QTest>
+
+#include <QtQuick/private/qquickdeliveryagent_p_p.h>
+#include <QtQuick/private/qquickitemview_p_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+
+#include <QtQuickTestUtils/private/visualtestutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickView *QQuickViewTestUtils::createView()
+{
+ QQuickView *window = new QQuickView(0);
+ const QSize size(240, 320);
+ window->resize(size);
+ QQuickViewTestUtils::centerOnScreen(window, size);
+ return window;
+}
+
+void QQuickViewTestUtils::centerOnScreen(QQuickView *window, const QSize &size)
+{
+ const QRect screenGeometry = window->screen()->availableGeometry();
+ const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
+ window->setFramePosition(screenGeometry.center() - offset);
+}
+
+void QQuickViewTestUtils::centerOnScreen(QQuickView *window)
+{
+ QQuickViewTestUtils::centerOnScreen(window, window->size());
+}
+
+void QQuickViewTestUtils::moveMouseAway(QQuickView *window)
+{
+#if QT_CONFIG(cursor) // Get the cursor out of the way.
+ QCursor::setPos(window->geometry().topRight() + QPoint(100, 100));
+#else
+ Q_UNUSED(window);
+#endif
+}
+
+void QQuickViewTestUtils::moveAndRelease(QQuickView *window, const QPoint &position)
+{
+ QTest::mouseMove(window, position);
+ QTest::mouseRelease(window, Qt::LeftButton, {}, position);
+}
+
+void QQuickViewTestUtils::moveAndPress(QQuickView *window, const QPoint &position)
+{
+ QTest::mouseMove(window, position);
+ QTest::mousePress(window, Qt::LeftButton, {}, position);
+}
+
+void QQuickViewTestUtils::flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration)
+{
+ const int pointCount = 5;
+ QPoint diff = to - from;
+
+ // send press, five equally spaced moves, and release.
+ moveAndPress(window, from);
+
+ for (int i = 0; i < pointCount; ++i)
+ QTest::mouseMove(window, from + (i+1)*diff/pointCount, duration / pointCount);
+
+ moveAndRelease(window, to);
+ QTest::qWait(50);
+}
+
+QList<int> QQuickViewTestUtils::adjustIndexesForAddDisplaced(const QList<int> &indexes, int index, int count)
+{
+ QList<int> result;
+ for (int i=0; i<indexes.count(); i++) {
+ int num = indexes[i];
+ if (num >= index) {
+ num += count;
+ }
+ result << num;
+ }
+ return result;
+}
+
+QList<int> QQuickViewTestUtils::adjustIndexesForMove(const QList<int> &indexes, int from, int to, int count)
+{
+ QList<int> result;
+ for (int i=0; i<indexes.count(); i++) {
+ int num = indexes[i];
+ if (from < to) {
+ if (num >= from && num < from + count)
+ num += (to - from); // target
+ else if (num >= from && num < to + count)
+ num -= count; // displaced
+ } else if (from > to) {
+ if (num >= from && num < from + count)
+ num -= (from - to); // target
+ else if (num >= to && num < from + count)
+ num += count; // displaced
+ }
+ result << num;
+ }
+ return result;
+}
+
+QList<int> QQuickViewTestUtils::adjustIndexesForRemoveDisplaced(const QList<int> &indexes, int index, int count)
+{
+ QList<int> result;
+ for (int i=0; i<indexes.count(); i++) {
+ int num = indexes[i];
+ if (num >= index)
+ num -= count;
+ result << num;
+ }
+ return result;
+}
+
+QQuickViewTestUtils::QaimModel::QaimModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+}
+
+int QQuickViewTestUtils::QaimModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return list.count();
+}
+
+int QQuickViewTestUtils::QaimModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return columns;
+}
+
+QHash<int,QByteArray> QQuickViewTestUtils::QaimModel::roleNames() const
+{
+ QHash<int,QByteArray> roles = QAbstractListModel::roleNames();
+ roles.insert(Name, "name");
+ roles.insert(Number, "number");
+ return roles;
+}
+
+QVariant QQuickViewTestUtils::QaimModel::data(const QModelIndex &index, int role) const
+{
+ QVariant rv;
+ if (role == Name)
+ rv = list.at(index.row()).first;
+ else if (role == Number)
+ rv = list.at(index.row()).second;
+
+ return rv;
+}
+
+int QQuickViewTestUtils::QaimModel::count() const
+{
+ return rowCount() * columnCount();
+}
+
+QString QQuickViewTestUtils::QaimModel::name(int index) const
+{
+ return list.at(index).first;
+}
+
+QString QQuickViewTestUtils::QaimModel::number(int index) const
+{
+ return list.at(index).second;
+}
+
+void QQuickViewTestUtils::QaimModel::addItem(const QString &name, const QString &number)
+{
+ emit beginInsertRows(QModelIndex(), list.count(), list.count());
+ list.append(QPair<QString,QString>(name, number));
+ emit endInsertRows();
+}
+
+void QQuickViewTestUtils::QaimModel::addItems(const QList<QPair<QString, QString> > &items)
+{
+ emit beginInsertRows(QModelIndex(), list.count(), list.count()+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.append(QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+}
+
+void QQuickViewTestUtils::QaimModel::insertItem(int index, const QString &name, const QString &number)
+{
+ emit beginInsertRows(QModelIndex(), index, index);
+ list.insert(index, QPair<QString,QString>(name, number));
+ emit endInsertRows();
+}
+
+void QQuickViewTestUtils::QaimModel::insertItems(int index, const QList<QPair<QString, QString> > &items)
+{
+ emit beginInsertRows(QModelIndex(), index, index+items.count()-1);
+ for (int i=0; i<items.count(); i++)
+ list.insert(index + i, QPair<QString,QString>(items[i].first, items[i].second));
+ emit endInsertRows();
+}
+
+void QQuickViewTestUtils::QaimModel::removeItem(int index)
+{
+ emit beginRemoveRows(QModelIndex(), index, index);
+ list.removeAt(index);
+ emit endRemoveRows();
+}
+
+void QQuickViewTestUtils::QaimModel::removeItems(int index, int count)
+{
+ emit beginRemoveRows(QModelIndex(), index, index+count-1);
+ while (count--)
+ list.removeAt(index);
+ emit endRemoveRows();
+}
+
+void QQuickViewTestUtils::QaimModel::moveItem(int from, int to)
+{
+ emit beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
+ list.move(from, to);
+ emit endMoveRows();
+}
+
+void QQuickViewTestUtils::QaimModel::moveItems(int from, int to, int count)
+{
+ emit beginMoveRows(QModelIndex(), from, from+count-1, QModelIndex(), to > from ? to+count : to);
+ qquickmodelviewstestutil_move(from, to, count, &list);
+ emit endMoveRows();
+}
+
+void QQuickViewTestUtils::QaimModel::modifyItem(int idx, const QString &name, const QString &number)
+{
+ list[idx] = QPair<QString,QString>(name, number);
+ emit dataChanged(index(idx,0), index(idx,0));
+}
+
+void QQuickViewTestUtils::QaimModel::clear()
+{
+ int count = list.count();
+ if (count > 0) {
+ beginRemoveRows(QModelIndex(), 0, count-1);
+ list.clear();
+ endRemoveRows();
+ }
+}
+
+void QQuickViewTestUtils::QaimModel::reset()
+{
+ emit beginResetModel();
+ emit endResetModel();
+}
+
+void QQuickViewTestUtils::QaimModel::resetItems(const QList<QPair<QString, QString> > &items)
+{
+ beginResetModel();
+ list = items;
+ endResetModel();
+}
+
+class ScopedPrintable
+{
+ Q_DISABLE_COPY_MOVE(ScopedPrintable)
+
+public:
+ ScopedPrintable(const QString &string) : data(QTest::toString(string)) {}
+ ~ScopedPrintable() { delete[] data; }
+
+ operator const char*() const { return data; }
+
+private:
+ const char *data;
+};
+
+void QQuickViewTestUtils::QaimModel::matchAgainst(const QList<QPair<QString, QString> > &other, const QString &error1, const QString &error2) {
+ for (int i=0; i<other.count(); i++) {
+ QVERIFY2(list.contains(other[i]),
+ ScopedPrintable(other[i].first + QLatin1Char(' ') + other[i].second + QLatin1Char(' ') + error1));
+ }
+ for (int i=0; i<list.count(); i++) {
+ QVERIFY2(other.contains(list[i]),
+ ScopedPrintable(list[i].first + QLatin1Char(' ') + list[i].second + QLatin1Char(' ') + error2));
+ }
+}
+
+
+
+QQuickViewTestUtils::ListRange::ListRange()
+ : valid(false)
+{
+}
+
+QQuickViewTestUtils::ListRange::ListRange(const ListRange &other)
+ : valid(other.valid)
+{
+ indexes = other.indexes;
+}
+
+QQuickViewTestUtils::ListRange::ListRange(int start, int end)
+ : valid(true)
+{
+ for (int i=start; i<=end; i++)
+ indexes << i;
+}
+
+QQuickViewTestUtils::ListRange::~ListRange()
+{
+}
+
+QQuickViewTestUtils::ListRange QQuickViewTestUtils::ListRange::operator+(const ListRange &other) const
+{
+ if (other == *this)
+ return *this;
+ ListRange a(*this);
+ a.indexes.append(other.indexes);
+ return a;
+}
+
+bool QQuickViewTestUtils::ListRange::operator==(const ListRange &other) const
+{
+ return QSet<int>(indexes.cbegin(), indexes.cend())
+ == QSet<int>(other.indexes.cbegin(), other.indexes.cend());
+}
+
+bool QQuickViewTestUtils::ListRange::operator!=(const ListRange &other) const
+{
+ return !(*this == other);
+}
+
+bool QQuickViewTestUtils::ListRange::isValid() const
+{
+ return valid;
+}
+
+int QQuickViewTestUtils::ListRange::count() const
+{
+ return indexes.count();
+}
+
+QList<QPair<QString,QString> > QQuickViewTestUtils::ListRange::getModelDataValues(const QaimModel &model)
+{
+ QList<QPair<QString,QString> > data;
+ if (!valid)
+ return data;
+ for (int i=0; i<indexes.count(); i++)
+ data.append(qMakePair(model.name(indexes[i]), model.number(indexes[i])));
+ return data;
+}
+
+QQuickViewTestUtils::StressTestModel::StressTestModel()
+ : QAbstractListModel()
+ , m_rowCount(20)
+{
+ QTimer *t = new QTimer(this);
+ t->setInterval(500);
+ t->start();
+
+ connect(t, &QTimer::timeout, this, &StressTestModel::updateModel);
+}
+
+int QQuickViewTestUtils::StressTestModel::rowCount(const QModelIndex &) const
+{
+ return m_rowCount;
+}
+
+QVariant QQuickViewTestUtils::StressTestModel::data(const QModelIndex &, int) const
+{
+ return QVariant();
+}
+
+void QQuickViewTestUtils::StressTestModel::updateModel()
+{
+ if (m_rowCount > 10) {
+ for (int i = 0; i < 10; ++i) {
+ int rnum = QRandomGenerator::global()->bounded(m_rowCount);
+ beginRemoveRows(QModelIndex(), rnum, rnum);
+ m_rowCount--;
+ endRemoveRows();
+ }
+ }
+ if (m_rowCount < 20) {
+ for (int i = 0; i < 10; ++i) {
+ int rnum = QRandomGenerator::global()->bounded(m_rowCount);
+ beginInsertRows(QModelIndex(), rnum, rnum);
+ m_rowCount++;
+ endInsertRows();
+ }
+ }
+}
+
+bool QQuickViewTestUtils::testVisibleItems(const QQuickItemViewPrivate *priv, bool *nonUnique, FxViewItem **failItem, int *expectedIdx)
+{
+ QHash<QQuickItem*, int> uniqueItems;
+
+ int skip = 0;
+ for (int i = 0; i < priv->visibleItems.count(); ++i) {
+ FxViewItem *item = priv->visibleItems.at(i);
+ if (!item) {
+ *failItem = nullptr;
+ return false;
+ }
+#if 0
+ qDebug() << "\t" << item->index
+ << item->item
+ << item->position()
+ << (!item->item || QQuickItemPrivate::get(item->item)->culled ? "hidden" : "visible");
+#endif
+ if (item->index == -1) {
+ ++skip;
+ } else if (item->index != priv->visibleIndex + i - skip) {
+ *nonUnique = false;
+ *failItem = item;
+ *expectedIdx = priv->visibleIndex + i - skip;
+ return false;
+ } else if (uniqueItems.contains(item->item)) {
+ *nonUnique = true;
+ *failItem = item;
+ *expectedIdx = uniqueItems.find(item->item).value();
+ return false;
+ }
+
+ uniqueItems.insert(item->item, item->index);
+ }
+
+ return true;
+}
+
+namespace QQuickTouchUtils {
+
+ /* QQuickWindow does event compression and only delivers events just
+ * before it is about to render the next frame. Since some tests
+ * rely on events being delivered immediately AND that no other
+ * event processing has occurred in the meanwhile, we flush the
+ * event manually and immediately.
+ */
+ void flush(QQuickWindow *window) {
+ if (!window)
+ return;
+ QQuickDeliveryAgentPrivate *da = QQuickWindowPrivate::get(window)->deliveryAgentPrivate();
+ if (!da || !da->delayedTouch)
+ return;
+ da->deliverDelayedTouchEvent();
+ }
+
+}
+
+namespace QQuickTest {
+
+ /*! \internal
+ Initialize \a view, set \a url, center in available geometry, move mouse away if desired.
+ If \a errorMessage is given, QQuickView::errors() will be concatenated into it;
+ otherwise, the QWARN messages are generally enough to debug the test.
+
+ Returns \c false if the view fails to load the QML. That should be fatal in most tests,
+ so normally the return value should be checked with QVERIFY.
+ */
+ bool initView(QQuickView &view, const QUrl &url, bool moveMouseOut, QByteArray *errorMessage)
+ {
+ view.setSource(url);
+ while (view.status() == QQuickView::Loading)
+ QTest::qWait(10);
+ if (view.status() != QQuickView::Ready) {
+ if (errorMessage) {
+ for (const QQmlError &e : view.errors())
+ errorMessage->append(e.toString().toLocal8Bit() + '\n');
+ }
+ return false;
+ }
+ const QRect screenGeometry = view.screen()->availableGeometry();
+ const QSize size = view.size();
+ const QPoint offset = QPoint(size.width() / 2, size.height() / 2);
+ view.setFramePosition(screenGeometry.center() - offset);
+ #if QT_CONFIG(cursor) // Get the cursor out of the way.
+ if (moveMouseOut)
+ QCursor::setPos(view.geometry().topRight() + QPoint(100, 100));
+ #else
+ Q_UNUSED(moveMouseOut);
+ #endif
+ return true;
+ }
+
+ /*! \internal
+ Initialize \a view, set \a url, center in available geometry, move mouse away,
+ show the \a view, wait for it to be exposed, and verify that its rootObject is not null.
+
+ Returns \c false if anything fails, which should be fatal in most tests.
+ The usual way to call this function is
+ \code
+ QQuickView window;
+ QVERIFY(QQuickTest::showView(window, testFileUrl("myitems.qml")));
+ \endcode
+ */
+ bool showView(QQuickView &view, const QUrl &url)
+ {
+ if (!initView(view, url))
+ return false;
+ view.show();
+ if (!QTest::qWaitForWindowExposed(&view))
+ return false;
+ if (!view.rootObject())
+ return false;
+ return true;
+ }
+}
+
+QT_END_NAMESPACE
+
+#include "moc_viewtestutils_p.cpp"
diff --git a/src/quicktestutils/quick/viewtestutils_p.h b/src/quicktestutils/quick/viewtestutils_p.h
new file mode 100644
index 0000000000..fd38844446
--- /dev/null
+++ b/src/quicktestutils/quick/viewtestutils_p.h
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKVIEWTESTUTILS_P_H
+#define QQUICKVIEWTESTUTILS_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/QAbstractListModel>
+#include <QtQml/QQmlExpression>
+#include <QtQuick/QQuickItem>
+
+QT_FORWARD_DECLARE_CLASS(QQuickView)
+QT_FORWARD_DECLARE_CLASS(QQuickItemViewPrivate)
+QT_FORWARD_DECLARE_CLASS(FxViewItem)
+
+QT_BEGIN_NAMESPACE
+
+namespace QQuickViewTestUtils
+{
+ QQuickView *createView();
+
+ void flick(QQuickView *window, const QPoint &from, const QPoint &to, int duration);
+ void centerOnScreen(QQuickView *window, const QSize &size);
+ void centerOnScreen(QQuickView *window);
+ void moveMouseAway(QQuickView *window);
+ void moveAndPress(QQuickView *window, const QPoint &position);
+ void moveAndRelease(QQuickView *window, const QPoint &position);
+
+ QList<int> adjustIndexesForAddDisplaced(const QList<int> &indexes, int index, int count);
+ QList<int> adjustIndexesForMove(const QList<int> &indexes, int from, int to, int count);
+ QList<int> adjustIndexesForRemoveDisplaced(const QList<int> &indexes, int index, int count);
+
+ struct ListChange {
+ enum { Inserted, Removed, Moved, SetCurrent, SetContentY, Polish } type;
+ int index;
+ int count;
+ int to; // Move
+ qreal pos; // setContentY
+
+ static ListChange insert(int index, int count = 1) { ListChange c = { Inserted, index, count, -1, 0.0 }; return c; }
+ static ListChange remove(int index, int count = 1) { ListChange c = { Removed, index, count, -1, 0.0 }; return c; }
+ static ListChange move(int index, int to, int count) { ListChange c = { Moved, index, count, to, 0.0 }; return c; }
+ static ListChange setCurrent(int index) { ListChange c = { SetCurrent, index, -1, -1, 0.0 }; return c; }
+ static ListChange setContentY(qreal pos) { ListChange c = { SetContentY, -1, -1, -1, pos }; return c; }
+ static ListChange polish() { ListChange c = { Polish, -1, -1, -1, 0.0 }; return c; }
+ };
+
+ class QaimModel : public QAbstractListModel
+ {
+ Q_OBJECT
+ public:
+ enum Roles { Name = Qt::UserRole+1, Number = Qt::UserRole+2 };
+
+ QaimModel(QObject *parent=0);
+
+ int rowCount(const QModelIndex &parent=QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent=QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override;
+ QHash<int,QByteArray> roleNames() const override;
+
+ int count() const;
+ QString name(int index) const;
+ QString number(int index) const;
+
+ Q_INVOKABLE void addItem(const QString &name, const QString &number);
+ void addItems(const QList<QPair<QString, QString> > &items);
+ void insertItem(int index, const QString &name, const QString &number);
+ void insertItems(int index, const QList<QPair<QString, QString> > &items);
+
+ Q_INVOKABLE void removeItem(int index);
+ void removeItems(int index, int count);
+
+ void moveItem(int from, int to);
+ void moveItems(int from, int to, int count);
+
+ void modifyItem(int idx, const QString &name, const QString &number);
+
+ void clear();
+ void reset();
+ void resetItems(const QList<QPair<QString, QString> > &items);
+
+ void matchAgainst(const QList<QPair<QString, QString> > &other, const QString &error1, const QString &error2);
+
+ using QAbstractListModel::dataChanged;
+
+ int columns = 1;
+
+ private:
+ QList<QPair<QString,QString> > list;
+ };
+
+ class ListRange
+ {
+ public:
+ ListRange();
+ ListRange(const ListRange &other);
+ ListRange(int start, int end);
+
+ ~ListRange();
+
+ ListRange operator+(const ListRange &other) const;
+ bool operator==(const ListRange &other) const;
+ bool operator!=(const ListRange &other) const;
+
+ bool isValid() const;
+ int count() const;
+
+ QList<QPair<QString,QString> > getModelDataValues(const QaimModel &model);
+
+ QList<int> indexes;
+ bool valid;
+ };
+
+ template<typename T>
+ static void qquickmodelviewstestutil_move(int from, int to, int n, T *items)
+ {
+ if (from > to) {
+ // Only move forwards - flip if backwards moving
+ int tfrom = from;
+ int tto = to;
+ from = tto;
+ to = tto+n;
+ n = tfrom-tto;
+ }
+
+ T replaced;
+ int i=0;
+ typename T::ConstIterator it=items->begin(); it += from+n;
+ for (; i<to-from; ++i,++it)
+ replaced.append(*it);
+ i=0;
+ it=items->begin(); it += from;
+ for (; i<n; ++i,++it)
+ replaced.append(*it);
+ typename T::ConstIterator f=replaced.begin();
+ typename T::Iterator t=items->begin(); t += from;
+ for (; f != replaced.end(); ++f, ++t)
+ *t = *f;
+ }
+
+ class StressTestModel : public QAbstractListModel
+ {
+ Q_OBJECT
+
+ public:
+
+ StressTestModel();
+
+ int rowCount(const QModelIndex &) const override;
+ QVariant data(const QModelIndex &, int) const override;
+
+ public Q_SLOTS:
+ void updateModel();
+
+ private:
+ int m_rowCount;
+ };
+
+ [[nodiscard]] bool testVisibleItems(const QQuickItemViewPrivate *priv,
+ bool *nonUnique, FxViewItem **failItem, int *expectedIdx);
+}
+
+namespace QQuickTouchUtils {
+ void flush(QQuickWindow *window);
+}
+
+namespace QQuickTest {
+ [[nodiscard]] bool initView(QQuickView &v, const QUrl &url,
+ bool moveMouseOut = true, QByteArray *errorMessage = nullptr);
+ [[nodiscard]] bool showView(QQuickView &v, const QUrl &url);
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QQuickViewTestUtils::QaimModel*)
+Q_DECLARE_METATYPE(QQuickViewTestUtils::ListChange)
+Q_DECLARE_METATYPE(QList<QQuickViewTestUtils::ListChange>)
+Q_DECLARE_METATYPE(QQuickViewTestUtils::ListRange)
+
+
+#endif // QQUICKVIEWTESTUTILS_P_H
diff --git a/src/quicktestutils/quick/visualtestutils.cpp b/src/quicktestutils/quick/visualtestutils.cpp
new file mode 100644
index 0000000000..272002c7ac
--- /dev/null
+++ b/src/quicktestutils/quick/visualtestutils.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "visualtestutils_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtQuick/QQuickItem>
+#include <QtQuick/private/qquickitemview_p.h>
+#include <QtQuickTest/QtQuickTest>
+
+QT_BEGIN_NAMESPACE
+
+QQuickItem *QQuickVisualTestUtils::findVisibleChild(QQuickItem *parent, const QString &objectName)
+{
+ QQuickItem *item = 0;
+ QList<QQuickItem*> items = parent->findChildren<QQuickItem*>(objectName);
+ for (int i = 0; i < items.count(); ++i) {
+ if (items.at(i)->isVisible() && !QQuickItemPrivate::get(items.at(i))->culled) {
+ item = items.at(i);
+ break;
+ }
+ }
+ return item;
+}
+
+void QQuickVisualTestUtils::dumpTree(QQuickItem *parent, int depth)
+{
+ static QString padding = QStringLiteral(" ");
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ qDebug() << padding.left(depth*2) << item;
+ dumpTree(item, depth+1);
+ }
+}
+
+void QQuickVisualTestUtils::moveMouseAway(QQuickWindow *window)
+{
+#if QT_CONFIG(cursor) // Get the cursor out of the way.
+ // Using "bottomRight() + QPoint(100, 100)" was causing issues on Ubuntu,
+ // where the window was positioned at the bottom right corner of the window
+ // (even after centering the window on the screen), so we use another position.
+ QCursor::setPos(window->frameGeometry().bottomLeft() + QPoint(-10, 10));
+#endif
+
+ // make sure hover events from QQuickWindowPrivate::flushFrameSynchronousEvents()
+ // do not interfere with the tests
+ QEvent leave(QEvent::Leave);
+ QCoreApplication::sendEvent(window, &leave);
+}
+
+void QQuickVisualTestUtils::centerOnScreen(QQuickWindow *window)
+{
+ const QRect screenGeometry = window->screen()->availableGeometry();
+ const QPoint offset = QPoint(window->width() / 2, window->height() / 2);
+ window->setFramePosition(screenGeometry.center() - offset);
+}
+
+bool QQuickVisualTestUtils::delegateVisible(QQuickItem *item)
+{
+ return item->isVisible() && !QQuickItemPrivate::get(item)->culled;
+}
+
+/*!
+ \internal
+
+ Compares \a ia with \a ib, returning \c true if the images are equal.
+ If they are not equal, \c false is returned and \a errorMessage is set.
+
+ A custom compare function to avoid issues such as:
+ When running on native Nvidia graphics cards on linux, the
+ distance field glyph pixels have a measurable, but not visible
+ pixel error. This was GT-216 with the ubuntu "nvidia-319" driver package.
+ llvmpipe does not show the same issue.
+*/
+bool QQuickVisualTestUtils::compareImages(const QImage &ia, const QImage &ib, QString *errorMessage)
+{
+ if (ia.size() != ib.size()) {
+ QDebug(errorMessage) << "Images are of different size:" << ia.size() << ib.size()
+ << "DPR:" << ia.devicePixelRatio() << ib.devicePixelRatio();
+ return false;
+ }
+ if (ia.format() != ib.format()) {
+ QDebug(errorMessage) << "Images are of different formats:" << ia.format() << ib.format();
+ return false;
+ }
+
+ int w = ia.width();
+ int h = ia.height();
+ const int tolerance = 5;
+ for (int y=0; y<h; ++y) {
+ const uint *as= (const uint *) ia.constScanLine(y);
+ const uint *bs= (const uint *) ib.constScanLine(y);
+ for (int x=0; x<w; ++x) {
+ uint a = as[x];
+ uint b = bs[x];
+
+ // No tolerance for error in the alpha.
+ if ((a & 0xff000000) != (b & 0xff000000)
+ || qAbs(qRed(a) - qRed(b)) > tolerance
+ || qAbs(qRed(a) - qRed(b)) > tolerance
+ || qAbs(qRed(a) - qRed(b)) > tolerance) {
+ QDebug(errorMessage) << "Mismatch at:" << x << y << ':'
+ << Qt::hex << Qt::showbase << a << b;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Finds the delegate at \c index belonging to \c itemView, using the given \c flags.
+
+ If the view needs to be polished, the function will wait for it to be done before continuing,
+ and returns \c nullptr if the polish didn't happen.
+*/
+QQuickItem *QQuickVisualTestUtils::findViewDelegateItem(QQuickItemView *itemView, int index, FindViewDelegateItemFlags flags)
+{
+ if (QQuickTest::qIsPolishScheduled(itemView)) {
+ if (!QQuickTest::qWaitForItemPolished(itemView)) {
+ qWarning() << "failed to polish" << itemView;
+ return nullptr;
+ }
+ }
+
+ // Do this after the polish, just in case the count changes after a polish...
+ if (index <= -1 || index >= itemView->count()) {
+ qWarning() << "index" << index << "is out of bounds for" << itemView;
+ return nullptr;
+ }
+
+ if (flags.testFlag(FindViewDelegateItemFlag::PositionViewAtIndex))
+ itemView->positionViewAtIndex(index, QQuickItemView::Center);
+
+ return itemView->itemAtIndex(index);
+}
+
+QQuickVisualTestUtils::QQuickApplicationHelper::QQuickApplicationHelper(QQmlDataTest *testCase,
+ const QString &testFilePath, const QVariantMap &initialProperties, const QStringList &qmlImportPaths)
+{
+ for (const auto &path : qmlImportPaths)
+ engine.addImportPath(path);
+
+ QQmlComponent component(&engine);
+
+ component.loadUrl(testCase->testFileUrl(testFilePath));
+ QVERIFY2(component.isReady(), qPrintable(component.errorString()));
+ QObject *rootObject = component.createWithInitialProperties(initialProperties);
+ cleanup.reset(rootObject);
+ if (component.isError() || !rootObject) {
+ errorMessage = QString::fromUtf8("Failed to create window: %1").arg(component.errorString()).toUtf8();
+ return;
+ }
+
+ window = qobject_cast<QQuickWindow*>(rootObject);
+ if (!window) {
+ errorMessage = QString::fromUtf8("Root object %1 must be a QQuickWindow subclass").arg(QDebug::toString(window)).toUtf8();
+ return;
+ }
+
+ if (window->isVisible()) {
+ errorMessage = QString::fromUtf8("Expected window not to be visible, but it is").toUtf8();
+ return;
+ }
+
+ ready = true;
+}
+
+QQuickVisualTestUtils::MnemonicKeySimulator::MnemonicKeySimulator(QWindow *window)
+ : m_window(window), m_modifiers(Qt::NoModifier)
+{
+}
+
+void QQuickVisualTestUtils::MnemonicKeySimulator::press(Qt::Key key)
+{
+ // QTest::keyPress() but not generating the press event for the modifier key.
+ if (key == Qt::Key_Alt)
+ m_modifiers |= Qt::AltModifier;
+ QTest::simulateEvent(m_window, true, key, m_modifiers, QString(), false);
+}
+
+void QQuickVisualTestUtils::MnemonicKeySimulator::release(Qt::Key key)
+{
+ // QTest::keyRelease() but not generating the release event for the modifier key.
+ if (key == Qt::Key_Alt)
+ m_modifiers &= ~Qt::AltModifier;
+ QTest::simulateEvent(m_window, false, key, m_modifiers, QString(), false);
+}
+
+void QQuickVisualTestUtils::MnemonicKeySimulator::click(Qt::Key key)
+{
+ press(key);
+ release(key);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_visualtestutils_p.cpp"
diff --git a/src/quicktestutils/quick/visualtestutils_p.h b/src/quicktestutils/quick/visualtestutils_p.h
new file mode 100644
index 0000000000..18967f670e
--- /dev/null
+++ b/src/quicktestutils/quick/visualtestutils_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKVISUALTESTUTILS_P_H
+#define QQUICKVISUALTESTUTILS_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/qqmlexpression.h>
+#include <QtQuick/private/qquickitem_p.h>
+
+#include <private/qmlutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickItemView;
+class QQuickWindow;
+
+namespace QQuickVisualTestUtils
+{
+ QQuickItem *findVisibleChild(QQuickItem *parent, const QString &objectName);
+
+ void dumpTree(QQuickItem *parent, int depth = 0);
+
+ void moveMouseAway(QQuickWindow *window);
+ void centerOnScreen(QQuickWindow *window);
+
+ [[nodiscard]] bool delegateVisible(QQuickItem *item);
+
+ /*
+ Find an item with the specified objectName. If index is supplied then the
+ item must also evaluate the {index} expression equal to index
+ */
+ template<typename T>
+ T *findItem(QQuickItem *parent, const QString &objectName, int index = -1)
+ {
+ const QMetaObject &mo = T::staticMetaObject;
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item)
+ continue;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName)) {
+ if (index != -1) {
+ QQmlContext *context = qmlContext(item);
+ if (!context->isValid())
+ continue;
+ QQmlExpression e(context, item, "index");
+ if (e.evaluate().toInt() == index)
+ return static_cast<T*>(item);
+ } else {
+ return static_cast<T*>(item);
+ }
+ }
+ item = findItem<T>(item, objectName, index);
+ if (item)
+ return static_cast<T*>(item);
+ }
+
+ return 0;
+ }
+
+ template<typename T>
+ QList<T*> findItems(QQuickItem *parent, const QString &objectName, bool visibleOnly = true)
+ {
+ QList<T*> items;
+ const QMetaObject &mo = T::staticMetaObject;
+ for (int i = 0; i < parent->childItems().count(); ++i) {
+ QQuickItem *item = qobject_cast<QQuickItem*>(parent->childItems().at(i));
+ if (!item || (visibleOnly && (!item->isVisible() || QQuickItemPrivate::get(item)->culled)))
+ continue;
+ if (mo.cast(item) && (objectName.isEmpty() || item->objectName() == objectName))
+ items.append(static_cast<T*>(item));
+ items += findItems<T>(item, objectName);
+ }
+
+ return items;
+ }
+
+ template<typename T>
+ QList<T*> findItems(QQuickItem *parent, const QString &objectName, const QList<int> &indexes)
+ {
+ QList<T*> items;
+ for (int i=0; i<indexes.count(); i++)
+ items << qobject_cast<QQuickItem*>(findItem<T>(parent, objectName, indexes[i]));
+ return items;
+ }
+
+ bool compareImages(const QImage &ia, const QImage &ib, QString *errorMessage);
+
+ struct SignalMultiSpy : public QObject
+ {
+ Q_OBJECT
+ public:
+ QList<QObject *> senders;
+ QList<QByteArray> signalNames;
+
+ template <typename Func1>
+ QMetaObject::Connection connectToSignal(const typename QtPrivate::FunctionPointer<Func1>::Object *obj, Func1 signal,
+ Qt::ConnectionType type = Qt::AutoConnection)
+ {
+ return connect(obj, signal, this, &SignalMultiSpy::receive, type);
+ }
+
+ void clear() {
+ senders.clear();
+ signalNames.clear();
+ }
+
+ public slots:
+ void receive() {
+ QMetaMethod m = sender()->metaObject()->method(senderSignalIndex());
+ senders << sender();
+ signalNames << m.name();
+ }
+ };
+
+ enum class FindViewDelegateItemFlag {
+ None = 0x0,
+ PositionViewAtIndex = 0x01
+ };
+ Q_DECLARE_FLAGS(FindViewDelegateItemFlags, FindViewDelegateItemFlag)
+
+ QQuickItem* findViewDelegateItem(QQuickItemView *itemView, int index,
+ FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex);
+
+ /*!
+ \internal
+
+ Same as above except allows use in QTRY_* functions without having to call it again
+ afterwards to assign the delegate.
+ */
+ template<typename T>
+ [[nodiscard]] bool findViewDelegateItem(QQuickItemView *itemView, int index, T &delegateItem,
+ FindViewDelegateItemFlags flags = FindViewDelegateItemFlag::PositionViewAtIndex)
+ {
+ delegateItem = qobject_cast<T>(findViewDelegateItem(itemView, index, flags));
+ return delegateItem != nullptr;
+ }
+
+ class QQuickApplicationHelper
+ {
+ public:
+ QQuickApplicationHelper(QQmlDataTest *testCase, const QString &testFilePath,
+ const QVariantMap &initialProperties = {},
+ const QStringList &qmlImportPaths = {});
+
+ // Return a C-style string instead of QString because that's what QTest uses for error messages,
+ // so it saves code at the calling site.
+ inline const char *failureMessage() const
+ {
+ return errorMessage.constData();
+ }
+
+ QQmlEngine engine;
+ QScopedPointer<QObject> cleanup;
+ QQuickWindow *window = nullptr;
+
+ bool ready = false;
+ // Store as a byte array so that we can return its raw data safely;
+ // using qPrintable() in failureMessage() will construct a throwaway QByteArray
+ // that is destroyed before the function returns.
+ QByteArray errorMessage;
+ };
+
+ class MnemonicKeySimulator
+ {
+ Q_DISABLE_COPY(MnemonicKeySimulator)
+ public:
+ explicit MnemonicKeySimulator(QWindow *window);
+
+ void press(Qt::Key key);
+ void release(Qt::Key key);
+ void click(Qt::Key key);
+
+ private:
+ QPointer<QWindow> m_window;
+ Qt::KeyboardModifiers m_modifiers;
+ };
+}
+
+#define QQUICK_VERIFY_POLISH(item) \
+ QTRY_COMPARE(QQuickItemPrivate::get(item)->polishScheduled, false)
+
+QT_END_NAMESPACE
+
+#endif // QQUICKVISUALTESTUTILS_P_H
diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp
index d0cc6f9048..d316d12588 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -83,6 +83,11 @@
#include <QtQuick/qquickgraphicsdevice.h>
#include <QtQuick/qquickrendertarget.h>
+#include "private/qwidget_p.h"
+
+#include <QtWidgets/qgraphicsscene.h>
+#include <QtWidgets/qgraphicsview.h>
+
QT_BEGIN_NAMESPACE
QQuickWidgetOffscreenWindow::QQuickWidgetOffscreenWindow(QQuickWindowPrivate &dd, QQuickRenderControl *control)
@@ -104,19 +109,80 @@ public:
}
};
+class QQuickWidgetRenderControlPrivate;
+
class QQuickWidgetRenderControl : public QQuickRenderControl
{
+ Q_DECLARE_PRIVATE(QQuickWidgetRenderControl)
public:
- QQuickWidgetRenderControl(QQuickWidget *quickwidget) : m_quickWidget(quickwidget) {}
- QWindow *renderWindow(QPoint *offset) override {
- if (offset)
- *offset = m_quickWidget->mapTo(m_quickWidget->window(), QPoint());
- return m_quickWidget->window()->windowHandle();
+ QQuickWidgetRenderControl(QQuickWidget *quickwidget);
+ QWindow *renderWindow(QPoint *offset) override;
+
+};
+
+class QQuickWidgetRenderControlPrivate : public QQuickRenderControlPrivate
+{
+public:
+ Q_DECLARE_PUBLIC(QQuickWidgetRenderControl)
+ QQuickWidgetRenderControlPrivate(QQuickWidgetRenderControl *renderControl, QQuickWidget *qqw)
+ : QQuickRenderControlPrivate(renderControl)
+ , m_quickWidget(qqw)
+ {
+ }
+
+ bool isRenderWindow(const QWindow *w) override {
+#if QT_CONFIG(graphicsview)
+ QWidgetPrivate *widgetd = QWidgetPrivate::get(m_quickWidget);
+ auto *proxy = (widgetd && widgetd->extra) ? widgetd->extra->proxyWidget : nullptr;
+ auto *scene = proxy ? proxy->scene() : nullptr;
+ if (scene) {
+ for (const auto &view : scene->views()) {
+ if (view->window()->windowHandle() == w)
+ return true;
+ }
+ }
+
+ return m_quickWidget->window()->windowHandle() == w;
+#endif
}
-private:
QQuickWidget *m_quickWidget;
};
+QQuickWidgetRenderControl::QQuickWidgetRenderControl(QQuickWidget *quickWidget)
+ : QQuickRenderControl(*(new QQuickWidgetRenderControlPrivate(this, quickWidget)), nullptr)
+{
+}
+
+QWindow *QQuickWidgetRenderControl::renderWindow(QPoint *offset)
+{
+ Q_D(QQuickWidgetRenderControl);
+ if (offset)
+ *offset = d->m_quickWidget->mapTo(d->m_quickWidget->window(), QPoint());
+
+ QWindow *result = nullptr;
+#if QT_CONFIG(graphicsview)
+ QWidgetPrivate *widgetd = QWidgetPrivate::get(d->m_quickWidget);
+ if (widgetd->extra) {
+ if (auto proxy = widgetd->extra->proxyWidget) {
+ auto scene = proxy->scene();
+ if (scene) {
+ const auto views = scene->views();
+ if (!views.isEmpty()) {
+ // Get the first QGV containing the proxy. Not ideal, but the callers
+ // of this function aren't prepared to handle more than one render window.
+ auto candidateView = views.first();
+ result = candidateView->window()->windowHandle();
+ }
+ }
+ }
+ }
+#endif
+ if (!result)
+ result = d->m_quickWidget->window()->windowHandle();
+
+ return result;
+}
+
void QQuickWidgetPrivate::initOffscreenWindow()
{
Q_Q(QQuickWidget);
@@ -492,19 +558,24 @@ QImage QQuickWidgetPrivate::grabFramebuffer()
size of the view. Alternatively the resizeMode may be set to SizeRootObjectToView which
will resize the view to the size of the root object.
- \note QQuickWidget is an alternative to using QQuickView and QWidget::createWindowContainer().
+ \section1 Performance Considerations
+
+ QQuickWidget is an alternative to using QQuickView and QWidget::createWindowContainer().
The restrictions on stacking order do not apply, making QQuickWidget the more flexible
alternative, behaving more like an ordinary widget.
- \note However, the above mentioned advantages come at the expense of performance.
- Unlike QQuickWindow and QQuickView, QQuickWidget requires rendering into OpenGL
+ However, the above mentioned advantages come at the expense of performance:
+ \list
+
+ \li Unlike QQuickWindow and QQuickView, QQuickWidget requires rendering into OpenGL
framebuffer objects, which needs to be enforced by calling
- QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi) at startup.
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL) at startup.
This will naturally carry a minor performance hit.
- \note Using QQuickWidget disables the threaded render loop on all platforms. This means that
- some of the benefits of threaded rendering, for example \l Animator classes and vsync driven
- animations, will not be available.
+ \li Using QQuickWidget disables the \l{threaded_render_loop}{threaded render loop} on all
+ platforms. This means that some of the benefits of threaded rendering, for example
+ \l Animator classes and vsync driven animations, will not be available.
+ \endlist
\note Avoid calling winId() on a QQuickWidget. This function triggers the creation of
a native window, resulting in reduced performance and possibly rendering glitches. The
@@ -593,6 +664,7 @@ QQuickWidget::QQuickWidget(QWidget *parent)
{
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
+ setAttribute(Qt::WA_AcceptTouchEvents);
d_func()->init();
}
@@ -1567,9 +1639,23 @@ bool QQuickWidget::event(QEvent *e)
case QEvent::TouchBegin:
case QEvent::TouchEnd:
case QEvent::TouchUpdate:
- case QEvent::TouchCancel:
+ case QEvent::TouchCancel: {
// Touch events only have local and global positions, no need to map.
- return QCoreApplication::sendEvent(d->offscreenWindow, e);
+ bool res = QCoreApplication::sendEvent(d->offscreenWindow, e);
+ if (e->isAccepted() && e->type() == QEvent::TouchBegin) {
+ // If the TouchBegin got accepted, then make sure all points that have
+ // an exclusive grabber are also accepted so that the widget code for
+ // delivering touch events make this widget an implicit grabber of those
+ // points.
+ QPointerEvent *pointerEvent = static_cast<QPointerEvent *>(e);
+ auto deliveredPoints = pointerEvent->points();
+ for (auto &point : deliveredPoints) {
+ if (pointerEvent->exclusiveGrabber(point))
+ point.setAccepted(true);
+ }
+ }
+ return res;
+ }
case QEvent::FocusAboutToChange:
return QCoreApplication::sendEvent(d->offscreenWindow, e);
@@ -1837,4 +1923,6 @@ Q_CONSTRUCTOR_FUNCTION(qt_registerDefaultPlatformBackingStoreOpenGLSupport);
QT_END_NAMESPACE
+#include "moc_qquickwidget_p.cpp"
+
#include "moc_qquickwidget.cpp"