aboutsummaryrefslogtreecommitdiffstats
path: root/src/imports/layouts
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2019-12-09 15:13:33 +0100
committerMitch Curtis <mitch.curtis@qt.io>2020-03-23 14:01:16 +0100
commit619dfbe8d02347cedb93a949cde627ec4424e0ae (patch)
tree670edc69d8c746fc5c3d73a7eccc0a84a7ea27d4 /src/imports/layouts
parentb9c7f8989b979374ab0528827d69050415a424e0 (diff)
StackLayout: add attached index, isCurrentItem, and layout properties
These properties are useful for items within StackLayout to get access to their index within it, especially when those items are declared in their own QML files. Similar API already exists for e.g. ListView and SwipeView. [ChangeLog][StackLayout] Added attached index, isCurrentItem, and layout properties. Change-Id: I648d4434ab21573b56edd9a0f8399463946fd571 Fixes: QTBUG-76999 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/imports/layouts')
-rw-r--r--src/imports/layouts/qquickstacklayout.cpp177
-rw-r--r--src/imports/layouts/qquickstacklayout_p.h37
2 files changed, 199 insertions, 15 deletions
diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp
index 4c1d611409..37fa4c999f 100644
--- a/src/imports/layouts/qquickstacklayout.cpp
+++ b/src/imports/layouts/qquickstacklayout.cpp
@@ -38,8 +38,11 @@
****************************************************************************/
#include "qquickstacklayout_p.h"
+
#include <limits>
+#include <QtQml/qqmlinfo.h>
+
/*!
\qmltype StackLayout
\instantiates QQuickStackLayout
@@ -99,6 +102,12 @@
QT_BEGIN_NAMESPACE
+static QQuickStackLayoutAttached *attachedStackLayoutObject(QQuickItem *item, bool create = false)
+{
+ return static_cast<QQuickStackLayoutAttached*>(
+ qmlAttachedPropertiesObject<QQuickStackLayout>(item, create));
+}
+
QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) :
QQuickLayout(*new QQuickStackLayoutPrivate, parent)
{
@@ -132,20 +141,34 @@ int QQuickStackLayout::currentIndex() const
void QQuickStackLayout::setCurrentIndex(int index)
{
Q_D(QQuickStackLayout);
- if (index != d->currentIndex) {
- QQuickItem *prev = itemAt(d->currentIndex);
- QQuickItem *next = itemAt(index);
- d->currentIndex = index;
- d->explicitCurrentIndex = true;
- if (prev)
- prev->setVisible(false);
- if (next)
- next->setVisible(true);
-
- if (isComponentComplete()) {
- rearrange(QSizeF(width(), height()));
- emit currentIndexChanged();
- }
+ if (index == d->currentIndex)
+ return;
+
+ QQuickItem *prev = itemAt(d->currentIndex);
+ QQuickItem *next = itemAt(index);
+ d->currentIndex = index;
+ d->explicitCurrentIndex = true;
+ if (prev)
+ prev->setVisible(false);
+ if (next)
+ next->setVisible(true);
+
+ if (isComponentComplete()) {
+ rearrange(QSizeF(width(), height()));
+ emit currentIndexChanged();
+ }
+
+ // Update attached properties after emitting currentIndexChanged()
+ // to maintain a more sensible emission order.
+ if (prev) {
+ auto stackLayoutAttached = attachedStackLayoutObject(prev);
+ if (stackLayoutAttached)
+ stackLayoutAttached->setIsCurrentItem(false);
+ }
+ if (next) {
+ auto stackLayoutAttached = attachedStackLayoutObject(next);
+ if (stackLayoutAttached)
+ stackLayoutAttached->setIsCurrentItem(true);
}
}
@@ -162,6 +185,21 @@ void QQuickStackLayout::componentComplete()
rearrange(QSizeF(width(), height()));
}
+void QQuickStackLayout::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
+{
+ QQuickLayout::itemChange(change, value);
+
+ if (change == ItemChildRemovedChange) {
+ QQuickItem *item = value.item;
+ auto stackLayoutAttached = attachedStackLayoutObject(item);
+ if (stackLayoutAttached) {
+ stackLayoutAttached->setLayout(nullptr);
+ stackLayoutAttached->setIndex(-1);
+ stackLayoutAttached->setIsCurrentItem(false);
+ }
+ }
+}
+
QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const
{
QSizeF &askingFor = m_cachedSizeHints[whichSizeHint];
@@ -205,6 +243,11 @@ int QQuickStackLayout::indexOf(QQuickItem *childItem) const
return -1;
}
+QQuickStackLayoutAttached *QQuickStackLayout::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickStackLayoutAttached(object);
+}
+
QQuickItem *QQuickStackLayout::itemAt(int index) const
{
const auto items = childItems();
@@ -294,6 +337,13 @@ void QQuickStackLayout::updateLayoutItems()
QQuickItem *child = itemAt(i);
checkAnchors(child);
child->setVisible(d->currentIndex == i);
+
+ auto stackLayoutAttached = attachedStackLayoutObject(child);
+ if (stackLayoutAttached) {
+ stackLayoutAttached->setLayout(this);
+ stackLayoutAttached->setIndex(i);
+ stackLayoutAttached->setIsCurrentItem(d->currentIndex == i);
+ }
}
invalidate();
@@ -347,6 +397,105 @@ bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const
return ignored;
}
+QQuickStackLayoutAttached::QQuickStackLayoutAttached(QObject *object)
+{
+ auto item = qobject_cast<QQuickItem*>(object);
+ if (!item) {
+ qmlWarning(object) << "StackLayout must be attached to an Item";
+ return;
+ }
+
+ auto stackLayout = qobject_cast<QQuickStackLayout*>(item->parentItem());
+ if (!stackLayout) {
+ // It might not be a child of a StackLayout yet, and that's OK.
+ // The index will get set by updateLayoutItems() when it's reparented.
+ return;
+ }
+
+ if (!stackLayout->isComponentComplete()) {
+ // Don't try to get the index if the StackLayout itself hasn't loaded yet.
+ return;
+ }
+
+ // If we got this far, the item was added as a child to the StackLayout after it loaded.
+ const int index = stackLayout->indexOf(item);
+ setLayout(stackLayout);
+ setIndex(index);
+ setIsCurrentItem(stackLayout->currentIndex() == index);
+}
+
+/*!
+ \qmlattachedproperty int StackLayout::index
+
+ This attached property holds the index of each child item in the
+ \l StackLayout.
+
+ \sa isCurrentItem, layout
+
+ \since QtQuick.Layouts 1.15
+*/
+int QQuickStackLayoutAttached::index() const
+{
+ return m_index;
+}
+
+void QQuickStackLayoutAttached::setIndex(int index)
+{
+ if (index == m_index)
+ return;
+
+ m_index = index;
+ emit indexChanged();
+}
+
+/*!
+ \qmlattachedproperty bool StackLayout::isCurrentItem
+
+ This attached property is \c true if this child is the current item
+ in the \l StackLayout.
+
+ \sa index, layout
+
+ \since QtQuick.Layouts 1.15
+*/
+bool QQuickStackLayoutAttached::isCurrentItem() const
+{
+ return m_isCurrentItem;
+}
+
+void QQuickStackLayoutAttached::setIsCurrentItem(bool isCurrentItem)
+{
+ if (isCurrentItem == m_isCurrentItem)
+ return;
+
+ m_isCurrentItem = isCurrentItem;
+ emit isCurrentItemChanged();
+}
+
+/*!
+ \qmlattachedproperty StackLayout StackLayout::layout
+
+ This attached property holds the \l StackLayout that manages this child
+ item.
+
+ \sa index, isCurrentItem
+
+ \since QtQuick.Layouts 1.15
+*/
+QQuickStackLayout *QQuickStackLayoutAttached::layout() const
+{
+ return m_layout;
+}
+
+void QQuickStackLayoutAttached::setLayout(QQuickStackLayout *layout)
+{
+ if (layout == m_layout)
+ return;
+
+ m_layout = layout;
+ emit layoutChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickstacklayout_p.cpp"
diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h
index 07f9e48178..b641376ed8 100644
--- a/src/imports/layouts/qquickstacklayout_p.h
+++ b/src/imports/layouts/qquickstacklayout_p.h
@@ -45,6 +45,7 @@
QT_BEGIN_NAMESPACE
class QQuickStackLayoutPrivate;
+class QQuickStackLayoutAttached;
class QQuickStackLayout : public QQuickLayout
{
@@ -53,6 +54,7 @@ class QQuickStackLayout : public QQuickLayout
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged)
QML_NAMED_ELEMENT(StackLayout)
QML_ADDED_IN_VERSION(1, 3)
+ QML_ATTACHED(QQuickStackLayoutAttached)
public:
explicit QQuickStackLayout(QQuickItem *parent = 0);
@@ -61,6 +63,7 @@ public:
void setCurrentIndex(int index);
void componentComplete() override;
+ void itemChange(ItemChange change, const ItemChangeData &value) override;
QSizeF sizeHint(Qt::SizeHint whichSizeHint) const override;
void setAlignment(QQuickItem *item, Qt::Alignment align) override;
void invalidate(QQuickItem *childItem = 0) override;
@@ -72,7 +75,7 @@ public:
int itemCount() const override;
int indexOf(QQuickItem *item) const;
-
+ static QQuickStackLayoutAttached *qmlAttachedProperties(QObject *object);
signals:
void currentIndexChanged();
@@ -85,6 +88,8 @@ private:
bool shouldIgnoreItem(QQuickItem *item) const;
Q_DECLARE_PRIVATE(QQuickStackLayout)
+ friend class QQuickStackLayoutAttached;
+
QList<QQuickItem*> m_items;
typedef struct {
@@ -109,6 +114,36 @@ private:
bool explicitCurrentIndex;
};
+class QQuickStackLayoutAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
+ Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged)
+ Q_PROPERTY(QQuickStackLayout *layout READ layout NOTIFY layoutChanged)
+
+public:
+ QQuickStackLayoutAttached(QObject *object);
+
+ int index() const;
+ void setIndex(int index);
+
+ bool isCurrentItem() const;
+ void setIsCurrentItem(bool isCurrentItem);
+
+ QQuickStackLayout *layout() const;
+ void setLayout(QQuickStackLayout *layout);
+
+signals:
+ void indexChanged();
+ void isCurrentItemChanged();
+ void layoutChanged();
+
+private:
+ int m_index = -1;
+ bool m_isCurrentItem = false;
+ QQuickStackLayout *m_layout = nullptr;
+};
+
QT_END_NAMESPACE
#endif // QQUICKSTACKLAYOUT_H