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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/quicktemplates/qquickpane.cpp