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
qquickpane.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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// Qt-Security score:significant reason:default
4
5#include "qquickpane_p.h"
8
9#include <QtCore/qloggingcategory.h>
10
12
13Q_STATIC_LOGGING_CATEGORY(lcPane, "qt.quick.controls.pane")
14
15/*!
16 \qmltype Pane
17 \inherits Control
18//! \nativetype QQuickPane
19 \inqmlmodule QtQuick.Controls
20 \since 5.7
21 \ingroup qtquickcontrols-containers
22 \ingroup qtquickcontrols-focusscopes
23 \brief Provides a background matching with the application style and theme.
24
25 Pane provides a background color that matches with the application style
26 and theme. Pane does not provide a layout of its own, but requires you to
27 position its contents, for instance by creating a \l RowLayout or a
28 \l ColumnLayout.
29
30 Items declared as children of a Pane are automatically parented to the
31 Pane's \l[QtQuickControls2]{Control::}{contentItem}. Items created
32 dynamically need to be explicitly parented to the \c contentItem.
33
34 As mentioned in \l {Event Handling}, Pane does not let click and touch
35 events through to items beneath it. If \l [QML] {Control::}{wheelEnabled}
36 is \c true, the same applies to mouse wheel events.
37
38 \section1 Content Sizing
39
40 If only a single item is used within a Pane, it will resize to fit the
41 implicit size of its contained item. This makes it particularly suitable
42 for use together with layouts.
43
44 \image qtquickcontrols-pane.png
45
46 \snippet qtquickcontrols-pane.qml 1
47
48 Sometimes there might be two items within the pane:
49
50 \code
51 Pane {
52 SwipeView {
53 // ...
54 }
55 PageIndicator {
56 anchors.horizontalCenter: parent.horizontalCenter
57 anchors.bottom: parent.bottom
58 }
59 }
60 \endcode
61
62 In this case, Pane cannot calculate a sensible implicit size. Since we're
63 anchoring the \l PageIndicator over the \l SwipeView, we can simply set the
64 content size to the view's implicit size:
65
66 \code
67 Pane {
68 contentWidth: view.implicitWidth
69 contentHeight: view.implicitHeight
70
71 SwipeView {
72 id: view
73 // ...
74 }
75 PageIndicator {
76 anchors.horizontalCenter: parent.horizontalCenter
77 anchors.bottom: parent.bottom
78 }
79 }
80 \endcode
81
82 If the \l[QtQuickControls2]{Control::}{contentItem} has no implicit size
83 and only one child, Pane will use the implicit size of that child. For
84 example, in the following code, the Pane assumes the size of the Rectangle:
85
86 \code
87 Pane {
88 Item {
89 Rectangle {
90 implicitWidth: 200
91 implicitHeight: 200
92 color: "salmon"
93 }
94 }
95 }
96 \endcode
97
98 \sa {Customizing Pane}, {Container Controls},
99 {Focus Management in Qt Quick Controls}, {Event Handling}
100*/
101
102void QQuickPanePrivate::init()
103{
104 Q_Q(QQuickPane);
105 q->setFlag(QQuickItem::ItemIsFocusScope);
106 q->setAcceptedMouseButtons(Qt::AllButtons);
107#if QT_CONFIG(cursor)
108 q->setCursor(Qt::ArrowCursor);
109#endif
110 connect(q, &QQuickControl::implicitContentWidthChanged, this, &QQuickPanePrivate::updateContentWidth);
111 connect(q, &QQuickControl::implicitContentHeightChanged, this, &QQuickPanePrivate::updateContentHeight);
112 setSizePolicy(QLayoutPolicy::Preferred, QLayoutPolicy::Preferred);
113}
114
115QList<QQuickItem *> QQuickPanePrivate::contentChildItems() const
116{
117 if (!contentItem)
118 return QList<QQuickItem *>();
119
120 return contentItem->childItems();
121}
122
123QQuickItem *QQuickPanePrivate::getContentItem()
124{
125 Q_Q(QQuickPane);
126 if (QQuickItem *item = QQuickControlPrivate::getContentItem())
127 return item;
128
129 return new QQuickContentItem(q);
130}
131
132void QQuickPanePrivate::itemImplicitWidthChanged(QQuickItem *item)
133{
134 QQuickControlPrivate::itemImplicitWidthChanged(item);
135
136 if (item == firstChild)
137 updateImplicitContentWidth();
138}
139
140void QQuickPanePrivate::itemImplicitHeightChanged(QQuickItem *item)
141{
142 QQuickControlPrivate::itemImplicitHeightChanged(item);
143
144 if (item == firstChild)
145 updateImplicitContentHeight();
146}
147
148void QQuickPanePrivate::itemDestroyed(QQuickItem *item)
149{
150 // Do this check before calling the base class implementation, as that clears contentItem.
151 if (item == firstChild)
152 firstChild = nullptr;
153
154 QQuickControlPrivate::itemDestroyed(item);
155}
156
157void QQuickPanePrivate::contentChildrenChange()
158{
159 Q_Q(QQuickPane);
160
161 QQuickItem *newFirstChild = getFirstChild();
162
163 if (newFirstChild != firstChild) {
164 if (firstChild)
165 removeImplicitSizeListener(firstChild);
166 if (newFirstChild && newFirstChild != contentItem)
167 addImplicitSizeListener(newFirstChild);
168 firstChild = newFirstChild;
169 }
170
171 updateImplicitContentSize();
172 emit q->contentChildrenChanged();
173}
174
175qreal QQuickPanePrivate::getContentWidth() const
176{
177 if (!contentItem)
178 return 0;
179
180 if (hasContentWidth)
181 return contentWidth;
182
183 const qreal cw = contentItem->implicitWidth();
184 if (!qFuzzyIsNull(cw))
185 return cw;
186
187 const auto contentChildren = contentChildItems();
188 if (contentChildren.size() == 1)
189 return contentChildren.first()->implicitWidth();
190
191 return 0;
192}
193
194QQuickItem* QQuickPanePrivate::getFirstChild() const
195{
196 // The first child varies depending on how the content item is declared.
197 // If it's declared as a child of the Pane, it will be parented to the
198 // default QQuickContentItem. If it's assigned to the contentItem property
199 // directly, QQuickControl::contentItem will be used.
200 return (qobject_cast<QQuickContentItem *>(contentItem)
201 ? contentChildItems().value(0) : contentItem.data());
202}
203
204qreal QQuickPanePrivate::getContentHeight() const
205{
206 if (!contentItem)
207 return 0;
208
209 if (hasContentHeight)
210 return contentHeight;
211
212 const qreal ch = contentItem->implicitHeight();
213 if (!qFuzzyIsNull(ch))
214 return ch;
215
216 const auto contentChildren = contentChildItems();
217 if (contentChildren.size() == 1)
218 return contentChildren.first()->implicitHeight();
219
220 return 0;
221}
222
223void QQuickPanePrivate::updateContentWidth()
224{
225 Q_Q(QQuickPane);
226 if (hasContentWidth || qFuzzyCompare(contentWidth, implicitContentWidth))
227 return;
228
229 const qreal oldContentWidth = contentWidth;
230 contentWidth = implicitContentWidth;
231 qCDebug(lcPane) << "contentWidth of" << q << "changed to" << contentWidth;
232 q->contentSizeChange(QSizeF(contentWidth, contentHeight), QSizeF(oldContentWidth, contentHeight));
233 emit q->contentWidthChanged();
234}
235
236void QQuickPanePrivate::updateContentHeight()
237{
238 Q_Q(QQuickPane);
239 if (hasContentHeight || qFuzzyCompare(contentHeight, implicitContentHeight))
240 return;
241
242 const qreal oldContentHeight = contentHeight;
243 contentHeight = implicitContentHeight;
244 qCDebug(lcPane) << "contentHeight of" << q << "changed to" << contentHeight;
245 q->contentSizeChange(QSizeF(contentWidth, contentHeight), QSizeF(contentWidth, oldContentHeight));
246 emit q->contentHeightChanged();
247}
248
249/*
250 A pane needs to be opaque to mouse events, so that events don't get
251 propagated through to controls covered by the pane.
252*/
253bool QQuickPanePrivate::handlePress(const QPointF &point, ulong timestamp)
254{
255 QQuickControlPrivate::handlePress(point, timestamp);
256 return true;
257}
258
259QQuickPane::QQuickPane(QQuickItem *parent)
260 : QQuickControl(*(new QQuickPanePrivate), parent)
261{
262 Q_D(QQuickPane);
263 d->init();
264}
265
266QQuickPane::~QQuickPane()
267{
268 Q_D(QQuickPane);
269 if (d->contentItem) {
270 // It's possible for the focus frame to be removed as a child of our contentItem
271 // upon our destruction, so disconnect to avoid getting our slot getting called during this.
272 QObjectPrivate::disconnect(d->contentItem, &QQuickItem::childrenChanged,
273 d, &QQuickPanePrivate::contentChildrenChange);
274 }
275 d->removeImplicitSizeListener(d->contentItem);
276 d->removeImplicitSizeListener(d->firstChild);
277}
278
279QQuickPane::QQuickPane(QQuickPanePrivate &dd, QQuickItem *parent)
280 : QQuickControl(dd, parent)
281{
282 Q_D(QQuickPane);
283 d->init();
284}
285
286/*!
287 \qmlproperty real QtQuick.Controls::Pane::contentWidth
288
289 This property holds the content width. It is used for calculating the total
290 implicit width of the pane.
291
292 For more information, see \l {Content Sizing}.
293
294 \sa contentHeight
295*/
296qreal QQuickPane::contentWidth() const
297{
298 Q_D(const QQuickPane);
299 return d->contentWidth;
300}
301
302void QQuickPane::setContentWidth(qreal width)
303{
304 Q_D(QQuickPane);
305 d->hasContentWidth = true;
306 if (qFuzzyCompare(d->contentWidth, width))
307 return;
308
309 const qreal oldWidth = d->contentWidth;
310 d->contentWidth = width;
311 contentSizeChange(QSizeF(width, d->contentHeight), QSizeF(oldWidth, d->contentHeight));
312 emit contentWidthChanged();
313}
314
315void QQuickPane::resetContentWidth()
316{
317 Q_D(QQuickPane);
318 if (!d->hasContentWidth)
319 return;
320
321 d->hasContentWidth = false;
322 d->updateImplicitContentWidth();
323}
324
325/*!
326 \qmlproperty real QtQuick.Controls::Pane::contentHeight
327
328 This property holds the content height. It is used for calculating the total
329 implicit height of the pane.
330
331 For more information, see \l {Content Sizing}.
332
333 \sa contentWidth
334*/
335qreal QQuickPane::contentHeight() const
336{
337 Q_D(const QQuickPane);
338 return d->contentHeight;
339}
340
341void QQuickPane::setContentHeight(qreal height)
342{
343 Q_D(QQuickPane);
344 d->hasContentHeight = true;
345 if (qFuzzyCompare(d->contentHeight, height))
346 return;
347
348 const qreal oldHeight = d->contentHeight;
349 d->contentHeight = height;
350 contentSizeChange(QSizeF(d->contentWidth, height), QSizeF(d->contentWidth, oldHeight));
351 emit contentHeightChanged();
352}
353
354void QQuickPane::resetContentHeight()
355{
356 Q_D(QQuickPane);
357 if (!d->hasContentHeight)
358 return;
359
360 d->hasContentHeight = false;
361 d->updateImplicitContentHeight();
362}
363
364/*!
365 \qmlproperty list<QtObject> QtQuick.Controls::Pane::contentData
366 \qmldefault
367
368 This property holds the list of content data.
369
370 The list contains all objects that have been declared in QML as children
371 of the pane.
372
373 \note Unlike \c contentChildren, \c contentData does include non-visual QML
374 objects.
375
376 \sa Item::data, contentChildren
377*/
378QQmlListProperty<QObject> QQuickPanePrivate::contentData()
379{
380 Q_Q(QQuickPane);
381 return QQmlListProperty<QObject>(q->contentItem(), nullptr,
382 QQuickItemPrivate::data_append,
383 QQuickItemPrivate::data_count,
384 QQuickItemPrivate::data_at,
385 QQuickItemPrivate::data_clear);
386}
387
388/*!
389 \qmlproperty list<Item> QtQuick.Controls::Pane::contentChildren
390
391 This property holds the list of content children.
392
393 The list contains all items that have been declared in QML as children
394 of the pane.
395
396 \note Unlike \c contentData, \c contentChildren does not include non-visual
397 QML objects.
398
399 \sa Item::children, contentData
400*/
401QQmlListProperty<QQuickItem> QQuickPanePrivate::contentChildren()
402{
403 Q_Q(QQuickPane);
404 return QQmlListProperty<QQuickItem>(q->contentItem(), nullptr,
405 QQuickItemPrivate::children_append,
406 QQuickItemPrivate::children_count,
407 QQuickItemPrivate::children_at,
408 QQuickItemPrivate::children_clear);
409}
410
411void QQuickPane::componentComplete()
412{
413 Q_D(QQuickPane);
414 QQuickControl::componentComplete();
415 d->updateImplicitContentSize();
416}
417
418void QQuickPane::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
419{
420 Q_D(QQuickPane);
421 QQuickControl::contentItemChange(newItem, oldItem);
422 if (oldItem) {
423 d->removeImplicitSizeListener(oldItem);
424 QObjectPrivate::disconnect(oldItem, &QQuickItem::childrenChanged, d, &QQuickPanePrivate::contentChildrenChange);
425 }
426 if (newItem) {
427 d->addImplicitSizeListener(newItem);
428 QObjectPrivate::connect(newItem, &QQuickItem::childrenChanged, d, &QQuickPanePrivate::contentChildrenChange);
429 }
430 d->contentChildrenChange();
431}
432
433void QQuickPane::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
434{
435 Q_UNUSED(newSize);
436 Q_UNUSED(oldSize);
437
438 Q_D(QQuickPane);
439 if (d->hasContentWidth)
440 d->updateImplicitContentWidth();
441 if (d->hasContentHeight)
442 d->updateImplicitContentHeight();
443}
444
445#if QT_CONFIG(accessibility)
446QAccessible::Role QQuickPane::accessibleRole() const
447{
448 return QAccessible::Pane;
449}
450#endif
451
452QT_END_NAMESPACE
453
454#include "moc_qquickpane_p.cpp"