From 3dab48bcc532f44acc0370d056329a2e5a6b7b6e Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Wed, 29 Apr 2015 09:55:05 +0200 Subject: Import the new TabBar implementation Change-Id: I2c646c07f8310c27f3f03f3cdb27f748c5e6198c Reviewed-by: J-P Nurmi --- src/controls/qquicktabbar.cpp | 182 +++++++++++++++++++++++++++++++++++++++- src/controls/qquicktabbar_p.h | 26 +++++- src/imports/controls/TabBar.qml | 27 +----- 3 files changed, 208 insertions(+), 27 deletions(-) diff --git a/src/controls/qquicktabbar.cpp b/src/controls/qquicktabbar.cpp index 340c2701..74766d1b 100644 --- a/src/controls/qquicktabbar.cpp +++ b/src/controls/qquicktabbar.cpp @@ -36,6 +36,10 @@ #include "qquicktabbar_p.h" #include "qquickcontainer_p_p.h" +#include "qquickexclusivegroup_p.h" + +#include +#include QT_BEGIN_NAMESPACE @@ -52,17 +56,84 @@ QT_BEGIN_NAMESPACE class QQuickTabBarPrivate : public QQuickContainerPrivate { + Q_DECLARE_PUBLIC(QQuickTabBar) + public: - QQuickTabBarPrivate() : currentIndex(0) { } + QQuickTabBarPrivate() : currentIndex(0), model(Q_NULLPTR), group(Q_NULLPTR) { } + + void updateLayout(); + void updateCurrent(); + + // TODO: implement the whole list property + static void contentData_append(QQmlListProperty *prop, QObject *obj); int currentIndex; + QQmlObjectModel *model; + QQuickExclusiveGroup *group; }; +void QQuickTabBarPrivate::updateLayout() +{ + const int count = model->count(); + if (count > 0 && contentItem) { + const qreal spacing = contentItem->property("spacing").toReal(); + const qreal itemWidth = (contentItem->width() - qMax(0, count - 1) * spacing) / count; + + for (int i = 0; i < count; ++i) { + QQuickItem *item = qobject_cast(model->get(i)); + if (item) { + QQuickItemPrivate *p = QQuickItemPrivate::get(item); + if (!p->widthValid) { + item->setWidth(itemWidth); + p->widthValid = false; + } + } + } + } +} + +void QQuickTabBarPrivate::updateCurrent() +{ + Q_Q(QQuickTabBar); + q->setCurrentIndex(model->indexOf(group->current(), Q_NULLPTR)); +} + +void QQuickTabBarPrivate::contentData_append(QQmlListProperty *prop, QObject *obj) +{ + QQuickTabBar *bar = static_cast(prop->object); + QQuickItem *item = qobject_cast(obj); + if (item) + bar->addItem(item); + else + QQuickItemPrivate::data_append(prop, obj); +} + QQuickTabBar::QQuickTabBar(QQuickItem *parent) : QQuickContainer(*(new QQuickTabBarPrivate), parent) { + Q_D(QQuickTabBar); setFlag(ItemIsFocusScope); setActiveFocusOnTab(true); + + d->model = new QQmlObjectModel(this); + connect(d->model, &QQmlObjectModel::countChanged, this, &QQuickTabBar::countChanged); + QObjectPrivate::connect(d->model, &QQmlObjectModel::countChanged, d, &QQuickTabBarPrivate::updateLayout); + + d->group = new QQuickExclusiveGroup(this); + connect(d->group, &QQuickExclusiveGroup::currentChanged, this, &QQuickTabBar::currentItemChanged); + QObjectPrivate::connect(d->group, &QQuickExclusiveGroup::currentChanged, d, &QQuickTabBarPrivate::updateCurrent); +} + +/*! + \qmlproperty int QtQuickControls2::TabBar::count + \readonly + + TODO +*/ +int QQuickTabBar::count() const +{ + Q_D(const QQuickTabBar); + return d->model->count(); } /*! @@ -81,8 +152,115 @@ void QQuickTabBar::setCurrentIndex(int index) Q_D(QQuickTabBar); if (d->currentIndex != index) { d->currentIndex = index; - emit currentIndexChanged(index); + emit currentIndexChanged(); } } +/*! + \qmlproperty Item QtQuickControls2::TabBar::currentItem + + TODO +*/ +QQuickItem *QQuickTabBar::currentItem() const +{ + Q_D(const QQuickTabBar); + return qobject_cast(d->group->current()); +} + +/*! + \qmlproperty model QtQuickControls2::TabBar::model + \readonly + + TODO +*/ +QVariant QQuickTabBar::model() const +{ + Q_D(const QQuickTabBar); + return QVariant::fromValue(d->model); +} + +QQmlListProperty QQuickTabBar::contentData() +{ + Q_D(QQuickTabBar); + // TODO: implement the whole list property + return QQmlListProperty(this, d, + QQuickTabBarPrivate::contentData_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + QQuickItemPrivate::data_clear); +} + +/*! + \qmlmethod Item QtQuickControls2::TabBar::itemAt(int index) + + TODO +*/ +QQuickItem *QQuickTabBar::itemAt(int index) const +{ + Q_D(const QQuickTabBar); + return qobject_cast(d->model->get(index)); +} + +/*! + \qmlmethod void QtQuickControls2::TabBar::addItem(Item item) + + TODO +*/ +void QQuickTabBar::addItem(QQuickItem *item) +{ + Q_D(QQuickTabBar); + insertItem(d->model->count(), item); +} + +/*! + \qmlmethod void QtQuickControls2::TabBar::insertItem(int index, Item item) + + TODO +*/ +void QQuickTabBar::insertItem(int index, QQuickItem *item) +{ + Q_D(QQuickTabBar); + d->model->insert(index, item); + d->group->addCheckable(item); + if (d->currentIndex == index) + d->group->setCurrent(item); +} + +/*! + \qmlmethod void QtQuickControls2::TabBar::moveItem(int from, int to) + + TODO +*/ +void QQuickTabBar::moveItem(int from, int to) +{ + Q_D(QQuickTabBar); + d->model->move(from, to); +} + +/*! + \qmlmethod void QtQuickControls2::TabBar::removeItem(int index) + + TODO +*/ +void QQuickTabBar::removeItem(int index) +{ + Q_D(QQuickTabBar); + d->group->removeCheckable(d->model->get(index)); + d->model->remove(index); +} + +void QQuickTabBar::componentComplete() +{ + Q_D(QQuickTabBar); + QQuickContainer::componentComplete(); + d->updateCurrent(); +} + +void QQuickTabBar::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickTabBar); + QQuickContainer::geometryChanged(newGeometry, oldGeometry); + d->updateLayout(); +} + QT_END_NAMESPACE diff --git a/src/controls/qquicktabbar_p.h b/src/controls/qquicktabbar_p.h index aee165a9..7d43e24e 100644 --- a/src/controls/qquicktabbar_p.h +++ b/src/controls/qquicktabbar_p.h @@ -49,6 +49,7 @@ // #include +#include QT_BEGIN_NAMESPACE @@ -57,23 +58,44 @@ class QQuickTabBarPrivate; class Q_QUICKCONTROLS_EXPORT QQuickTabBar : public QQuickContainer { Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged FINAL) Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL) + Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL) + Q_PROPERTY(QVariant model READ model CONSTANT FINAL) + Q_PROPERTY(QQmlListProperty contentData READ contentData) + Q_CLASSINFO("DefaultProperty", "contentData") public: explicit QQuickTabBar(QQuickItem *parent = Q_NULLPTR); + int count() const; int currentIndex() const; + QQuickItem *currentItem() const; + + QVariant model() const; + QQmlListProperty contentData(); + + Q_INVOKABLE QQuickItem *itemAt(int index) const; + Q_INVOKABLE void addItem(QQuickItem *item); + Q_INVOKABLE void insertItem(int index, QQuickItem *item); + Q_INVOKABLE void moveItem(int from, int to); + Q_INVOKABLE void removeItem(int index); public Q_SLOTS: void setCurrentIndex(int index); Q_SIGNALS: - void currentIndexChanged(int index); + void countChanged(); + void currentIndexChanged(); + void currentItemChanged(); + +protected: + void componentComplete() Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QQuickTabBar) Q_DECLARE_PRIVATE(QQuickTabBar) - friend class QQuickTabView; }; QT_END_NAMESPACE diff --git a/src/imports/controls/TabBar.qml b/src/imports/controls/TabBar.qml index 845cf3d0..93d30f35 100644 --- a/src/imports/controls/TabBar.qml +++ b/src/imports/controls/TabBar.qml @@ -40,14 +40,7 @@ import QtQuick.Controls 2.0 AbstractTabBar { id: control - property list items - readonly property int count: items.length property alias highlight: listView.highlight - property alias spacing: listView.spacing - - property Component delegate: TabButton { - width: (listView.width - Math.max(0, count - 1) * spacing) / count - } contentWidth: listView.contentWidth contentHeight: listView.contentHeight @@ -57,10 +50,6 @@ AbstractTabBar { Accessible.role: Accessible.PageTabList - ExclusiveGroup { - id: group - } - contentItem: ListView { id: listView @@ -69,18 +58,9 @@ AbstractTabBar { boundsBehavior: Flickable.StopAtBounds snapMode: ListView.SnapToItem - model: control.items + model: control.model currentIndex: control.currentIndex - delegate: Loader { - sourceComponent: control.delegate - visible: modelData.Tab.visible - Binding { target: item; property: "Exclusive.group"; value: group } - Binding { target: item; property: "text"; value: modelData.Tab.title } - Binding { target: item; property: "checked"; value: control.currentIndex === index } - Connections { target: item; onClicked: control.currentIndex = index } - } - highlightMoveDuration: 250 highlightResizeDuration: 0 highlightFollowsCurrentItem: true @@ -98,10 +78,11 @@ AbstractTabBar { background: Rectangle { implicitWidth: 26 implicitHeight: 26 - width: listView.width + border.color: control.Theme.backgroundColor border.width: 8 - color: listView.count > 1 ? control.Theme.frameColor : control.Theme.backgroundColor + color: control.count > 1 ? control.Theme.frameColor : control.Theme.backgroundColor + Rectangle { y: parent.height - height width: parent.width -- cgit v1.2.3