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