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 "qquickpage_p.h"
5#include "qquickpage_p_p.h"
6#include "qquicktoolbar_p.h"
7#if QT_CONFIG(quicktemplates2_container)
8#include "qquicktabbar_p.h"
9#include "qquickdialogbuttonbox_p.h"
10#endif
11
12QT_BEGIN_NAMESPACE
13
14/*!
15 \qmltype Page
16 \inherits Pane
17//! \nativetype QQuickPage
18 \inqmlmodule QtQuick.Controls
19 \since 5.7
20 \ingroup qtquickcontrols-containers
21 \ingroup qtquickcontrols-focusscopes
22 \brief Styled page control with support for a header and footer.
23
24 Page is a container control which makes it convenient to add
25 a \l header and \l footer item to a page.
26
27 \image qtquickcontrols-page-wireframe.png
28
29 Items declared as children of a Page are:
30 \list
31 \li automatically parented to the Page's contentItem. Items created
32 dynamically need to be explicitly parented to the contentItem.
33 \li not automatically positioned or resized.
34 \endlist
35
36 The following example snippet illustrates how to use a page-specific
37 toolbar header and an application-wide tabbar footer.
38
39 \qml
40 import QtQuick.Controls
41 import QtQuick.Layouts
42
43 ApplicationWindow {
44 visible: true
45
46 StackView {
47 anchors.fill: parent
48
49 initialItem: Page {
50 header: ToolBar {
51 // ...
52 }
53
54 ColumnLayout {
55 anchors.fill: parent
56 // ...
57 }
58 }
59 }
60
61 footer: TabBar {
62 // ...
63 }
64 }
65 \endqml
66
67 \sa ApplicationWindow, {Container Controls},
68 {Focus Management in Qt Quick Controls}
69*/
70
71static const QQuickItemPrivate::ChangeTypes LayoutChanges = QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed
72 | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
73
74namespace {
75 enum Position {
76 Header,
77 Footer
78 };
79
80Q_STATIC_ASSERT(int(Header) == int(QQuickToolBar::Header));
81Q_STATIC_ASSERT(int(Footer) == int(QQuickToolBar::Footer));
82
83#if QT_CONFIG(quicktemplates2_container)
84 Q_STATIC_ASSERT(int(Header) == int(QQuickTabBar::Header));
85 Q_STATIC_ASSERT(int(Footer) == int(QQuickTabBar::Footer));
86
87 Q_STATIC_ASSERT(int(Header) == int(QQuickDialogButtonBox::Header));
88 Q_STATIC_ASSERT(int(Footer) == int(QQuickDialogButtonBox::Footer));
89#endif
90
91 static void setPos(QQuickItem *item, Position position)
92 {
93 if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(object: item))
94 toolBar->setPosition(static_cast<QQuickToolBar::Position>(position));
95#if QT_CONFIG(quicktemplates2_container)
96 else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(object: item))
97 tabBar->setPosition(static_cast<QQuickTabBar::Position>(position));
98 else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object: item))
99 buttonBox->setPosition(static_cast<QQuickDialogButtonBox::Position>(position));
100#endif
101 }
102}
103
104void QQuickPagePrivate::relayout()
105{
106 Q_Q(QQuickPage);
107 const qreal hh = header && header->isVisible() ? header->height() : 0;
108 const qreal fh = footer && footer->isVisible() ? footer->height() : 0;
109 const qreal hsp = hh > 0 ? spacing : 0;
110 const qreal fsp = fh > 0 ? spacing : 0;
111
112 if (contentItem) {
113 contentItem->setY(q->topPadding() + hh + hsp);
114 contentItem->setX(q->leftPadding());
115 contentItem->setWidth(q->availableWidth());
116 contentItem->setHeight(q->availableHeight() - hh - fh - hsp - fsp);
117 }
118
119 if (header) {
120 header->setY(0);
121 header->setWidth(q->width());
122 }
123
124 if (footer) {
125 footer->setY(q->height() - footer->height());
126 footer->setWidth(q->width());
127 }
128}
129
130void QQuickPagePrivate::resizeContent()
131{
132 relayout();
133}
134
135void QQuickPagePrivate::itemVisibilityChanged(QQuickItem *item)
136{
137 Q_Q(QQuickPage);
138 QQuickPanePrivate::itemVisibilityChanged(item);
139 if (item == header) {
140 QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals);
141 emit q->implicitHeaderWidthChanged();
142 emit q->implicitHeaderHeightChanged();
143 relayout();
144 } else if (item == footer) {
145 QBoolBlocker signalGuard(emittingImplicitSizeChangedSignals);
146 emit q->implicitFooterWidthChanged();
147 emit q->implicitFooterHeightChanged();
148 relayout();
149 }
150}
151
152void QQuickPagePrivate::itemImplicitWidthChanged(QQuickItem *item)
153{
154 Q_Q(QQuickPage);
155 QQuickPanePrivate::itemImplicitWidthChanged(item);
156
157 // Avoid binding loops by skipping signal emission if we're already doing it.
158 if (emittingImplicitSizeChangedSignals)
159 return;
160
161 if (item == header)
162 emit q->implicitHeaderWidthChanged();
163 else if (item == footer)
164 emit q->implicitFooterWidthChanged();
165}
166
167void QQuickPagePrivate::itemImplicitHeightChanged(QQuickItem *item)
168{
169 Q_Q(QQuickPage);
170 QQuickPanePrivate::itemImplicitHeightChanged(item);
171
172 // Avoid binding loops by skipping signal emission if we're already doing it.
173 if (emittingImplicitSizeChangedSignals)
174 return;
175
176 if (item == header)
177 emit q->implicitHeaderHeightChanged();
178 else if (item == footer)
179 emit q->implicitFooterHeightChanged();
180}
181
182void QQuickPagePrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF & diff)
183{
184 QQuickPanePrivate::itemGeometryChanged(item, change, diff);
185 if (item == header || item == footer)
186 relayout();
187}
188
189void QQuickPagePrivate::itemDestroyed(QQuickItem *item)
190{
191 Q_Q(QQuickPage);
192 QQuickPanePrivate::itemDestroyed(item);
193 if (item == header) {
194 header = nullptr;
195 relayout();
196 emit q->implicitHeaderWidthChanged();
197 emit q->implicitHeaderHeightChanged();
198 emit q->headerChanged();
199 } else if (item == footer) {
200 footer = nullptr;
201 relayout();
202 emit q->implicitFooterWidthChanged();
203 emit q->implicitFooterHeightChanged();
204 emit q->footerChanged();
205 }
206}
207
208QQuickPage::QQuickPage(QQuickItem *parent)
209 : QQuickPane(*(new QQuickPagePrivate), parent)
210{
211}
212
213QQuickPage::QQuickPage(QQuickPagePrivate &dd, QQuickItem *parent)
214 : QQuickPane(dd, parent)
215{
216}
217
218QQuickPage::~QQuickPage()
219{
220 Q_D(QQuickPage);
221 if (d->header)
222 QQuickItemPrivate::get(item: d->header)->removeItemChangeListener(d, types: LayoutChanges);
223 if (d->footer)
224 QQuickItemPrivate::get(item: d->footer)->removeItemChangeListener(d, types: LayoutChanges);
225}
226
227/*!
228 \qmlproperty string QtQuick.Controls::Page::title
229
230 This property holds the page title.
231
232 The title is often displayed at the top of a page to give
233 the user context about the page they are viewing.
234
235 Page does not render the title itself, but instead relies
236 on the application to do so. For example:
237
238 \code
239 ApplicationWindow {
240 visible: true
241 width: 400
242 height: 400
243
244 header: Label {
245 text: view.currentItem.title
246 horizontalAlignment: Text.AlignHCenter
247 }
248
249 SwipeView {
250 id: view
251 anchors.fill: parent
252
253 Page {
254 title: qsTr("Home")
255 }
256 Page {
257 title: qsTr("Discover")
258 }
259 Page {
260 title: qsTr("Activity")
261 }
262 }
263 }
264 \endcode
265*/
266
267QString QQuickPage::title() const
268{
269 return d_func()->title;
270}
271
272void QQuickPage::setTitle(const QString &title)
273{
274 Q_D(QQuickPage);
275 if (d->title == title)
276 return;
277
278 d->title = title;
279 maybeSetAccessibleName(name: title);
280 emit titleChanged();
281}
282
283void QQuickPage::resetTitle()
284{
285 setTitle(QString());
286}
287
288/*!
289 \qmlproperty Item QtQuick.Controls::Page::header
290
291 This property holds the page header item. The header item is positioned to
292 the top, and resized to the width of the page. The default value is \c null.
293
294 \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page header
295 automatically sets the respective \l ToolBar::position, \l TabBar::position,
296 or \l DialogButtonBox::position property to \c Header.
297
298 \sa footer, ApplicationWindow::header
299*/
300QQuickItem *QQuickPage::header() const
301{
302 Q_D(const QQuickPage);
303 return d->header;
304}
305
306void QQuickPage::setHeader(QQuickItem *header)
307{
308 Q_D(QQuickPage);
309 if (d->header == header)
310 return;
311
312 if (d->header) {
313 QQuickItemPrivate::get(item: d->header)->removeItemChangeListener(d, types: LayoutChanges);
314 d->header->setParentItem(nullptr);
315 }
316 d->header = header;
317 if (header) {
318 header->setParentItem(this);
319 QQuickItemPrivate::get(item: header)->addItemChangeListener(listener: d, types: LayoutChanges);
320 if (qFuzzyIsNull(d: header->z()))
321 header->setZ(1);
322 setPos(item: header, position: Header);
323 }
324 if (isComponentComplete())
325 d->relayout();
326 emit headerChanged();
327}
328
329/*!
330 \qmlproperty Item QtQuick.Controls::Page::footer
331
332 This property holds the page footer item. The footer item is positioned to
333 the bottom, and resized to the width of the page. The default value is \c null.
334
335 \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page footer
336 automatically sets the respective \l ToolBar::position, \l TabBar::position,
337 or \l DialogButtonBox::position property to \c Footer.
338
339 \sa header, ApplicationWindow::footer
340*/
341QQuickItem *QQuickPage::footer() const
342{
343 Q_D(const QQuickPage);
344 return d->footer;
345}
346
347void QQuickPage::setFooter(QQuickItem *footer)
348{
349 Q_D(QQuickPage);
350 if (d->footer == footer)
351 return;
352
353 if (d->footer) {
354 QQuickItemPrivate::get(item: d->footer)->removeItemChangeListener(d, types: LayoutChanges);
355 d->footer->setParentItem(nullptr);
356 }
357 d->footer = footer;
358 if (footer) {
359 footer->setParentItem(this);
360 QQuickItemPrivate::get(item: footer)->addItemChangeListener(listener: d, types: LayoutChanges);
361 if (qFuzzyIsNull(d: footer->z()))
362 footer->setZ(1);
363 setPos(item: footer, position: Footer);
364 }
365 if (isComponentComplete())
366 d->relayout();
367 emit footerChanged();
368}
369
370/*!
371 \since QtQuick.Controls 2.5 (Qt 5.12)
372 \qmlproperty real QtQuick.Controls::Page::implicitHeaderWidth
373 \readonly
374
375 This property holds the implicit header width.
376
377 The value is equal to \c {header && header.visible ? header.implicitWidth : 0}.
378
379 \sa implicitHeaderHeight, implicitFooterWidth
380*/
381qreal QQuickPage::implicitHeaderWidth() const
382{
383 Q_D(const QQuickPage);
384 if (!d->header || !d->header->isVisible())
385 return 0;
386 return d->header->implicitWidth();
387}
388
389/*!
390 \since QtQuick.Controls 2.5 (Qt 5.12)
391 \qmlproperty real QtQuick.Controls::Page::implicitHeaderHeight
392 \readonly
393
394 This property holds the implicit header height.
395
396 The value is equal to \c {header && header.visible ? header.implicitHeight : 0}.
397
398 \sa implicitHeaderWidth, implicitFooterHeight
399*/
400qreal QQuickPage::implicitHeaderHeight() const
401{
402 Q_D(const QQuickPage);
403 if (!d->header || !d->header->isVisible())
404 return 0;
405 return d->header->implicitHeight();
406}
407
408/*!
409 \since QtQuick.Controls 2.5 (Qt 5.12)
410 \qmlproperty real QtQuick.Controls::Page::implicitFooterWidth
411 \readonly
412
413 This property holds the implicit footer width.
414
415 The value is equal to \c {footer && footer.visible ? footer.implicitWidth : 0}.
416
417 \sa implicitFooterHeight, implicitHeaderWidth
418*/
419qreal QQuickPage::implicitFooterWidth() const
420{
421 Q_D(const QQuickPage);
422 if (!d->footer || !d->footer->isVisible())
423 return 0;
424 return d->footer->implicitWidth();
425}
426
427/*!
428 \since QtQuick.Controls 2.5 (Qt 5.12)
429 \qmlproperty real QtQuick.Controls::Page::implicitFooterHeight
430 \readonly
431
432 This property holds the implicit footer height.
433
434 The value is equal to \c {footer && footer.visible ? footer.implicitHeight : 0}.
435
436 \sa implicitFooterWidth, implicitHeaderHeight
437*/
438qreal QQuickPage::implicitFooterHeight() const
439{
440 Q_D(const QQuickPage);
441 if (!d->footer || !d->footer->isVisible())
442 return 0;
443 return d->footer->implicitHeight();
444}
445
446void QQuickPage::componentComplete()
447{
448 Q_D(QQuickPage);
449 QQuickPane::componentComplete();
450 d->relayout();
451}
452
453void QQuickPage::spacingChange(qreal newSpacing, qreal oldSpacing)
454{
455 Q_D(QQuickPage);
456 QQuickPane::spacingChange(newSpacing, oldSpacing);
457 d->relayout();
458}
459
460#if QT_CONFIG(accessibility)
461QAccessible::Role QQuickPage::accessibleRole() const
462{
463 return QAccessible::PageTab;
464}
465
466void QQuickPage::accessibilityActiveChanged(bool active)
467{
468 Q_D(QQuickPage);
469 QQuickPane::accessibilityActiveChanged(active);
470
471 if (active)
472 maybeSetAccessibleName(name: d->title);
473}
474#endif
475
476QT_END_NAMESPACE
477
478#include "moc_qquickpage_p.cpp"
479

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

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