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