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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | Q_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 | |
101 | void 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 | |
114 | QList<QQuickItem *> QQuickPanePrivate::contentChildItems() const |
115 | { |
116 | if (!contentItem) |
117 | return QList<QQuickItem *>(); |
118 | |
119 | return contentItem->childItems(); |
120 | } |
121 | |
122 | QQuickItem *QQuickPanePrivate::getContentItem() |
123 | { |
124 | Q_Q(QQuickPane); |
125 | if (QQuickItem *item = QQuickControlPrivate::getContentItem()) |
126 | return item; |
127 | |
128 | return new QQuickContentItem(q); |
129 | } |
130 | |
131 | void QQuickPanePrivate::itemImplicitWidthChanged(QQuickItem *item) |
132 | { |
133 | QQuickControlPrivate::itemImplicitWidthChanged(item); |
134 | |
135 | if (item == firstChild) |
136 | updateImplicitContentWidth(); |
137 | } |
138 | |
139 | void QQuickPanePrivate::itemImplicitHeightChanged(QQuickItem *item) |
140 | { |
141 | QQuickControlPrivate::itemImplicitHeightChanged(item); |
142 | |
143 | if (item == firstChild) |
144 | updateImplicitContentHeight(); |
145 | } |
146 | |
147 | void 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 | |
156 | void 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 | |
174 | qreal 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 | |
190 | QQuickItem* 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 | |
200 | qreal 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 | |
216 | void 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 | |
229 | void 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 | */ |
246 | bool QQuickPanePrivate::handlePress(const QPointF &point, ulong timestamp) |
247 | { |
248 | QQuickControlPrivate::handlePress(point, timestamp); |
249 | return true; |
250 | } |
251 | |
252 | QQuickPane::QQuickPane(QQuickItem *parent) |
253 | : QQuickControl(*(new QQuickPanePrivate), parent) |
254 | { |
255 | Q_D(QQuickPane); |
256 | d->init(); |
257 | } |
258 | |
259 | QQuickPane::~QQuickPane() |
260 | { |
261 | Q_D(QQuickPane); |
262 | d->removeImplicitSizeListener(item: d->contentItem); |
263 | d->removeImplicitSizeListener(item: d->firstChild); |
264 | } |
265 | |
266 | QQuickPane::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 | */ |
283 | qreal QQuickPane::contentWidth() const |
284 | { |
285 | Q_D(const QQuickPane); |
286 | return d->contentWidth; |
287 | } |
288 | |
289 | void 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 | |
302 | void 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 | */ |
322 | qreal QQuickPane::contentHeight() const |
323 | { |
324 | Q_D(const QQuickPane); |
325 | return d->contentHeight; |
326 | } |
327 | |
328 | void 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 | |
341 | void 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 | */ |
365 | QQmlListProperty<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 | */ |
388 | QQmlListProperty<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 | |
398 | void QQuickPane::componentComplete() |
399 | { |
400 | Q_D(QQuickPane); |
401 | QQuickControl::componentComplete(); |
402 | d->updateImplicitContentSize(); |
403 | } |
404 | |
405 | void 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 | |
420 | void QQuickPane::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) |
421 | { |
422 | Q_UNUSED(newSize); |
423 | Q_UNUSED(oldSize); |
424 | } |
425 | |
426 | #if QT_CONFIG(accessibility) |
427 | QAccessible::Role QQuickPane::accessibleRole() const |
428 | { |
429 | return QAccessible::Pane; |
430 | } |
431 | #endif |
432 | |
433 | QT_END_NAMESPACE |
434 | |
435 | #include "moc_qquickpane_p.cpp" |
436 |
Definitions
- lcPane
- init
- contentChildItems
- getContentItem
- itemImplicitWidthChanged
- itemImplicitHeightChanged
- itemDestroyed
- contentChildrenChange
- getContentWidth
- getFirstChild
- getContentHeight
- updateContentWidth
- updateContentHeight
- handlePress
- QQuickPane
- ~QQuickPane
- QQuickPane
- contentWidth
- setContentWidth
- resetContentWidth
- contentHeight
- setContentHeight
- resetContentHeight
- contentData
- contentChildren
- componentComplete
- contentItemChange
- contentSizeChange
Start learning QML with our Intro Training
Find out more