Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqstylekitdelegatecontainer.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtQuick/private/qquickitem_p.h>
5
7#include "../qqstylekitcontrolproperties_p.h"
8
10
11QQmlComponent* QQStyleKitDelegateContainer::s_defaultDelegateComponent = nullptr;
12QQmlComponent* QQStyleKitDelegateContainer::s_defaultShadowComponent = nullptr;
13
14QQStyleKitDelegateContainer::QQStyleKitDelegateContainer(QQuickItem *parent)
15 : QQuickItem(parent)
16{
17}
18
20{
21 // Disconnect before QQuickItem::~QQuickItem() reparents children, which emits
22 // signals. At that point our vtable would already be replaced with QQuickItem's,
23 // causing assertObjectType to fail.
24 if (m_delegateInstance)
25 disconnect(m_delegateInstance, nullptr, this, nullptr);
26}
27
28QQStyleKitDelegateProperties *QQStyleKitDelegateContainer::delegateStyle() const
29{
30 return m_delegateProperties;
31}
32
33void QQStyleKitDelegateContainer::setDelegateStyle(QQStyleKitDelegateProperties *delegateProperties)
34{
35 if (m_delegateProperties == delegateProperties)
36 return;
37
38 if (m_delegateProperties) {
39 /* We don't expect m_delegateProperties to change after componentCompleted(), since it's bound
40 * to a controls StyleKitReader, which is not supposed to change. So, considering that there
41 * might be hundreds of delegate instances in an application, we try to save some connections
42 * this way. But note, this is only an optimization, not a technical limitation. */
43 qmlWarning(this) << "Changing delegateStyle on StyleKitContainer is not supported.";
44 return;
45 }
46
47 m_delegateProperties = delegateProperties;
48 emit delegateStyleChanged();
49}
50
52{
53 return m_control;
54}
55
57{
58 if (m_control == control)
59 return;
60 m_control = control;
61 emit quickControlChanged();
62}
63
65{
66 return m_delegateInstance;
67}
68
70{
71 return m_delegateComponent == s_defaultDelegateComponent;
72}
73
74void QQStyleKitDelegateContainer::updateImplicitSize()
75{
76 setImplicitWidth(m_delegateInstance ? m_delegateInstance->implicitWidth() : 0);
77 setImplicitHeight(m_delegateInstance ? m_delegateInstance->implicitHeight() : 0);
78}
79
80void QQStyleKitDelegateContainer::maybeCreateDelegate()
81{
82 if (m_delegateInstance)
83 return;
84 if (!m_delegateProperties)
85 return;
86
87 if (!m_delegateProperties->visible()) {
88 connect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
89 this, &QQStyleKitDelegateContainer::maybeCreateDelegate, Qt::UniqueConnection);
90 return;
91 }
92
93 disconnect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
94 this, &QQStyleKitDelegateContainer::maybeCreateDelegate);
95
96 const bool wasUsingDefaultDelegate = usingDefaultDelegate();
97
98 if (QQmlComponent *delegateComponent = m_delegateProperties->delegate()) {
99 m_delegateComponent = delegateComponent;
100 } else {
101 if (!s_defaultDelegateComponent || s_defaultDelegateComponent->engine() != qmlEngine(this)) {
102 delete s_defaultDelegateComponent;
103 QQmlEngine *engine = qmlEngine(this);
104 s_defaultDelegateComponent = new QQmlComponent(engine);
105 const QString qmlCode = QString::fromUtf8(R"(
106 import QtQuick
107 import Qt.labs.StyleKit
108 StyledItem {
109 width: parent.width
110 height: parent.height
111 }
112 )");
113 s_defaultDelegateComponent->setData(qmlCode.toUtf8(), QUrl());
114 Q_ASSERT_X(!s_defaultDelegateComponent->isError(), __FUNCTION__,
115 s_defaultDelegateComponent->errorString().toUtf8().constData());
116 }
117 m_delegateComponent = s_defaultDelegateComponent;
118 }
119
120 QQmlContext *ctx = QQmlEngine::contextForObject(this);
121 m_delegateInstance = qobject_cast<QQuickItem*>(m_delegateComponent->beginCreate(ctx));
122 Q_ASSERT(m_delegateInstance);
123 m_delegateInstance->setParent(this);
124 m_delegateInstance->setParentItem(this);
125 m_delegateInstance->setProperty("control", QVariant::fromValue(m_control.get()));
126 m_delegateInstance->setProperty("delegateStyle", QVariant::fromValue(m_delegateProperties.get()));
127 m_delegateComponent->completeCreate();
128
129 updateImplicitSize();
130 connect(m_delegateInstance, &QQuickItem::implicitWidthChanged, this, &QQStyleKitDelegateContainer::updateImplicitSize);
131 connect(m_delegateInstance, &QQuickItem::implicitHeightChanged, this, &QQStyleKitDelegateContainer::updateImplicitSize);
132
133 if (usingDefaultDelegate() != wasUsingDefaultDelegate)
134 emit usingDefaultDelegateChanged();
135}
136
137void QQStyleKitDelegateContainer::maybeCreateShadow()
138{
139 if (m_shadowInstance)
140 return;
141 if (!m_delegateProperties)
142 return;
143
144 if (!m_delegateProperties->visible()) {
145 connect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
146 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
147 return;
148 }
149 if (!m_delegateProperties->shadow()->visible()) {
150 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::visibleChanged,
151 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
152 return;
153 }
154 if (m_delegateProperties->shadow()->color().alpha() == 0) {
155 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::colorChanged,
156 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
157 return;
158 }
159 if (m_delegateProperties->shadow()->opacity() == 0) {
160 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::opacityChanged,
161 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
162 return;
163 }
164
165 disconnect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
166 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
167 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::visibleChanged,
168 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
169 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::colorChanged,
170 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
171 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::opacityChanged,
172 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
173
174 if (QQmlComponent *shadowComponent = m_delegateProperties->shadow()->delegate()) {
175 m_shadowComponent = shadowComponent;
176 } else {
177 if (!s_defaultShadowComponent || s_defaultShadowComponent->engine() != qmlEngine(this)) {
178 delete s_defaultShadowComponent;
179 QQmlEngine *engine = qmlEngine(this);
180 s_defaultShadowComponent = new QQmlComponent(engine);
181 const QString qmlCode = QString::fromUtf8(R"(
182 import Qt.labs.StyleKit.impl
183 Shadow {}
184 )");
185 s_defaultShadowComponent->setData(qmlCode.toUtf8(), QUrl());
186 Q_ASSERT_X(!s_defaultShadowComponent->isError(), __FUNCTION__,
187 s_defaultShadowComponent->errorString().toUtf8().constData());
188 }
189 m_shadowComponent = s_defaultShadowComponent;
190 }
191
192 QQmlContext *ctx = QQmlEngine::contextForObject(this);
193 m_shadowInstance = qobject_cast<QQuickItem*>(m_shadowComponent->beginCreate(ctx));
194 Q_ASSERT(m_shadowInstance);
195 m_shadowInstance->setParent(this);
196 m_shadowInstance->setParentItem(this);
197 m_shadowInstance->setZ(-1);
198 m_shadowInstance->setProperty("control", QVariant::fromValue(m_control.get()));
199 m_shadowInstance->setProperty("delegateStyle", QVariant::fromValue(m_delegateProperties.get()));
200 m_shadowComponent->completeCreate();
201}
202
204{
205 QQuickItem::componentComplete();
206 Q_ASSERT(m_delegateProperties);
207 Q_ASSERT(m_control);
208
209 maybeCreateDelegate();
210 connect(m_delegateProperties, &QQStyleKitDelegateProperties::delegateChanged, this, [this]{
211 if (!m_delegateInstance) {
212 maybeCreateDelegate();
213 } else {
214 const QQmlComponent *newDelegateComp = m_delegateProperties->delegate();
215 if (m_delegateComponent == newDelegateComp)
216 return;
217 if (!newDelegateComp && m_delegateComponent == s_defaultDelegateComponent) {
218 /* If newDelegateComp is nullptr, it means that we should use the default
219 * delegate instead, which we already do. */
220 return;
221 }
222
223 delete m_delegateInstance;
224 maybeCreateDelegate();
225 emit delegateInstanceChanged();
226 }
227 });
228
229 maybeCreateShadow();
230 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::delegateChanged, this, [this]{
231 if (!m_shadowInstance) {
232 maybeCreateShadow();
233 } else {
234 const QQmlComponent *newShadowComp = m_delegateProperties->shadow()->delegate();
235 if (m_shadowComponent == newShadowComp)
236 return;
237 if (!newShadowComp && m_shadowComponent == s_defaultShadowComponent) {
238 /* If newShadowComp is nullptr, it means that we should use the default
239 * delegate instead, which we already do. */
240 return;
241 }
242
243 delete m_shadowInstance;
244 maybeCreateShadow();
245 }
246 });
247}
248
249QT_END_NAMESPACE
250
251#include "moc_qqstylekitdelegatecontainer_p.cpp"
QQStyleKitDelegateProperties * delegateStyle() const
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void setDelegateStyle(QQStyleKitDelegateProperties *delegateProperties)
Combined button and popup list for selecting options.