aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates2')
-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
187 files changed, 57896 insertions, 0 deletions
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
+}