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 qreal implicitWidth = 0;
77 qreal implicitHeight = 0;
78
79 if (m_delegateInstance) {
80 /* The delegate instance is expected to bind its implicit size to the
81 * value from the style, but may override it if needed. */
82 implicitWidth = m_delegateInstance->implicitWidth();
83 implicitHeight = m_delegateInstance->implicitHeight();
84 } else if (m_delegateProperties) {
85 /* The delegate instance may not exist yet (e.g. because it is hidden),
86 * but the container should still report the style's implicit size so
87 * that it reserves the correct space in a layout. */
88 implicitWidth = qMax(m_delegateProperties->minimumWidth(), m_delegateProperties->implicitWidth());
89 implicitHeight = m_delegateProperties->implicitHeight();
90 }
91
92 setImplicitWidth(implicitWidth);
93 setImplicitHeight(implicitHeight);
94}
95
96void QQStyleKitDelegateContainer::maybeCreateDelegate()
97{
98 if (m_delegateInstance)
99 return;
100 if (!m_delegateProperties)
101 return;
102
103 if (!m_delegateProperties->visible()) {
104 connect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
105 this, &QQStyleKitDelegateContainer::maybeCreateDelegate, Qt::UniqueConnection);
106 return;
107 }
108
109 disconnect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
110 this, &QQStyleKitDelegateContainer::maybeCreateDelegate);
111
112 const bool wasUsingDefaultDelegate = usingDefaultDelegate();
113
114 if (QQmlComponent *delegateComponent = m_delegateProperties->delegate()) {
115 m_delegateComponent = delegateComponent;
116 } else {
117 if (!s_defaultDelegateComponent || s_defaultDelegateComponent->engine() != qmlEngine(this)) {
118 delete s_defaultDelegateComponent;
119 QQmlEngine *engine = qmlEngine(this);
120 s_defaultDelegateComponent = new QQmlComponent(engine);
121 const QString qmlCode = QString::fromUtf8(R"(
122 import QtQuick
123 import Qt.labs.StyleKit
124 StyledItem {
125 width: parent.width
126 height: parent.height
127 }
128 )");
129 s_defaultDelegateComponent->setData(qmlCode.toUtf8(), QUrl());
130 Q_ASSERT_X(!s_defaultDelegateComponent->isError(), __FUNCTION__,
131 s_defaultDelegateComponent->errorString().toUtf8().constData());
132 }
133 m_delegateComponent = s_defaultDelegateComponent;
134 }
135
136 QQmlContext *ctx = QQmlEngine::contextForObject(this);
137 m_delegateInstance = qobject_cast<QQuickItem*>(m_delegateComponent->beginCreate(ctx));
138 Q_ASSERT(m_delegateInstance);
139 m_delegateInstance->setParent(this);
140 m_delegateInstance->setParentItem(this);
141 m_delegateInstance->setProperty("control", QVariant::fromValue(m_control.get()));
142 m_delegateInstance->setProperty("delegateStyle", QVariant::fromValue(m_delegateProperties.get()));
143 m_delegateComponent->completeCreate();
144
145 updateImplicitSize();
146 connect(m_delegateInstance, &QQuickItem::implicitWidthChanged, this, &QQStyleKitDelegateContainer::updateImplicitSize);
147 connect(m_delegateInstance, &QQuickItem::implicitHeightChanged, this, &QQStyleKitDelegateContainer::updateImplicitSize);
148
149 if (usingDefaultDelegate() != wasUsingDefaultDelegate)
150 emit usingDefaultDelegateChanged();
151}
152
153void QQStyleKitDelegateContainer::maybeCreateShadow()
154{
155 if (m_shadowInstance)
156 return;
157 if (!m_delegateProperties)
158 return;
159
160 if (!m_delegateProperties->visible()) {
161 connect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
162 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
163 return;
164 }
165 if (!m_delegateProperties->shadow()->visible()) {
166 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::visibleChanged,
167 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
168 return;
169 }
170 if (m_delegateProperties->shadow()->color().alpha() == 0) {
171 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::colorChanged,
172 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
173 return;
174 }
175 if (m_delegateProperties->shadow()->opacity() == 0) {
176 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::opacityChanged,
177 this, &QQStyleKitDelegateContainer::maybeCreateShadow, Qt::UniqueConnection);
178 return;
179 }
180
181 disconnect(m_delegateProperties, &QQStyleKitDelegateProperties::visibleChanged,
182 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
183 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::visibleChanged,
184 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
185 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::colorChanged,
186 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
187 disconnect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::opacityChanged,
188 this, &QQStyleKitDelegateContainer::maybeCreateShadow);
189
190 if (QQmlComponent *shadowComponent = m_delegateProperties->shadow()->delegate()) {
191 m_shadowComponent = shadowComponent;
192 } else {
193 if (!s_defaultShadowComponent || s_defaultShadowComponent->engine() != qmlEngine(this)) {
194 delete s_defaultShadowComponent;
195 QQmlEngine *engine = qmlEngine(this);
196 s_defaultShadowComponent = new QQmlComponent(engine);
197 const QString qmlCode = QString::fromUtf8(R"(
198 import Qt.labs.StyleKit.impl
199 Shadow {}
200 )");
201 s_defaultShadowComponent->setData(qmlCode.toUtf8(), QUrl());
202 Q_ASSERT_X(!s_defaultShadowComponent->isError(), __FUNCTION__,
203 s_defaultShadowComponent->errorString().toUtf8().constData());
204 }
205 m_shadowComponent = s_defaultShadowComponent;
206 }
207
208 QQmlContext *ctx = QQmlEngine::contextForObject(this);
209 m_shadowInstance = qobject_cast<QQuickItem*>(m_shadowComponent->beginCreate(ctx));
210 Q_ASSERT(m_shadowInstance);
211 m_shadowInstance->setParent(this);
212 m_shadowInstance->setParentItem(this);
213 m_shadowInstance->setZ(-1);
214 m_shadowInstance->setProperty("control", QVariant::fromValue(m_control.get()));
215 m_shadowInstance->setProperty("delegateStyle", QVariant::fromValue(m_delegateProperties.get()));
216 m_shadowComponent->completeCreate();
217}
218
220{
221 QQuickItem::componentComplete();
222 Q_ASSERT(m_delegateProperties);
223 Q_ASSERT(m_control);
224
225 maybeCreateDelegate();
226 connect(m_delegateProperties, &QQStyleKitDelegateProperties::delegateChanged, this, [this]{
227 if (!m_delegateInstance) {
228 maybeCreateDelegate();
229 } else {
230 const QQmlComponent *newDelegateComp = m_delegateProperties->delegate();
231 if (m_delegateComponent == newDelegateComp)
232 return;
233 if (!newDelegateComp && m_delegateComponent == s_defaultDelegateComponent) {
234 /* If newDelegateComp is nullptr, it means that we should use the default
235 * delegate instead, which we already do. */
236 return;
237 }
238
239 delete m_delegateInstance;
240 maybeCreateDelegate();
241 emit delegateInstanceChanged();
242 }
243 });
244
245 maybeCreateShadow();
246 connect(m_delegateProperties->shadow(), &QQStyleKitShadowProperties::delegateChanged, this, [this]{
247 if (!m_shadowInstance) {
248 maybeCreateShadow();
249 } else {
250 const QQmlComponent *newShadowComp = m_delegateProperties->shadow()->delegate();
251 if (m_shadowComponent == newShadowComp)
252 return;
253 if (!newShadowComp && m_shadowComponent == s_defaultShadowComponent) {
254 /* If newShadowComp is nullptr, it means that we should use the default
255 * delegate instead, which we already do. */
256 return;
257 }
258
259 delete m_shadowInstance;
260 maybeCreateShadow();
261 }
262 });
263
264 updateImplicitSize();
265}
266
267QT_END_NAMESPACE
268
269#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.